1.4.2 docker run
docker run命令的作用是创建一个全新的Docker容器,并在容器内部运行指定命令。Docker Daemon处理用户发起的这条命令时,所做工作可以分为两部分:第一,创建Docker容器对象,并为容器准备所需的rootfs;第二,创建容器的运行环境,如网络环境、资源限制等,最终真正运行用户指令。因此,在dockerrun命令的完整执行流程中,Docker Client给Docker Server发送了两次HTTP请求,第二次请求的发起取决于第一次请求的返回状态。docker run命令执行流程如图1-11所示。
图1-11 docker run命令执行流程示意图
图1-11中有编号的箭头表示dockerrun命令在发起后,Docker架构中相应模块所做的一系列运行。下面我们逐一分析这些步骤:
1)Docker Client处理用户发起的docker run命令,解析完请求与参数之后,向Docker Server发送一个HTTP请求,HTTP请求方法为POST,请求URL为"/containers/create?"+"xxx",实际意义为创建一个容器对象,即Docker Daemon程序逻辑中的容器对象,并非实际运行的容器。
2)Docker Server接收以上HTTP请求,并交给mux.Router,mux.Router通过URL以及请求方法来确定执行该请求的具体handler。
3)mux.Router将请求路由分发至相应的handler,具体为PostContainersCreate。
4)在PostContainersCreate这个handler之中,创建并初始化一个名为"create"的Job,之后触发执行该Job。
5)名为"create"的Job在运行过程中执行Container.Create操作,该操作需要获取容器镜像来为Docker容器准备rootfs,通过graphdriver完成。
6)graphdriver从Graph中获取创建Docker容器rootfs所需要的所有镜像。
7)graphdriver将rootfs的所有镜像通过某种联合文件系统的方式加载至Docker容器指定的文件目录下。
8)若以上操作全部正常执行,没有返回错误或异常,则Docker Client收到Docker Server返回状态之后,发起第二次HTTP请求。请求方法为"POST",请求URL为"/containers/"+container_ID+"/start",实际意义为启动时才创建完毕的容器对象,实现物理容器的真正运行。
9)Docker Server接收以上HTTP请求,并交给mux.Router,mux.Router通过URL以及请求方法来确定执行该请求的具体handler。
10)mux.Router将请求路由分发至相应的handler,具体为PostContainersStart。
11)在PostContainersStart这个handler之中,创建并初始化名为"start"的Job,之后触发执行该Job。
12)名为"start"的Job执行需要完成一系列与Docker容器相关的配置工作,其中之一是为Docker容器网络环境分配网络资源,如IP资源等,通过调用networkdriver完成。
13)networkdriver为指定的Docker容器分配网络资源,其中有IP、port等,另外为容器设置防火墙规则。
14)返回名为"start"的Job,执行完一些辅助性操作后,Job开始执行用户指令,调用execdriver。
15)execdriver被调用,开始初始化Docker容器内部的运行环境,如命名空间、资源控制与隔离,以及用户命令的执行,相应的操作转交至libcontainer来完成。
16)libcontainer被调用,完成Docker容器内部的运行环境初始化,并最终执行用户要求启动的命令。