前面在Docker:架构分解章节Docker架构中各个部分的介绍。下面将以串联Docker各模块来简要分析,分析原型为Docker中的docker pull与docker run两个命令。
docker pull
docker pull命令的作用为:从Docker Registry中下载指定的容器镜像,并存储在本地的Graph中,以备后续创建Docker容器时的使用。docker pull命令执行流程如下图。
如图,图中标记的红色箭头表示docker pull命令在发起后,Docker所做的一系列运行。以下逐一分析这些步骤。
1) Docker Client接受docker pull命令,解析完请求以及收集完请求参数之后,发送一个HTTP请求给Docker Server,HTTP请求方法为POST,请求URL为”/images/create? “+”xxx”;
2) Docker Server接受以上HTTP请求,并交给mux.Router,mux.Router通过URL以及请求方法来确定执行该请求的具体handler;
3) mux.Router将请求路由分发至相应的handler,具体为PostImagesCreate;
4) 在PostImageCreate这个handler之中,一个名为”pull”的job被创建,并开始执行;
5) 名为”pull”的job在执行过程中,执行pullRepository操作,即从Docker Registry中下载相应的一个或者多个image;
6) 名为”pull”的job将下载的image交给graphdriver;
7) graphdriver负责将image进行存储,一方创建graph对象,另一方面在GraphDB中记录image之间的关系。
docker run
docker run命令的作用是在一个全新的Docker容器内部运行一条指令。Docker在执行这条命令的时候,所做工作可以分为两部分:第一,创建Docker容器所需的rootfs;第二,创建容器的网络等运行环境,并真正运行用户指令。因此,在整个执行流程中,Docker Client给Docker Server发送了两次HTTP请求,第二次请求的发起取决于第一次请求的返回状态。Docker run命令执行流程如下图。
如图,图中标记的红色箭头表示docker run命令在发起后,Docker所做的一系列运行。以下逐一分析这些步骤。
1) Docker Client接受docker run命令,解析完请求以及收集完请求参数之后,发送一个HTTP请求给Docker Server,HTTP请求方法为POST,请求URL为”/containers/create? “+”xxx”;
2) Docker Server接受以上HTTP请求,并交给mux.Router,mux.Router通过URL以及请求方法来确定执行该请求的具体handler;
3) mux.Router将请求路由分发至相应的handler,具体为PostContainersCreate;
4) 在PostImageCreate这个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被创建,并开始执行;
12) 名为”start”的job执行完初步的配置工作后,开始配置与创建网络环境,调用networkdriver
13) networkdriver需要为指定的Docker容器创建网络接口设备,并为其分配IP,port,以及设置防火墙规则,相应的操作转交至libcontainer中的netlink包来完成;
14) netlink完成Docker容器的网络环境配置与创建;
15) 返回至名为”start”的job,执行完一些辅助性操作后,job开始执行用户指令,调用execdriver;
16) execdriver被调用,初始化Docker容器内部的运行环境,如命名空间,资源控制与隔离,以及用户命令的执行,相应的操作转交至libcontainer来完成;
17) libcontainer被调用,完成Docker容器内部的运行环境初始化,并最终执行用户要求启动的命令。