Docker源码分析(三):Docker Daemon启动,dockerdaemon
Docker源码分析(三):Docker Daemon启动,dockerdaemon
Docker Daemon是Docker架构中运行在后台的守护进程,大致可以分为Docker Server、Engine和Job三部分。Docker Daemon可以认为是通过Docker Server模块接受Docker Client的请求,并在Engine中处理请求,然后根据请求类型,创建出指定的Job并运行,运行过程的作用有以下几种可能:向Docker Registry获取镜像,通过graphdriver执行容器镜像的本地化操作,通过networkdriver执行容器网络环境的配置,通过execdriver执行容器内部运行的执行工作等。 以下为Docker Daemon的架构示意图: 3 Docker Daemon源码分析内容安排 本文从源码的角度,主要分析Docker Daemon的启动流程。由于Docker Daemon和Docker Client的启动流程有很大的相似之处,故在介绍启动流程之后,本文着重分析启动流程中最为重要的环节:创建daemon过程中mainDaemon()的实现。 4 Docker Daemon的启动流程 由于Docker Daemon和Docker Client的启动都是通过可执行文件docker来完成的,因此两者的启动流程非常相似。Docker可执行文件运行时,运行代码通过不同的命令行flag参数,区分两者,并最终运行两者各自相应的部分。 启动Docker Daemon时,一般可以使用以下命令:docker --daemon=true; docker –d; docker –d=true等。接着由docker的main()函数来解析以上命令的相应flag参数,并最终完成Docker Daemon的启动。 首先,附上Docker Daemon的启动流程图: 由于《Docker源码分析》系列之Docker Client篇中,已经涉及了关于Docker中main()函数运行的很多前续工作(可参见Docker Client篇),并且Docker Daemon的启动也会涉及这些工作,故本文略去相同部分,而主要针对后续仅和Docker Daemon相关的内容进行深入分析,即mainDaemon()的具体源码实现。 5 mainDaemon( )的具体实现 通过Docker Daemon的流程图,可以得出一个这样的结论:有关Docker Daemon的所有的工作,都被包含在mainDaemon()方法的实现中。 宏观来讲,mainDaemon()完成创建一个daemon进程,并使其正常运行。 从功能的角度来说,mainDaemon()实现了两部分内容:第一,创建Docker运行环境;第二,服务于Docker Client,接收并处理相应请求。 从实现细节来讲,mainDaemon()的实现过程主要包含以下步骤:- daemon的配置初始化(这部分在init()函数中实现,即在mainDaemon()运行前就执行,但由于这部分内容和mainDaemon()的运行息息相关,故可认为是mainDaemon()运行的先决条件);
- 命令行flag参数检查;
- 创建engine对象;
- 设置engine的信号捕获及处理方法;
- 加载builtins;
- 使用goroutine加载daemon对象并运行;
- 打印Docker版本及驱动信息;
-
Job之”serveapi”的创建与运行。
- 定义一个为String类型的flag参数;
- 该flag的名称为”p”或者”-pidfile”;
- 该flag的值为” /var/run/docker.pid”,并将该值绑定在变量config.Pidfile上;
-
该flag的描述信息为"Path to use for daemon PID file"。
- 创建并设置一个channel,用于发送信号通知;
- 定义signals数组变量,初始值为os.SIGINT, os.SIGTERM;若环境变量DEBUG为空的话,则添加os.SIGQUIT至signals数组;
- 通过gosignal.Notify(c, signals...)中Notify函数来实现将接收到的signal信号传递给c。需要注意的是只有signals中被罗列出的信号才会被传递给c,其余信号会被直接忽略;
-
创建一个goroutine来处理具体的signal信号,当信号类型为os.Interrupt或者syscall.SIGTERM时,执行传入Trap函数的具体执行方法,形参为cleanup(),实参为eng.Shutdown。
- Docker Daemon不再接收任何新的Job;
- Docker Daemon等待所有存活的Job执行完毕;
- Docker Daemon调用所有shutdown的处理方法;
-
当所有的handler执行完毕,或者15秒之后,Shutdown()函数返回。
- 获取为Docker服务的网络设备的地址;
- 创建指定IP地址的网桥;
- 配置网络iptables规则;
-
另外还为eng对象注册了多个Handler,如 ”allocate_interface”, ”release_interface”, ”allocate_port”,”link”。
- 通过init函数中初始化的daemonCfg与eng对象来创建一个daemon对象d;
- 通过daemon对象的Install函数,向eng对象中注册众多的Handler;
-
在Docker Daemon启动完毕之后,运行名为”acceptconnections”的job,主要工作为向init守护进程发送”READY=1”信号,以便开始正常接受请求。
- 向eng对象中注册众多的Handler对象;
- daemon.Repositories().Install(eng)实现了向eng对象注册多个与image相关的Handler,Install的实现位于./docker/graph/service.go;
-
eng.Hack_SetGlobalVar("httpapi.daemon", daemon)实现向eng对象中map类型的hack对象中添加一条记录,key为”httpapi.daemon”,value为daemon。
评论暂时关闭