docker启动Container进程之启动流程
来源:互联网 发布:怎么出售淘宝店铺页面 编辑:程序博客网 时间:2024/05/21 09:40
docker启动Container进程之启动流程
代码分析起点:daemon/container.go/Start
docker启动containter的起始点在daemon/container.go/Start
方法。
这个方法做了三大方面的事情:
- 配置启动container所需要的环境
- 启动container进程
- 如果container启动失败,做资源回收
1 配置启动container需要的环境
此部分为启动container进程做准备。包括一下几个方面:
1. 构建container的DNS
使用container的setupContainerDns
方法构建container的DNS。 –dns
2. 挂在文件系统
使用Mount
方法配置container的basefs
路径。
3. 初始化网络
使用initialize
方法配置container网络信息,详细分析见docker如果构建bridge网络 。–net
4. 更新parent hosts
使用container的updateParentHosts
方法更新与当前container相关container的etc/hosts
。
5. 验证container资源设置
使用container的verifyDaemonSetting
方法校验container的Me moryLimit
、SwapLimit
和IPv4ForwardingDisable
设置。
6. 卷准备
使用container的prepareVolumes
方法为container启动配置挂载数据卷。 –volume
7. 链接其他container
使用container的setupLinkedContainers
方法配置container需要连接的其他container。 –link
8. 构建工作路径
使用container的setupWorkingDirectory
方法配置container的工作路径。
9. 创建container进程环境
使用container的createDaemonEnvironment
方法配置container内的环境变量。 –env
10. populateCommand
根据步骤9收集到的环境变量,使用populateCommand
构建execdriver命令execdriver.Command
11. 构建mount点
使用container的setupMounts
方法设置container内部的mount配置。
2 启动container进程
在准备好启动container进程的配置后,docker开始创建container进程,使用container的waitForStart
方法完成此项任务。
通过为启动的container创建一个monitor来监控container进程的启动情况,这个地方使用了golang的一个特性:channel。
如果container进程正常启动,那么会在container.monitor.startSigbal
通道受到一个信号;如果在promise.Go(container.monitor.Start)
通道收到错误消息,说明container启动失败并返回错误信息。
也就是说container monitor监控container主进程的执行情况。如果container被指定了一种重启策略,那么monitor保证进程按重启策略重启。当container被stop,monitor会reset并cleanup container占用的资源。
2.1 为container创建monitor
在newContinerMonitor
方法中根据为container内第一个进程配置的重启策略创建一个monitor对象。
func newContainerMonitor(container *Container, policy runconfig.RestartPolicy) *containerMonitor { return &containerMonitor{ container: container, restartPolicy: policy, timeIncrement: defaultTimeIncrement, stopChan: make(chan struct{}), startSignal: make(chan struct{}), }}
containerMonitor结构字段
2.2 启动container进程
docker daemon启动一个goroutine执行container.monitor.Start
,然后监听两个通道,如果捕获了startSignal
,说明container进行正常启动;如果从promise.Go(container.monitor.Start)
通道捕获到了err,说明container进程启动失败。其中contianer.monitor.Start
为启动container进程的入口函数。
// block until we either receive an error from the initial start of the container's // process or until the process is running in the container select { case <-container.monitor.startSignal: case err := <-promise.Go(container.monitor.Start): return err }
下面看看monitor.Start做了什么事情:
首先为container创建标准输入、输出和错误管道。
pipes := execdriver.NewPipes(m.container.stdin, m.container.stdout, m.container.stderr, m.container.Config.OpenStdin)
然后启动container进程
if exitStatus, err = m.container.daemon.Run(m.container, pipes, m.callback); err != nil { // if we receive an internal error from the initial start of a container then lets // return it instead of entering the restart loop if m.container.RestartCount == 0 { m.container.ExitCode = -1 m.resetContainer(false) return err } log.Errorf("Error running container: %s", err) }
daemon/Run –> execdriver/Run –> native/driver.go/Run
在native/driver.go/Run中使用namespace包中的方法Exec创建容器进程。
go func() { exitCode, err := namespaces.Exec(container, c.ProcessConfig.Stdin, c.ProcessConfig.Stdout, c.ProcessConfig.Stderr, c.ProcessConfig.Console, dataPath, args, func(container *libcontainer.Config, console, dataPath, init string, child *os.File, args []string) *exec.Cmd { c.ProcessConfig.Path = d.initPath c.ProcessConfig.Args = append([]string{ DriverName, "-console", console, "-pipe", "3", "-root", filepath.Join(d.root, c.ID), "--", }, args...) // set this to nil so that when we set the clone flags anything else is reset c.ProcessConfig.SysProcAttr = &syscall.SysProcAttr{ Cloneflags: uintptr(namespaces.GetNamespaceFlags(container.Namespaces)), } c.ProcessConfig.ExtraFiles = []*os.File{child} c.ProcessConfig.Env = container.Env c.ProcessConfig.Dir = container.RootFs return &c.ProcessConfig.Cmd }, func() { close(waitForStart) if startCallback != nil { c.ContainerPid = c.ProcessConfig.Process.Pid startCallback(&c.ProcessConfig, c.ContainerPid) } }) execOutputChan <- execOutput{exitCode, err} }()
函数func(container *libcontainer.Config, console, dataPath, init string, child *os.File, args []string)
构建了container进程的属性相关字段,例如 :dockerinit
路径、进程参数、进程namespace flags、进程环境、进程根目录等信息。
3 启动失败后资源的回收
如果container进行启动失败,那么通过
defer func() { if err != nil { container.setError(err) // if no one else has set it, make sure we don't leave it at zero if container.ExitCode == 0 { container.ExitCode = 128 } container.toDisk() container.cleanup() } }()
回收已经为container分配的资源。
- docker启动Container进程之启动流程
- Docker Container开机自动启动
- YARN Container 启动流程分析
- YARN Container 启动流程分析
- Docker Container同时启动多服务
- Docker Container同时启动多服务 centOS6
- WebKit之GPU进程启动流程说明
- nginx启动流程之master进程初始化
- 启动进程流程
- linux进程启动流程
- Zygote进程启动流程
- SystemServer进程启动流程
- Android进程启动流程
- android进程启动流程
- 使用Supervisord实现Docker Container的自启动
- centos 使用 systemctl 使 docker 容器(container)开机启动
- Docker基于Image启动Container并指定端口映射
- Linux内核启动进程流程
- windows平台下配置hadoop的javahome时空格问题解决
- 错误提示“运行时错误: “JSON”未定义”解决方法,增加json2.js文件引用
- myeclipse中tomcat内存大小的设置
- boost::threadpool线程池使用实例
- JSON格式的天气预报接口及城市代码
- docker启动Container进程之启动流程
- DLL动态链接库编程入门之一:DLL概论及其调试和查看
- 【实战】:sqlserver数据实时同步到mysql
- Java中 for循环的用法解析
- android 获取 imei号码
- iMX6 IPU之DP .
- Nodejs使用实例——网站登录验证
- N皇后-回溯-位运算解法
- Android 众多的布局属性详解