docker进程模型分析
前言
当我们启动了一个docker容器后,使用ps命令查看,会发现启动了多个docker相关的进程,如下,
初步看起来:
dockerd是docker engine守护进程,dockerd启动时会启动containerd子进程,二者通过rpc进行通信;
containerd通过shim操作runc,runc真正控制容器生命周期;
每个容器启动时,就会启动一个shim进程;
shim与containerd之前通过rpc通信;
应用对应的启动进程由runc的init进程启动;
proxy用来做端口映射,底层通过iptables实现;
下面逐一分析下这几个进程分别是干嘛的和相互之间的关系。
进程关系
直接上图。
Docker Daemon
作为 Docker 容器管理的守护进程,Docker Daemon 从最初集成在docker
命令中(1.11 版本前),到后来的独立成单独二进制程序(1.11 版本开始),其功能正在逐渐拆分细化,被分配到各个单独的模块中去。从 Docker 服务的启动脚本,也能看见守护进程的逐渐剥离:
在 Docker 1.8 之前,Docker 守护进程启动的命令为:
docker -d
这个阶段,守护进程看上去只是 Docker client 的一个选项。
Docker 1.8 开始,启动命令变成了:
docker daemon
这个阶段,守护进程看上去是docker
命令的一个模块。
Docker 1.11 开始,守护进程启动命令变成了:
dockerd
此时已经和 Docker client 分离,独立成一个二进制程序了。
虽然守护进程模块一直在重构,但其基本功能和定位没有变化。和一般的 CS 架构系统一样,守护进程负责和 Docker client 交互,并管理 Docker 镜像、容器。
Containerd
containerd 是容器技术标准化之后的产物,为了能够兼容 OCI 标准,将容器运行时及其管理功能从 Docker Daemon 剥离。
从其项目介绍页面可以看出,containerd 主要职责是镜像管理(镜像、元信息等)、容器执行(调用最终运行时组件执行)。
containerd 向上为 Docker Daemon 提供了 gRPC 接口,使得 Docker Daemon 屏蔽下面的结构变化,确保原有接口向下兼容。向下通过 containerd-shim 结合 runC,使得引擎可以独立升级,避免之前 Docker Daemon 升级会导致所有容器不可用的问题。
shim
作用如下:
允许runc在创建&运行容器之后退出
用shim作为容器的父进程,而不是直接用containerd作为容器的父进程,是为了防止这种情况:当containerd挂掉的时候,shim还在,因此可以保证容器打开的文件描述符不会被关掉
依靠shim来收集&报告容器的退出状态,这样就不需要containerd来wait子进程
归纳起来,就是将containerd和容器进程解耦。
runc
OCI 定义了容器运行时标准,runC 是 Docker 按照开放容器格式标准(OCF, Open Container Format)制定的一种具体实现。
runC 是从 Docker 的 libcontainer 中迁移而来的,实现了容器启停、资源隔离等功能。Docker 默认提供了 docker-runc 实现,事实上,通过 containerd 的封装,可以在 Docker Daemon 启动的时候指定 runc 的实现。
我们可以通过启动 Docker Daemon 时增加--add-runtime
参数来选择其他的 runC 现。例如:
docker daemon --add-runtime "custom=/usr/local/bin/my-runc-replacement"
总结
从 Docker 1.11 之后,Docker Daemon 被分成了多个模块以适应 OCI 标准。拆分之后,结构分成了以下几个部分。
其中,containerd 独立负责容器运行时和生命周期(如创建、启动、停止、中止、信号处理、删除等),其他一些如镜像构建、卷管理、日志等由 Docker Daemon 的其他模块处理。
- 点赞
- 收藏
- 关注作者
评论(0)