icon-cookie
The website uses cookies to optimize your user experience. Using this website grants us the permission to collect certain information essential to the provision of our services to you, but you may change the cookie settings within your browser any time you wish. Learn more
I agree
blank_error__heading
blank_error__body
Text direction?

认识docker核心组件--->> containerd和runC

0.36字数 1,912阅读 163

containerd是什么

containerd是容器技术标准化之后的产物,为了能够兼容OCI标准,将容器运行时及其管理功能从Docker Daemon剥离。理论上,即使不运行dockerd,也能够直接通过containerd来管理容器。(当然,containerd本身也只是一个守护进程,容器的实际运行时由后面介绍的runC控制。)

containerd主要职责是镜像管理(镜像、元信息等)、容器执行(调用最终运行时组件执行)。

containerd向上为Docker Daemon提供了gRPC接口,使得Docker Daemon屏蔽下面的结构变化,确保原有接口向下兼容。向下通过containerd-shim结合runC,使得引擎可以独立升级,避免之前Docker Daemon升级会导致所有容器不可用的问题。

当Docker daemon启动之后,dockerd和docker-containerd进程一直存在。当启动容器之后,docker-containerd进程会创建docker-containerd-shim进程,其中的参数b9a04a582b66206492d29444b5b7bc6ec9cf1eb83eff580fe43a039ad556e223就是要启动容器的id。最后docker-containerd-shim子进程,已经是实际在容器中运行的进程(既sleep 1000)。

docker-containerd-shim另一个参数,是一个和容器相关的目录/var/run/docker/libcontainerd/b9a04…,里面的内容有:

├── config.json

├── init-stderr

├── init-stdin

└── init-stdout

其中包括了容器配置标准输入、标准输出、标准错误三个管道文件。

containerd架构

containerd的架构如下:

containerd独立负责容器运行时和生命周期(如创建、启动、停止、中止、信号处理、删除等),其他一些如镜像构建、卷管理、日志等由Docker Daemon的其他模块处理。

组件和子系统

组件实现了contianerd的行为。

组件大致组织成子系统,组件可能跨越子系统。

子系统之间的桥接可以认为是模块,模块提供横向切割功能,比如永久存储和事件分发。

distribute子系统

该服务实现拿去镜像功能;

bundle子系统

该服务允许用户从磁盘映像中提取镜像和打包成bundle。

runtime子系统

该服务实现bundles的执行, 包括运行时容器的创建。

Executor组件

实际容器运行时的执行器

Supervisor组件

监视和报告容器状态

Metadata组件

将元数据存储在图形数据库中。用于存储对镜像和bundle的任何持久性引用。输入到数据库的数据将具有在组件之间协调的模式,以提供对任意数据的访问。其他功能包括定义了用于磁盘资源的垃圾回收的钩子。

Content组件

提供对content addressable storage (镜像的层文件)的访问,所有不可变的内容将存储在这里,通过内容的hash索引。

Snapshot组件

管理容器映像的文件系统快照。这类似于Docker中的graphdriver。图层被解包到快照中。

Events组件

支持事件的收集和使用,以提供一致的,事件驱动的行为和审计。

Metrics组件

每个组件将导出几个指标,可通过指标API访问。

数据流

bundle是containerd的核心。下面是一个说明创建bundle的数据流的图。

指示Distribution组件拉取一个指定的镜像;

Distribution组件将镜像的content放入content组件中存储;

将镜像名字和根清单指针向metadata组件存储注册;

bundle组件解压镜像为一个bundle;

根据上面content组件中存储,将镜像的层文件解压到snapshot 组件中;

当一个容器的rootfs的snapshot准备好时,bundle组件使用镜像清单指针和配置来准备执行所有的配置;

将准备好的bundle传递给runtime子系统执行;

runtime子系统读取bundle配置,创建一个运行容器。

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一些命令,实现不使用Docker Daemon直接启动一个镜像,以便了解Docker Daemon每个模块的作用。

首先,需要创建容器标准包,这部分实际上由containerd的bundle模块实现,将Docker镜像转换成容器标准包。

mkdir my_container

cd my_container

mkdir rootfs

docker export $(docker create busybox) | tar -C rootfs -xvf -

上述命令将busybox镜像解压缩到指定的rootfs目录中。如果本地不存在busybox镜像,containerd还会通过distribution模块去远程仓库拉取。

现在整个my_container目录结构如下:

$ tree -d my_container/

my_container/

└── rootfs

├── bin

├── dev

│ ├── pts

│ └── shm

├── etc

├── home

├── proc

├── root

├── sys

├── tmp

├── usr

│ └── sbin

└── var

├── spool

│ └── mail

└── www

17 directories

此时,标准包所需的容器数据已经准备完毕,接下来我们需要创建配置文件:

docker-runc spec

此时会生成一个名为config.json的配置文件,该文件和Docker容器的配置文件类似,主要包含容器挂载信息、平台信息、进程信息等容器启动依赖的所有数据。

最后,可以通过runc命令来启动容器:

runc run busybox

注意,runC必须使用root权限启动。

执行之后,我们可以看见容器已经启动:

localhost my_container # runc run busybox

/ # ps aux

PID USER TIME COMMAND

1 root 0:00 sh

9 root 0:00 ps aux

此时,事实上已经可以不依赖Docker本身,如果系统上安装了runc包,即可运行容器。

当然,也可以使用docker-runc命令来启动容器:

localhost my_container # docker-runc run busybox

/ # ps aux

PID USER TIME COMMAND

1 root 0:00 sh

7 root 0:00 ps aux

从这里可以看到标准化的重要性。

conrainer在docker中所处的位置

新版的Containerd将包含如下特性:

一个分布式的组件,它负责处理到注册中心的推送,无需与特定厂商关联。

一组网络原语,用来创建系统接口和API,以便管理容器的网络命名空间。

主机级别的镜像和容器文件系统存储。

一组GRPC API。

Prometheus格式的度量指标API,用在内部和容器级别的度量指标上。

完全支持OCI镜像和runC的参考实现。

Containerd是Docker开源的众多项目中的新成员,这些项目包括libcontainer、libnetwork、notary、runC、HyperKit、VPNkit、Datakit、swarmkit和Infrakit等。

Measure
Measure
Related Notes
Get a free MyMarkup account to save this article and view it later on any device.
Create account

End User License Agreement

Summary | 4 Annotations
独立负责容器运行时和生命周期
2020/07/27 08:47
子系统
2020/07/27 08:47
镜像管理(镜像、元信息等)、容器执行
2020/07/27 09:59
标准输入、标准输出、标准错误
2020/07/27 09:59