Docker引擎架构

发布时间 2023-11-09 09:43:43作者: 李成敏

# 1. Docker引擎的发展

## 1.1 Docker引擎首次发布时

Docker首次发布时,Docker引擎由两个核心组件组成:LXC和Docker daemon

Docker daemon是单一的二进制文件,包含诸如Docker客户端、Docker API、容器运行时、镜像构建等。

LXC提供对诸如命名空间(Namespace)和控制组(CGroup)等基础工具的操作能力,他是基于Linux内核的容器虚拟化技术。

 

### 1.2 首次发布Docker引擎存在的问题

首先,LXC是基于Linux的。这对于一个立志于跨平台的项目来说是个问题。

其次,如此核心的组件依赖于外部工具,这会给项目带来巨大的风险,甚至影响其发展。

因此,Docker公司开发了名为Libcontainer的自研工具,用于替代LXC。Libcontainer的目标是成为平台无关的工具,可基于不同的内核为Docker上层提供必要的容器交互功能。

### 1.3 现有的Docker引擎

![image-20231108111849610](Docker引擎.assets/image-20231108111849610.png)

 

runc:基于OCI实现,只有一个作用--创建容器

containerd:对Docker daemon进行拆解后,所有容器执行逻辑被重构到一个新的名为containerd(container-dee)的工具中。它的主要任务是容器的生命周期管理---start | stop | pause | rm ...

docker daemon:主要功能包括镜像管理、镜像构建、REST API、身份验证、安全、核心网络以及编排,<font color=red>不再包含任何创建容器的代码。</font>

shim:runc创建容器完毕,对应的runc进程就会退出,相关联的containerd-shim进程就会成为容器的父进程。<font color=red>shim是实现无daemon的容器不可或缺的工具。</font>

### 1.4 容器启动过程

![image-20231108114444784](Docker引擎.assets/image-20231108114444784.png)

 

Docker client向Docker daemon发送创建容器的命令,Docker daemon一旦接收到创建新容器的命令,它就会向containerd发出调用,虽然名叫containerd,但是它并不负责创建容器,二十指挥runc去做。containerd将Docker镜像转换为OCI bundle,并让runc基于此创建一个新的容器。

runc与操作系统内核接口进行通信,基于所有必要工具(Namespace、CGroup等)来创建容器。容器进程作为runc的子进程,启动完毕后,runc将会退出。相关联的containerd-shim进程成为容器的父进程。

 

该模型的优势:

将所有用于启动、管理容器的逻辑核代码从daemon中移除,意味着容器运行时与Docker daemon是解耦的,有时称之为“无守护进程的容器(daemonless container)”,如此,对Docker daemon的维护和升级工作不会影响到运行中的容器。

### 1.5 关于OCI

OCI(open container Initiative)开放容器倡议,定义了两个规范:

- 镜像规范
- 容器运行时规范

 

## 2. 关于k8s 1.24版本弃用dockershim的问题

![img](Docker引擎.assets/v2-7040b4753114ee31d56dd273b9147632_720w.webp)

 

k8s的CRI(Container Runtime Interface)与docker引擎的API并不兼容,为了支持Docker,在kubelet和Docker之间增加了一个适配器(dockershim)。

在k8s 1.24版本完全弃用了dockershim,kubelet直接与containerd通信,管理容器的生命周期,去掉了 dockershim 和 Docker Engine 这两个环节,更加简洁明了,性能更好。

弃用dockershim对K8s和Docker的影响不大,因为docker引擎也是通过containerd进行容器生命周期管理,原有的Docker镜像和容器仍然可以正常运行。唯一的变化是K8s绕过了docker,直接调用containerd。

K8s直接使用containerd来操作容器,那么它就是一个独立于Docker的工作环境,两者都无法访问对方管理的容器和镜像。换句话说,使用`docker ps`命令将不会看到K8s中运行的容器。

由于容器镜像格式已经标准化(OCI规范,Open Container Initiative),Docker镜像在K8s中仍然可以正常使用,不需要改变原有的开发测试和CI/CD流程。我们仍然可以拉取 Docker Hub,或者编写一个 Dockerfile 来打包应用程序。

 

## 3. 参考

《深入浅出Docker》第五章

https://zhuanlan.zhihu.com/p/572907451