【docker】docker的容器创建与管理过程
发布网友
发布时间:2022-09-15 09:23
我来回答
共1个回答
热心网友
时间:2023-10-08 22:40
# yum -y install docker docker-ce-cli containerd.io
# rpm -qa | grep container
# rpm -qa | grep docker
# rpm -ql docker-ce-cli | grep bin
# rpm -ql docker-ce | grep bin
# rpm -ql containerd.io | grep bin
# systemctl status docker
# systemctl status containerd
/var/run/docker.sock
/run/containerd/containerd.sock
/usr/bin/docker 和 /usr/bin/dockerd 就是命令行客户端和daemon
dcocker的架构是 C/S 模式
docker-containerd
docker-containerd-ctr
docker-containerd-shim
docker-init
docker-proxy
docker-runc
其实最简单的方式,就是加个命令行参数 --help 看看他们的简介。
可以看出来,docker-init, docker-containerd-shim 和 docker-proxy 没有在帮助里告诉我们是干什么的,其他的都有:
docker-containerd: 高性能容器运行时
docker-containerd-ctr: docker-containerd 的命令行客户端
docker-runc: 运行容器的命令行工具
如果去搜索一番,就会发现:docker-containerd 就是 containerd ,而 docker-runc 就是 runc 。
containerd是真正管控容器的daemon,执行容器的时候用的是runc。
为什么 要分的七零八散呢?
我估计其中主要的原因是防止docker垄断,因此把容器标准独立出来,就有了 runtime-spec ,然后有了 runc ,然后有了 containerd (此处发展历史没有考究,并不关心)。
可以看出来,docker本身其实已经被剥离干净了,只剩下docker自身的一些特色功能了,真正容器的管控都在containerd里实现。
所以接下来介绍的顺序是 runc, containerd, shim, docker-init, docker-proxy。
runc是标准化的产物,为了防止一家商业公司主导容器化标准,因此又了open containers组织,因此,创建容器,其实最终通过runc就可以了。
dockerd 有个子进程,是 containerd,然后 containerd 有子进程。
从 官方仓库 的描述可以看出来,其实 containerd 就包含了我们常用的 docker 的命令:
增删查改容器
增删查改镜像
也就是说,如果我们要对容器进行操控,直接使用 containerd 其实就够了。
说明: 如果没有单独起一个containerd,而是使用了 docker-containerd,通过 ps aux | grep docker 发现它使用了 /var/run/docker/containerd/containerd.toml 这个配置文件,而监听路径就写在里面。
shim的翻译是垫片,就是修自行车的时候,用来夹在螺丝和螺母之间的小铁片。
关于shim本身,网上介绍的文章很少,但是作者在 Google Groups 里有解释到shim的作用:
https://groups.google.com/forum/#!topic/docker-dev/zaZFlvIx1_k
1. 允许runc在创建&运行容器之后退出
2. 用shim作为容器的父进程,而不是直接用containerd作为容器的父进程,是为了防止这种情况:当containerd挂掉的时候,shim还在,因此可以保证容器打开的文件描述符不会被关掉
3. 依靠shim来收集&报告容器的退出状态,这样就不需要containerd来wait子进程
因此,使用shim的主要作用,就是 将containerd和真实的容器(里的进程)解耦 ,这是第二点和第三点所描述的。
而第一点,为什么要允许runc退出呢?
因为,Go编译出来的二进制文件,默认是静态链接,因此,如果一个机器上起N个容器,那么就会占用M*N的内存,其中M是一个runc所消耗的内存。 但是出于上面描述的原因又不想直接让containerd来做容器的父进程,因此,就需要一个比runc占内存更小的东西来作父进程,也就是shim。但实际上, shim仍然比较占内存( 参考这里 )。
我们都知道UNIX系统中,1号进程是init进程,也是所有孤儿进程的父进程。
而使用docker时,如果不加 --init 参数,容器中的1号进程 就是所给的ENTRYPOINT。
而加上 --init 之后,1号进程就会是 tini 。
在entrypoint.sh中使用Tini的优势是什么?
https://zhuanlan.hu.com/p/59796137
用来做容器和宿主机之间的端口映射,其底层是使用iptables来完成的。
The docker-proxy
https://windsock.io/the-docker-proxy
docker本身而言包括了,docker client和dockerd(docker daemon),dockerd本身实属是对容器相关操作的api的最上层封装,
直接面向操作用户。
dockerd
dockerd本身实属是对容器相关操作的api的最上层封装,直接面向操作用户。
containerd
dockerd实际真实调用的还是 containerd的api接口(rpc方式实现 ),containerd是dockerd和runc之间的一个中间交流组件。
containerd-shim
containerd-shim是一个运行的容器的真实垫片载体,每启动一个容器都会起一个新的docker-shim进程。
他直接通过指定的三个参数:容器id,boundle目录(containerd的对应某个容器生成的目录,一般位于:/var/run/docker/libcontainerd/containerID),运行二进制(默认为runc)来调用runc的api创建一个容器(比如创建容器:最后拼装的命令如下:runc create )
runc
runc是一个命令行工具端,根据oci(开放容器组织)的标准来创建和运行容器。
1. docker 与 dockerd 通过/var/run/docker.sock 通讯
2. dockerd通过 grpc 与containerd模块通信,dockerd由libcontainerd负责和containerd进行交换,dockerd与containerd通信socket文件为 /run/containerd/containerd.sock
3. containerd在dockerd启动时 被启动 ,然后containerd启动grpc请求监听,containerd处理grpc请求,根据请求做相应动作
4. 若是start或是exec容器,containerd拉起一个 container-shim ,并进行相应的操作
5. container-shim拉起后,start/exec/create拉起runC进程,通过exit、control文件和 containerd 通信,通过父子进程关系和SIGCHLD监控容器中进程状态
6. 在整个容器生命周期中,containerd通过epoll监控容器文件,监控容器事件
Docker组件介绍(一):runc和containerd
https://jiajunhuang.com/articles/2018_12_24-docker_components_part2.md.html
Docker组件介绍(二):shim, docker-init和docker-proxy
https://jiajunhuang.com/articles/2018_12_24-docker_components_part2.md.html
关于docker启动一个容器后进程
https://www.jianshu.com/p/caad2176186f