从零自制docker-15-【实现 mydocker run -d 支持后台运行容器】

实现目的

docker run -d时容器在后台运行,而不会进入命令行交互形式

  1. 首先是需要添加-d选项
  2. 然后设置当添加-d选项时候主进程不会等待子进程,而是直接结束
func Contain_run(cmd string,it bool,resource_config *cgroups.Resource,volume string) {
	command,writepipe,rooturl:=new_contain_process(it,volume)
	log.Infof("cmd %s it %t",cmd,it)
	
	if err:=command.Start();err!=nil{
		log.Error(err)
	}
	log.Infof("cmd %s",cmd)
	cmdstring:=strings.Split(cmd, " ")
	log.Infof("split cmd %v",cmdstring)

	llkdockercgroups:=cgroups.Cgroups{
		Cgroups_Name: "llkdockercgroups",
		Resour:resource_config,
		Sub:cgroups.Subsystemins,
	}
	log.Info(llkdockercgroups.Resour)

	cgroups_path:=cgroups.Get_cgroups_path("cgroup",llkdockercgroups.Cgroups_Name)
	log.Info("in run.go get cgroups_path")
	llkdockercgroups.Move(command.Process.Pid,cgroups_path)

	llkdockercgroups.Set(cgroups_path)
	//defer llkdockercgroups.Remove(cgroups_path) //-d后台运行的话不能删除cgroup

	write_to_pipe(cmdstring,writepipe)
	if it{ //-it实现交互,那么当前终端就不能关闭退出,还需留给子进程使用
		command.Wait()
		// 从容器内的命令行中的退出才会wait结束
		end_volume(rooturl,volume)
		end_overlays(rooturl)
	}
	
	log.Infof("exit  !!!")

}
  1. 最后注意主进程不能删除该进程建立的cgroup,否则会出现下述问题,这个是删除cgroup出现的问题,原因是这个cgroup还包含一些正在运行的进程,那些进程没有结束就删除cgroup会删除失败
    在这里插入图片描述

解决方法:就是在-it的模式下最后删除,但后台运行的不会

if it{ //-it实现交互,那么当前终端就不能关闭退出,还需留给子进程使用
		command.Wait()
		// 从容器内的命令行中的退出才会wait结束
		end_volume(rooturl,volume)
		end_overlays(rooturl)
		llkdockercgroups.Remove(cgroups_path) //-d后台运行的话不能删除cgroup
	}

这个是后台运行docker的
在这里插入图片描述
而最后通过-it运行的结果如下
在这里插入图片描述

莫名奇妙的问题

发现调试的时候,使用log.Infof等其他类似的,最后终端上没有显示全,但通ps -ef|grep -e PPID -e top查看发现其又确实在在运行

例如下面这个9550进程是后台运行的top进程
在这里插入图片描述
但在终端上显示时有时不全,有时也会显示全
在这里插入图片描述
这里我是开了子进程的和当前终端的标准输入输出和错误都一样的,不然看不到相关调试信息

func new_contain_process(it bool,volume string)  (*exec.Cmd,*os.File,string){	
	
	readpipe,writepipe,err:=os.Pipe()
	if err!=nil{
		log.Fatal(err)
	}
	command:=exec.Command("/proc/self/exe","init")
	command.SysProcAttr=&syscall.SysProcAttr{
		Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS |
			syscall.CLONE_NEWNET | syscall.CLONE_NEWIPC,
	}
	 //主进程和子进程共用一个终端
		command.Stdin=os.Stdin
		command.Stdout=os.Stdout
		command.Stderr=os.Stderr
	
	log.Info(command)
	log.Infof("sucess create a contain process")
	command.ExtraFiles=[]*os.File{readpipe}
	mntURL := "./merged"
	rootURL := "./"
	command.Dir = mntURL
	prepare_overlays(rootURL) 
	prepare_volume(rootURL,volume)

	log.Info(readpipe)
	return command,writepipe,rootURL
	
}

对之前upper层出现root补充

之前一直是对上一个写的docker复制然后在复制的上面写新的,发现busybox和刚从busybox解压得到缺少了很多东西,然后又重新解压生成了busybox将其使用。然后之前在后面发现upper中出现root是调用相关命令就会出现root,但当时没有啥修改的文件,这次全的busybox发现出现了下面的这个,那么确实就是因为调用命令引起的日志记录的变化导致的
在这里插入图片描述

对run某些命令出现找不到文件或目录的原因

当时是容器在挂载前就找相关命令,找到的这个是宿主机上的,但我们要的是在pivoroot后的根目录下的相关命令的路径,所以后面运行这个宿主机上的路径会显示路径找不到,因为此时是以容器的根目录为相对参考


func Contain_init(){
	
	
	cmd:=readpipe()
	log.Infof("init %s",cmd)
	
	log.Infof("cmd[0] %s",cmd[0]=="/bin/sh")
	log.Infof("cmd len %d",len(cmd))
	log.Infof("cmd %s",cmd[0])
	/*
	path,err:=exec.LookPath(cmd[0])//挂载前得到相关命令的路径会出现找不到
	if err!=nil{
		log.Fatal(err)
	}
	argv:=[]string{}
    for i:=1;i<len(cmd);i++{
		argv=append(argv,cmd[i-1])
	}*/

	log.Infof("prepare for mount ")

	mount()
	path,err:=exec.LookPath(cmd[0]) //挂载后再得到相关命令的路径等
	if err!=nil{
		log.Fatal(err)
	}
	argv:=[]string{}
    for i:=1;i<len(cmd);i++{
		argv=append(argv,cmd[i-1])
	}


	log.Infof("prepare for exec cmd ")
	log.Info(path)
	log.Info(argv)
	log.Info(os.Environ())

	if err:=syscall.Exec(path,argv,os.Environ());err!=nil{
		log.Infof("exec error")
		log.Info(err)
	}
	
}

代码

https://github.com/FULLK/llkdocker/tree/main/run_d_docker

效果

最终我启动了sudo ./run_docker run -d top多次,在cgroup.procs中可以看到(一部分是之前sudo ./run_docker run -it /bin/sh加入的,因为我最后关闭了主进程最后自动删除cgroup的函数),最终可以看到top进程在后台运行
`
在这里插入图片描述

  • 9
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

看星猩的柴狗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值