Docker架构

在安装好并启动了Docker之后,我们可以使用在命令行中使用docker命令操作docker。

比如我们使用如下命令打印docker的版本信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
[root@localhost ~]# docker version
Client: Docker Engine - Community
Version: 25.0.0
API version: 1.44
Go version: go1.21.6
Git commit: e758fe5
Built: Thu Jan 18 17:13:17 2024
OS/Arch: linux/amd64
Context: default

Server: Docker Engine - Community
Engine:
Version: 25.0.0
API version: 1.44 (minimum version 1.24)
Go version: go1.21.6
Git commit: 615dfdf
Built: Thu Jan 18 17:12:10 2024
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.6.27
GitCommit: a1496014c916f9e62104b33d1bb5bd03b0858e59
runc:
Version: 1.1.11
GitCommit: v1.1.11-0-g4bccb38
docker-init:
Version: 0.19.0
GitCommit: de40ad0

从以上信息,我们看到打出了两个部分的信息:Client和Server。

Docker采用 C/S架构 Docker daemon 作为服务端接受来自客户的请求,并处理这些请求(创建、运行、分发容器)。 客户端和服务端既可以运行在一个机器上。

Docker架构
Docker架构

当使用 Docker 命令行工具执行命令时,Docker 客户端会将其转换为合适的 API 格式,并发送到正确的 API 端点。

一旦 daemon 接收到创建新容器的命令,它就会向 containerd 发出调用。daemon 使用一种 CRUD 风格的 API,通过 gRPC 与 containerd 进行通信。

虽然名叫 containerd,但是它并不负责创建容器,而是指挥 runc 去做。containerd 将 Docker 镜像转换为 OCI bundle,并让 runc 基于此创建一个新的容器。

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

一旦容器进程的父进程 runc 退出,相关联的 containerd-shim 进程就会成为容器的父进程。当 daemon 重启的时候,容器不会终止,并且可以将容器的退出状态反馈给 daemon。