docker-3.3 组件

190 阅读4分钟

docker主要组件

  • docker cli(dockerd)
  • docker daemon(dockerd)
  • containerd
  • containerd-shim
  • RunC

docker创建并且运行一个容器的过程

  1. 容器镜像的下载是由dockerd完成的,但容器的创建和运行就需要containerd(docker-containerd) 来完成了。Dockerd与docker-containerd之间是通过grpc协议通信的。

  2. 当docker-containerd收到dockerd 启动容器的请求之后,会做一些初始化工作,然后启动docker-containerd-shim进程,并将相关配置作为参数传给它。

    docker-containerd负责管理所有本机正在运行的容器,而一个docker-containerd-shim进程只负责管理一个运行的容器

  3. docker-containerd-shim相当于docker-runc的一个封装,充当docker-containerd和docker-runc之间的桥梁,docker-runc能干的就交给docker-runc来做,docker-runc做不了的就放到这里来做

docker主要进程以及之间的父子关系

docker run -d busybox sleep 100000
systemd
        ├─dockerd─┬─containerd─┬─containerd-shim─┬─sleep
        │         │            │                 └─10*[{containerd-shim}]

docker-runc进程

  • 容器启动的过程中,docker-runc作为dockerd-contained-shim的子进程存在,docker-runc进程根据容器的配置找到容器的rootfs为容器创建bash进程后,就退出了,创建的第一个bash进程有父进程dockerd-contained-shim接管
  • runc是标准化的产物,为了防止一家商业公司主导容器化标准,因此又了opencontainers组织,因此,创建容器,其实最终通过runc就可以了。
  1. 如果要自己编译,就要先克隆代码,然后执行 sudo make install。
git clone http://github.com/opencontainers/runc
make install
  1. 用runc创建一个容器
mkdir -p mycontainer/rootfs
cd mycontainer/
docker export $(docker create busybox) | tar -C rootfs -xf -
runc spec
runc run mycontainer

github.com/opencontain…

containerd

架构

  1. Containerd对上提供grpc接口方式的api,而Metric api是度量功能使用的。所有的编排工具容器适配层都可以使用grpc api作为containerd的客户端,使用containerd操作容器。
  2. Distribution用于容器镜像的pull和push动作(这部分出现在Containerd中完全是因为OCI v1标准推出Docker公司将自己镜像格式贡献了出去,所以containerd理所当然需要对镜像进行管理了)。
  3. Bundle(在docker的语景里是容器运行的目录集)子系统用于容器存储管理它的作用就是原来的graphdriver,它提供将容器镜像拆解成容器运行时刻需要的Bundle。
  4. Runtime子系统用于容器执行和监控,就是它直接操作runtime,传递和接收信号(signal),中转fifo,记录日志。
  5. Content、Metadata和Snapshots是存储管理组组件
  6. Excutor和Supervisor是执行体组件。 整个系统通过Event事件驱动。

源码

github.com/containerd/…

containerd源码阅读

docker-containerd-shim

  • 允许runc在创建&运行容器之后退出

  • 用shim作为容器的父进程,而不是直接用containerd作为容器的父进程,是为了防止这种情况:当containerd挂掉的时候,shim还在,因此可以保证容器打开的文件描述符不会被关掉

  • 依靠shim来收集&报告容器的退出状态,这样就不需要containerd来wait子进程

    前两点尤其重要,有了它们就可以在不中断容器运行的情况下升级或重启 dockerd(这对于生产环境来说意义重大)

    第一点,为什么要允许runc退出呢? 因为,Go编译出来的二进制文件,默认是静态链接,因此,如果一个机器上起N个容器,那么就会占用M*N的内存,其中M是一个runc所消耗的内存。 但是出于上面描述的原因又不想直接让containerd来做容器的父进程,因此,就需要一个比runc占内存更小的东西来作父进程,也就是shim。

docker-proxy

容器网络代理

#docker ps
e7ea6abc29cf        goharbor/harbor-log:v1.8.3                          "/bin/sh -c /usr/loc…"   3 months ago        Up 3 months (healthy)   127.0.0.1:1514->10514/tcp   harbor-log

#pstree -l -a -A
  ├─dockerd -H fd:// --containerd=/run/containerd/containerd.sock
  │   ├─docker-proxy -proto tcp -host-ip 127.0.0.1 -host-port 1514 -container-ip 172.19.0.2 -container-port 10514
  
#iptables-save |grep 1514    
-A DOCKER -d 127.0.0.1/32 ! -i br-a4c38bc30ca1 -p tcp -m tcp --dport 1514 -j DNAT --to-destination 172.19.0.2:10514