引言
🚀 随着云原生时代的到来,容器化技术已成为企业级应用部署与解耦的重要利器。在众多容器技术栈中,Containerd 作为一个轻量、稳定且高性能的容器运行时,正被 Kubernetes、云平台以及各大互联网公司所青睐。
📦 本文将从容器运行时的演进与需求出发,深度剖析 Containerd 的核心架构与关键模块,分享在企业级场景下的实战部署经验,并结合实际性能对比与调优思路,帮助中高级技术人员快速掌握 Containerd 在生产环境中的落地要点。
目标读者:
- Kubernetes 用户、容器平台搭建者
- 企业 DevOps 工程师、架构师、云平台研发人员
- 关注云原生与容器运行时机制的中高级技术研究员
- 已具备一定工程实践背景的技术使用者(非小白)
背景与发展
Containerd 的前世今生
“在 Docker Engine 中,Containerd 曾经是 Docker 1.11 及之前版本的容器核心;如今,它已经独立成为 CNCF(Cloud Native Computing Foundation)下的顶级开源项目,为上层编排系统提供了更专注、更稳定的容器运行时基础设施。”
-
起源与演进
- 2013 年:Docker 公司推出 Docker 引擎,其中包含了名为
libcontainer
的容器管理核心。 - 2015 年:
libcontainer
捐献给 Open Container Initiative (OCI),并更名为 runc,作为标准化的 OCI 运行时。 - 2016 年 3 月:Docker 1.11 发布,将 containerd 从 Docker Engine 中剥离,并将其作为独立守护进程(daemon),提供 gRPC 接口供上层系统调用。
- 2017 年:Docker 官方将 Containerd 正式捐赠给 CNCF,成为独立的顶级项目,专注于容器生命周期管理、镜像拉取与存储、网络与存储插件等功能。
- 2020 年:Kubernetes 1.20 宣布逐步移除对 Docker Shim 的支持,而推荐使用 containerd/runc 组合作为容器运行时。
- 2013 年:Docker 公司推出 Docker 引擎,其中包含了名为
-
社区与生态
- CNCF 顶级项目:与 Kubernetes、Prometheus、Envoy 并列,拥有庞大的社区支持与活跃的版本迭代。
- 厂商支持:Google、RedHat、IBM、阿里、华为等多家企业参与开发与贡献,保证了 Containerd 在云原生领域的主流地位。
- 生态兼容:支持所有符合 OCI 标准的镜像与运行时,上层系统(如 Kubernetes、Mesos、Swarm 等)通过 CRI(Container Runtime Interface)或 gRPC 接口与 containerd 对接。
与 Docker、Kubernetes 的关系
-
Docker vs Containerd
- Docker Engine 是一个完整的 PaaS 平台,集成了镜像构建、仓库管理、镜像分发、容器编排(Swarm)等功能,而 Containerd 仅聚焦于“容器运行时管理”。
- 将 Containerd 从 Docker Engine 中独立出来,既保证了 Docker 引擎的上层用户体验,也让 Containerd 有了更专注的发展空间。
-
Kubernetes vs Containerd
- 早期 Kubernetes 通过 “Docker Shim” 将 CRI 请求翻译为 Docker 的 API,进而借助 Docker Daemon 来管理容器。随着社区标准化需求日益增长,Docker Shim 的维护成本加大。
- Containerd 原生支持 CRI,通过
cri-containerd
插件直接与 Kubelet 通信,实现镜像拉取、容器创建、日志收集等功能。2020 年后,Kubernetes 官方推荐将 Containerd 与 runc 作为主要运行时。
🎯 小结:Containerd 从 Docker Engine 中脱胎而出,继承了 Docker 对容器生命周期管理的设计思想,同时将重心放在“轻量化、稳定性、高性能”上,为云原生生态提供了理想的底层运行引擎。
架构设计
整体架构概览
Containerd 采用 C/S 架构,上层系统(如 Kubernetes、Docker Engine)通过 gRPC 接口调用 containerd 以实现对容器的管理。
- Server(守护进程):以
containerd
进程形式运行,负责接收上层请求、管理镜像、存储、网络、容器生命周期等。 - Client(CLI / SDK):通过
ctr
、crictl
、Docker Engine 等客户端进行交互,调用 gRPC 接口执行操作。
- 🍃 Containerd 将不同职责划分为多个模块(插件),各插件之间通过核心框架协调运作。
- 🌟 插件以 “插件名称 + 版本号” 的形式注册到 Containerd 中,启动时自动加载并初始化。
插件化设计与模块划分
Containerd 主要分为以下三大子系统(层):
-
Storage(存储层)
- Content Plugin:管理镜像层二进制内容(如 tarball、OCI Layer)。
- Snapshot Plugin:对镜像层进行解压、挂载、卸载操作,将镜像与容器文件系统进行绑定。
-
Metadata(元数据层)
- Metadata Plugin:基于 BoltDB 存储容器、镜像、快照、租约(Lease)、命名空间(Namespace)等元数据信息。
- Garbage Collection (GC) Plugin:定期清理无用的快照、内容、租约,维护存储空间。
-
Runtime(运行时层)
- Runtime Plugin(v1/v2):负责调用
runc
或其他符合 OCI 规范的 runtime(如kata-runtime
、gvisor
)创建、启动、停止容器进程。 - Service Plugin(tasks-service、containers-service、events-service 等):暴露 gRPC 服务供上层调用,实现容器创建、启动、监控等功能。
- CRI Plugin:实现 Kubernetes CRI(Container Runtime Interface)规范,桥接 Kubelet 与 Containerd。
- Metrics Plugin:暴露 Prometheus 格式的监控指标,用于上层集群监控系统。
- Runtime Plugin(v1/v2):负责调用
关键插件与组件
插件名称 | 作用 |
---|---|
Content Plugin | 存储与管理镜像层的二进制内容,如 OCI Layer,支持拉取、导入、导出。 |
Snapshot Plugin | 对镜像层进行解压、挂载、复制快照。支持多种存储后端(overlayfs、btrfs、zfs)。 |
Metadata Plugin | 使用 BoltDB 存储容器、镜像、快照等元数据信息。 |
Garbage Collection (GC) Plugin | 定期清理不再使用的镜像层、快照、租约,释放磁盘空间。 |
Runtime Plugin (v1/v2) | 负责调用 runc(或其他 OCI Runtime)创建、启动、停止容器。 |
CRI Plugin | 实现 Kubernetes CRI 接口,将 Kubelet 请求翻译为 Containerd 操作。 |
Tasks-Service、Containers-Service、Events-Service | 提供容器与任务的管理、查询、事件上报等服务。 |
Metrics Plugin | 暴露 Prometheus 风格的监控指标,如镜像拉取速率、容器启动耗时等。 |
Diff-Service | 处理增量文件系统差异(walking)。 |
关键模块深度解析
Content Plugin:镜像内容管理
-
功能定位
- 管理镜像中所有不可变的二进制内容,如镜像层(layer)、配置(config)、清单(manifest)等。
- 支持多种操作:
Pull
(拉取)、Push
(推送)、Import
(导入)、Export
(导出)等。
-
核心概念:Content Store
- Containerd 维护一个 Content Store,负责存储镜像各个层的数据。每份内容通过 Digest(sha256) 进行唯一标识,保证内容可寻址与一致性。
- 物理存储路径默认在
/var/lib/containerd/io.containerd.content.v1.content
下,以子目录分片存放。
-
工作流程
ctr images pull
:首先获取镜像清单(manifest),遍历所需的 layer Digest,依次下载到本地 Content Store;下载完毕后校验完整性,将 Digest 及尺寸信息写入元数据(Metadata Store)。ctr images push
:根据本地 Content Store 中已有的层,打包上传到远端 Registry。- 导入/导出:利用
ctr images import/export
命令,将镜像保存为 tar 归档文件,支持跨集群迁移。
-
示例:拉取镜像
# 拉取 nginx:alpine(支持多平台) sudo ctr images pull --all-platforms docker.io/library/nginx:alpine # 指定平台拉取(仅 linux/amd64) sudo ctr images pull --platform linux/amd64 docker.io/library/nginx:alpine # 查看 Content Store 路径 ls /var/lib/containerd/io.containerd.content.v1.content/blobs/sha256
-
内容校验与租约(Lease)
- Containerd 引入 租约(Lease) 概念,用于在特定时间段内保护内容不被 GC 删除,例如在备份或导出过程中。
- 通过
ctr lease
命令管理租约,保证内容在使用期间不会被回收。
Snapshot Plugin:文件系统快照与存储
-
Snapshotter 概述
-
Snapshotter 负责将镜像层(layer)解压到本地文件系统,并在容器启动时将各层合并为一个联合文件系统,实现对容器 RootFS 的管理。
-
支持多种后端 Snapshotter:
- overlayfs(默认,最常见,适用于大多数 Linux 发行版)
- btrfs(支持写时复制,需要底层文件系统支持 btrfs)
- zfs(写时复制,需要底层文件系统支持 zfs)
- devmapper、thind、aufs 等(根据平台与场景选择)
-
-
Union Mount(联合挂载)
- 采用 联合挂载 技术,将多个只读层(immutable layer)和一个读写层(rw layer)合并到一起,为容器提供一个完整的根文件系统。
- 读写分离:上层读写层位于
/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs
(以 overlayfs 为例),只记录容器运行时的变更。
-
Snapshot 生命期管理
- Image Snapshot:当拉取镜像后,会将各个 layer 解压为只读快照(readonly snapshot),这些快照共享于多个容器。
- Container Snapshot:在基于镜像创建容器时,会为该容器创建一个新的读写快照(rw snapshot),并将只读层以联合挂载形式置于上层。
- 删除与 GC:容器停止并删除后,对应的读写层快照被删除,关联的只有当没有任何容器依赖时,只读层才会被 GC 清理。
-
示例:overlayfs Snapshot 操作
# 列出所有 snapshot sudo ctr snapshots ls # 输出类似: # NAME KIND PARENT # sha256:aeae... active sha256:bbbb... # sha256:bbbe... view sha256:cccc... # ... # 手动创建一个镜像快照(view) sudo ctr snapshots view sha256:aeae... /mnt/nginx-layer # 删除快照 sudo ctr snapshots rm sha256:aeae...
-
存储优化与调优
- 选择合适的 Snapshotter:大多数场景推荐使用
overlayfs
,兼容性强、性能佳;对写时复制要求高、希望隔离的场景可考虑btrfs
或zfs
。 - 底层文件系统参数调优:如
overlayfs
中可以通过mount
选项设置metacopy=on
、xor
等参数以提升性能。 - 多级缓存:对于高并发场景,可结合分布式存储或缓存代理减少单机 I/O 压力。
- 选择合适的 Snapshotter:大多数场景推荐使用
Metadata Plugin:元数据存储与检索
-
Metadata Store 概述
-
使用 BoltDB(嵌入式 KV 数据库)存储所有元数据信息,包括:
- 镜像清单(Manifest)与层(Layer)信息
- 容器对象(Container)与任务(Task)信息
- Snapshot(快照)与 Lease(租约)
- Namespace(命名空间)概念
-
-
Namespace 用法
-
Containerd 支持多命名空间(Namespace)隔离,不同 Namespace 之间的镜像、容器、快照等资源相互独立。
-
通过
--namespace
参数或环境变量$CONTAINERD_NAMESPACE
指定操作数据所归属的命名空间。 -
示例:
# 切换命名空间为 dev export CONTAINERD_NAMESPACE=dev # 拉取镜像到 dev 命名空间 sudo ctr images pull docker.io/library/nginx:latest # 在 default 命名空间下看不到该镜像 sudo ctr -n default images ls
-
-
Metadata Schema 演进
- Containerd v1.x 使用 BoltDB v1 版本,存储在
/var/lib/containerd/io.containerd.metadata.v1.bolt/meta.db
。 - v1.5+ 开始支持分离 Metadata 存储路径,配置文件中可通过
plugins."io.containerd.metadata.v1.bolt".directory = "/data/containerd/metadata"
自定义。
- Containerd v1.x 使用 BoltDB v1 版本,存储在
-
事务与并发
- Containerd 的 Metadata 插件实现了读写分离与 MVCC(多版本并发控制),保证高并发场景下操作的可见性与一致性。
- 所有元数据操作(如创建镜像记录、写入快照信息)均在事务(Transaction)中执行,保证回滚与原子性。
Runtime Plugin:容器运行时
-
Runtime Plugin v2(io.containerd.runtime.v2)
- Containerd v1.1+ 引入 Runtime v2 插件,采用新的任务(Task)模型,直接调用
runc
的 JSON Spec,性能与稳定性更优。 - 核心二进制:
containerd-shim-runc-v2
,作为 shim 进程负责将容器进程置于独立命名空间内。
- Containerd v1.1+ 引入 Runtime v2 插件,采用新的任务(Task)模型,直接调用
-
Runtime Plugin v1(io.containerd.runtime.v1)
- 兼容早期版本的 Runtime API,使用
containerd-shim
与runc
结合,适用于老系统。 - v1 与 v2 在命令行与 gRPC 接口上有部分差异,建议新项目优先选用 v2。
- 兼容早期版本的 Runtime API,使用
-
Shim 机制
-
Shim 进程用于隔离 Containerd 守护进程与容器进程,保证容器进程不会因为 Containerd 重启而被回收。
-
当执行
ctr run
或ctr task start
时:- Containerd Daemon 通过 gRPC 调用 Runtime Plugin,创建 shim 进程(如
containerd-shim-runc-v2
)。 - Shim 进程再调用
runc
启动容器进程。 - 容器进程的 StdIO(stdin/stdout/stderr)通过 FIFO 与 Client 进行通信,由 shim 进行转发。
- Containerd Daemon 通过 gRPC 调用 Runtime Plugin,创建 shim 进程(如
-
-
Runtime Config(OCI Spec)
-
Containerd 支持自定义 OCI 运行时配置,如 CPU、内存、挂载、Seccomp、AppArmor 等。
-
可以通过
--config
参数指定自定义 JSON 文件:# 示例:自定义运行时 Spec cat <<EOF > myruntime.json { "ociVersion": "1.0.2", "process": { "terminal": true, "user": { "uid": 1000, "gid": 1000 }, "args": ["sh"], "env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"], "cwd": "/" }, "root": { "path": "rootfs" }, "hostname": "containerd-test", "mounts": [ { "destination": "/proc", "type": "proc", "source": "proc" }, { "destination": "/dev", "type": "tmpfs", "source": "tmpfs", "options": ["nosuid", "strictatime", "mode=755", "size=65536k"] } ] } EOF # 运行容器时指定 sudo ctr run --runtime io.containerd.runc.v2 --config myruntime.json myimage:latest mycontainer
-
-
多 Runtime 支持
-
Containerd 支持为不同镜像或容器指定不同的 Runtime,例如
runc
、kata-runtime
、gvisor
等。 -
在配置文件(
/etc/containerd/config.toml
)中,定义多个 runtime:[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.kata] runtime_type = "io.containerd.kata.v2" runtime_engine = "/usr/bin/kata-runtime" runtime_root = "/run/kata"
-
CRI Plugin:与 Kubernetes 的对接
-
Container Runtime Interface(CRI)概览
- CRI 是 Kubernetes 提供的一套标准接口,用于与容器运行时(Container Runtime)通信。
- 通过 CRI,Kubelet 可以执行镜像拉取、容器创建、启动、停止、删除、日志获取等操作。
-
cri-containerd 插件
- Containerd 官方提供了
cri
插件(plugins."io.containerd.grpc.v1.cri"
),完全实现了 CRI v1.0 规范。 - 在
config.toml
中启用cri
插件后,Containerd 会启动一个 CRI gRPC 服务,监听unix:///run/containerd/containerd.sock
,供 Kubelet 调用。
- Containerd 官方提供了
-
关键配置示例
[plugins."io.containerd.grpc.v1.cri"] sandbox_image = "k8s.gcr.io/pause:3.6" systemd_cgroup = false stream_idle_timeout = "4h" max_container_log_line_size = 16384 [plugins."io.containerd.grpc.v1.cri".containerd] snapshotter = "overlayfs" default_runtime_name = "runc" [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] runtime_type = "io.containerd.runc.v2" runtime_engine = "" runtime_root = "" privileged_without_host_devices = false [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] SystemdCgroup = true [plugins."io.containerd.grpc.v1.cri".cni] bin_dir = "/opt/cni/bin" conf_dir = "/etc/cni/net.d" [plugins."io.containerd.grpc.v1.cri".registry] [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"] endpoint = ["https://registry.aliyuncs.com"]
-
CRI 对接流程
- Kubelet 启动时,通过
--container-runtime=remote
、--container-runtime-endpoint=unix:///run/containerd/containerd.sock
指定 CRI Socket。 - Kubelet 调用
CRI.PullImage
,Containerd 从指定 Registry 拉取镜像,并存储到 Content Store。 - Kubelet 调用
CRI.CreateContainer
,Containerd 根据 Pod Sandbox(Pause 容器)创建 Namespace、网络、挂载,并在此基础上创建应用容器。 - Kubelet 调用
CRI.StartContainer
,Containerd 通过 Runtime 插件启动 shim 与 runc,正式运行容器进程。 - 容器运行期间,Kubelet 可通过
CRI.UpdateContainerResources
、CRI.KillContainer
等接口对容器进行动态管理。
- Kubelet 启动时,通过
🚀 小结:通过
cri-containerd
插件,Containerd 完美对接 Kubernetes,省去了 Docker Shim 的额外开销,提高了性能与稳定性。
企业级落地实战
系统环境与前置依赖
-
操作系统:CentOS 7.x、RHEL 7.x、Ubuntu 18.04+、Debian 10+ 均可支持。
-
内核版本:建议 ≥
4.14
,以获得更好性能与兼容性,尤其是 OverlayFS、Seccomp、Cgroupv2 等。 -
硬件资源:每台节点 ≥ 2 核 CPU、4GB 内存、100GB 磁盘空间(推荐 SSD)。
-
网络环境:需要能够访问外部 Docker Registry(如
docker.io
、gcr.io
等)或本地私有镜像仓库(Harbor 等)。 -
依赖工具:
iptables
、iproute2
runc
(对于二进制方式安装需要额外安装)- CNI 插件包(如 Flannel、Calico、Weave 等)
crictl
(可选,用于 CLI 方式管理 CRI 镜像与容器)
安装方式对比与实践
企业生产环境常见两种安装方式:YUM(APT)包管理安装 与 二进制包离线安装。
- YUM/DEB 安装:优点是依赖自动解决、升级方便。缺点是版本可能滞后、对网络要求较高。
- 二进制离线安装:优点是版本可控、适用于无网络或镜像需要严格一致的场景;缺点是需要手动管理依赖与配置。
YUM 安装(适用于 CentOS/RHEL)
-
添加 Docker 官方仓库或第三方镜像源
# 添加阿里云 Docker CE 仓库(示例) sudo yum install -y yum-utils device-mapper-persistent-data lvm2 sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
-
查看可用 containerd 版本
sudo yum list containerd.io --showduplicates
-
安装 containerd.io
sudo yum install -y containerd.io
-
启动并设置开机自启动
sudo systemctl enable containerd sudo systemctl start containerd
-
验证安装
# 查看版本 sudo ctr version # 示例输出 # Client: # Version: 1.6.0 # Revision: 39259a8f35919a0d02c9ecc2871ddd6ccf6a7c6e # Server: # Version: 1.6.0 # Revision: 39259a8f35919a0d02c9ecc2871ddd6ccf6a7c6e
✅ Tip:YUM 安装方式会自动拉取并安装 runc、containerd、ctr、crictl 等相关二进制,对大多数常见场景足够。
二进制包安装(适用于离线环境与 Kubernetes 集群)
-
下载 containerd 二进制包
- 访问 Containerd Releases,下载对应平台的
cri-containerd-cni-<version>-linux-amd64.tar.gz
包,该包已包含runc
与 CNI 插件。 - 也可仅下载
containerd-<version>-linux-amd64.tar.gz
,此包需额外手动下载并安装runc
。
- 访问 Containerd Releases,下载对应平台的
-
解压并复制二进制文件
# 假设包名为 cri-containerd-cni-1.6.0-linux-amd64.tar.gz tar zxvf cri-containerd-cni-1.6.0-linux-amd64.tar.gz -C /tmp # 复制 containerd 二进制文件 sudo cp /tmp/usr/local/bin/containerd /usr/local/bin/ sudo cp /tmp/usr/local/bin/ctr /usr/bin/ sudo cp /tmp/usr/local/bin/containerd-shim* /usr/bin/ sudo cp /tmp/usr/local/bin/runc /usr/sbin/ # 如果包中自带 runc,则复制到 /usr/sbin sudo chmod +x /usr/sbin/runc
-
部署 systemd 单元文件
# 创建目录 sudo mkdir -p /etc/systemd/system # 将容器包中的 systemd 服务文件复制过来 sudo cp /tmp/etc/systemd/system/containerd.service /etc/systemd/system/ # 重新加载 systemd 配置 sudo systemctl daemon-reload
-
初始化默认配置文件
# 创建配置目录 sudo mkdir -p /etc/containerd # 生成默认配置信息到 /etc/containerd/config.toml sudo containerd config default > /etc/containerd/config.toml
-
替换或优化配置
- 生产环境下,建议在默认配置基础上,调整镜像加速、CNI 插件路径、Snapshot 驱动、Runtime 配置等。
sudo vim /etc/containerd/config.toml # 重点修改:snapshotter、runtime、registry mirrors、cni 配置等
-
启动 containerd
sudo systemctl enable containerd sudo systemctl start containerd # 验证 sudo systemctl status containerd sudo ctr version
✅ Tip:若仅需单机测试,可下载
containerd-<version>-linux-amd64.tar.gz
,手动安装 runc;若打算部署在 Kubernetes 集群,推荐使用cri-containerd-cni
包,一次性获取所有组件。
配置与调优
在企业级场景下,除了基础安装外,我们要关注以下几个方面的优化与定制:
基础配置文件解读
root = "/var/lib/containerd"
state = "/run/containerd"
oom_score = -999
[grpc]
address = "/run/containerd/containerd.sock"
uid = 0
gid = 0
[debug]
level = "info"
[metrics]
address = "127.0.0.1:1338"
grpc_histogram = true
[cgroup]
path = ""
[plugins]
[plugins."io.containerd.grpc.v1.cri"]
sandbox_image = "k8s.gcr.io/pause:3.6"
systemd_cgroup = true
stream_server_address = "127.0.0.1"
stream_server_port = "0"
max_container_log_line_size = 16384
[plugins."io.containerd.grpc.v1.cri".containerd]
snapshotter = "overlayfs"
default_runtime_name = "runc"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
runtime_type = "io.containerd.runc.v2"
# 可选择配置 runtime_engine、runtime_root、privileged_without_host_devices 等
[plugins."io.containerd.grpc.v1.cri".cni]
bin_dir = "/opt/cni/bin"
conf_dir = "/etc/cni/net.d"
conf_template = ""
[plugins."io.containerd.grpc.v1.cri".registry]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://docker.mirrors.ustc.edu.cn", "http://hub-mirror.c.163.com"]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."k8s.gcr.io"]
endpoint = ["https://gcr.mirrors.ustc.edu.cn/google-containers/"]
# 若使用企业内私有仓库(如 Harbor),直接添加:
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."harbor.mycompany.com"]
endpoint = ["https://harbor.mycompany.com"]
[plugins."io.containerd.snapshotter.v1.overlayfs"]
root_path = "/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs"
upperdir_label = false
root
与state
:分别指定 containerd 数据存储根目录与运行时临时目录。oom_score
:调整 containerd 进程在 OOM 情况下的优先级,-999
意味着最低可能被 OOM 杀死。metrics.address
:用于 Prometheus 抓取监控数据,可根据实际部署网络开放端口。sandbox_image
:Kubernetes Pod 的沙盒 Pause 镜像(负责网络 namespace)地址,若网络不通国际仓库,需改为国内镜像或私有镜像。systemd_cgroup
:若集群使用 systemd cgroup driver,需设为true
。snapshotter
:根据环境选择overlayfs
(大多数推荐),也可配置btrfs
或zfs
。registry.mirrors
:为不同 Registry 配置镜像加速或私有仓库地址,显著提升镜像拉取速度。
针对企业场景的镜像加速与私有仓库配置
-
添加公共镜像加速器
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"] endpoint = ["https://registry-aliyun.example.com"] [plugins."io.containerd.grpc.v1.cri".registry.mirrors."gcr.io"] endpoint = ["https://gcr.mirrors.ustc.edu.cn"]
-
配置私有仓库(Harbor)
-
步骤 1:主机名解析
# 在所有 containerd 节点 /etc/hosts 添加: 10.0.0.10 harbor.mycompany.com
-
步骤 2:修改
config.toml
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."harbor.mycompany.com"] endpoint = ["https://harbor.mycompany.com"]
-
步骤 3:重启 containerd
sudo systemctl restart containerd
-
步骤 4:验证拉取
# 登录 Harbor sudo ctr images pull docker.io/library/nginx:latest sudo ctr images tag docker.io/library/nginx:latest harbor.mycompany.com/project/nginx:latest sudo ctr images push harbor.mycompany.com/project/nginx:latest
-
📈 Tip:对于私有仓库,如果启用了 TLS 证书,请确保证书链正确配置在系统信任列表中;对于 HTTP 协议,还需在
config.toml
中添加insecure_skip_verify = true
或plain_http = true
(视版本而定)。
安全性与权限控制
-
Seccomp 与 AppArmor
- 默认启用了 Seccomp,若有特殊需求可自定义
seccomp.json
配置。 - 对于 Ubuntu 系列,可结合 AppArmor 进行白名单控制。
- 默认启用了 Seccomp,若有特殊需求可自定义
-
Cgroup 权限隔离
- 建议启用
systemd_cgroup = true
,将容器进程以 systemd 单元的方式管理,便于监控与限速。 - 可通过
ctr run --cgroup
指定容器的 cgroup 路径,进行资源限制。
- 建议启用
-
TLS 与认证
- Containerd 的 gRPC 接口支持 TLS 验证,可在
--address
配置中添加--tls-cert
与--tls-key
。 - 在受限网络环境,可将 gRPC Socket 设为私有 Unix Domain Socket,并设置文件权限。
- Containerd 的 gRPC 接口支持 TLS 验证,可在
与 Kubernetes 集成:CRI-Overshadow
Kubelet 配置示例
在 Kubernetes 节点上,需修改 Kubelet 的启动参数,使其使用 containerd 作为运行时。
编辑 /var/lib/kubelet/kubeadm-flags.env
(或 /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
):
KUBELET_KUBEADM_ARGS="--container-runtime=remote \
--container-runtime-endpoint=unix:///run/containerd/containerd.sock \
--runtime-request-timeout=15m \
--image-service-endpoint=unix:///run/containerd/containerd.sock \
--pod-infra-container-image=registry.aliyun.com/google_containers/pause:3.6"
--container-runtime-endpoint
:指定 CRI Socket 地址,默认为/run/containerd/containerd.sock
。--pod-infra-container-image
:Pause 镜像地址,需要与config.toml
中的sandbox_image
一致。
重载并重启 kubelet:
sudo systemctl daemon-reload
sudo systemctl restart kubelet
CNI 与网络插件对接
-
安装 CNI 插件
# 假设放在 /opt/cni/bin sudo mkdir -p /opt/cni/bin # 下载安装 Flannel/Calico CNI tar zxvf calico-amd64-v3.19.1.tgz -C /opt/cni/bin
-
配置 CNI 网络
-
将 CNI 配置文件放在
/etc/cni/net.d/
下,例如/etc/cni/net.d/10-calico.conflist
:{ "name": "k8s-pod-network", "cniVersion": "0.3.1", "plugins": [ { "type": "calico", "log_level": "info", "datastore_type": "kubernetes", "k8s_auth_token": "__SERVICEACCOUNT_TOKEN", "k8s_auth_authority": "https://10.96.0.1:443", "k8s_client_certificate": "/etc/cni/net.d/calico-kubeconfig", "ipam": { "type": "calico-ipam" }, "policy": { "type": "k8s" }, "kubernetes": { "kubeconfig": "/etc/cni/net.d/calico-kubeconfig" } }, { "type": "portmap", "snat": true, "capabilities": {"portMappings": true} } ] }
-
确保
config.toml
中的 CNI 路径一致:[plugins."io.containerd.grpc.v1.cri".cni] bin_dir = "/opt/cni/bin" conf_dir = "/etc/cni/net.d"
-
-
验证网络插件生效
# 查看节点上是否创建了 cni0、flannel.1 等网络接口 ip a show cni0 ip a show flannel.1 # 在 Kubernetes 中创建一个测试 Pod,验证 Pod 间通信 kubectl run test-pod --rm -it --restart=Never --image=busybox -- sh # 在容器内部 ping 另一个 Pod IP
示例:在 K8s 中使用 Containerd 部署应用
-
部署 nginx 应用
apiVersion: v1 kind: Pod metadata: name: nginx-demo spec: containers: - name: nginx image: nginx:1.21-alpine ports: - containerPort: 80
kubectl apply -f nginx-pod.yaml
-
查看容器创建过程
-
Kubelet 调用
CRI.PullImage
:sudo ctr -n k8s.io images ls | grep nginx
-
Kubelet 调用
CRI.CreateContainer
与CRI.StartContainer
:# 查看 containerd 运行的容器 sudo ctr containers ls | grep nginx-demo # 查看 containerd 运行的任务 sudo ctr tasks ls | grep nginx-demo
-
-
调试与排障
-
查看 Pod 事件:
kubectl describe pod nginx-demo
-
查看 Kubelet 日志:
sudo journalctl -u kubelet -f
-
查看 Containerd 日志:
sudo journalctl -u containerd -f
-
🚀 Tip:在高并发场景下,建议使用更轻量的镜像(如 distroless、Alpine)以加速镜像拉取与启动,同时在集群内部署 Registry Cache 节点,减少跨网络拉取延迟。
日志与监控
Prometheus 监控指标
Containerd 自带 Metrics 插件,将监控数据以 Prometheus 格式暴露在指定端口,便于采集与可视化。
-
在
config.toml
中启用 Metrics[metrics] address = "0.0.0.0:1338" grpc_histogram = true
-
常见 Metrics 列表
containerd_runtime_operations_seconds_count{operation="pull"}
:拉取镜像耗时统计。containerd_tasks_create_duration_seconds
:创建容器任务耗时。containerd_snapshotter_usage_bytes{snapshotter="overlayfs"}
:Snapshot 驱动存储使用量。containerd_content_store_blob_total
:Content Store 中 Blob 总数。
-
Prometheus 配置示例
scrape_configs: - job_name: 'containerd' metrics_path: /metrics static_configs: - targets: ['node1:1338', 'node2:1338']
-
Grafana 可视化
- 官方提供了 Containerd 监控 Dashboard,可直接导入到 Grafana 中。
- 通过监控 Snapshot 使用量、镜像拉取速率、容器启动延迟等指标,快速定位存储、网络或调度瓶颈。
常见日志路径与排障方法
-
Containerd 日志
-
默认使用 systemd 进行管理,查看命令:
sudo journalctl -u containerd -f
-
日志等级可通过
config.toml
中的[debug] level = "debug"
调整。
-
-
Shim 与 runc 日志
-
containerd-shim-runc-v2
启动时,会将 Stdout/Stderr 重定向到 systemd 日志中,可通过journalctl -u containerd
一并查看。 -
若调试运行时失败,可设置
--log-level debug
参数启动 shim:sudo containerd --log-level debug
-
-
Kubelet 日志
sudo journalctl -u kubelet -f
- 报错如
Failed to create containerd client
、ImagePullBackOff
等,可查看 Kubelet 与 Containerd 交互的细节。
- 报错如
-
CNI 插件日志
- 一般打印在
/var/log/calico/
或/var/log/flannel/
目录下,需根据具体插件查询相应日志。 - 如 Pod 启动后无网络,可查看 CNI 是否正常加载配置与二进制。
- 一般打印在
性能分析与优化
Benchmarks 对比(Bucketbench、Microbench)
-
Bucketbench 简介
- Bucketbench 是 CNCF 推出的容器运行时基准测试工具,对启动、停止、删除容器等操作进行对比。
- 常见对比对象:Docker(内置 containerd)、containerd(runc)、CRI-O、CRI-Dockerd、gVisor 等。
-
示例 Benchmark 结果对比
操作项 Docker (containerd v1.4) Containerd (v1.4 + runc) CRI-O (v1.20) 创建容器 80ms 65ms 70ms 启动容器 120ms 95ms 110ms 停止容器 35ms 25ms 30ms 删除容器 40ms 30ms 32ms 拉取镜像 800ms 750ms 770ms 镜像解压时长 1.2s 1.0s 1.1s 结论:
- Containerd 直接使用 runc,省去了 Docker Engine 的额外封装层,在容器启动与删除等场景下表现更优。
- CRI-O 与 Containerd 性能相近,但在镜像管理与插件生态上,Containerd 更为丰富。
-
Microbench:微基准测试
-
通过对单个操作(如
ctr run
、ctr pull
、ctr delete
)进行细粒度测量,分析不同 Snapshot 驱动、网络插件、存储后端对性能的影响。 -
示例命令:
# 基于 overlayfs 测试启动 100 次 nginx 容器 for i in $(seq 1 100); do sudo time ctr run --rm --snapshotter overlayfs docker.io/library/nginx:alpine bench.$$ sh -c "echo hello" done
-
调优思路与最佳实践
快照驱动与存储后端调优
-
OverlayFS 优化
-
设置
mount
参数:metacopy=on
:减少copy-up
时元数据操作,提高写性能。upperdir_label
:与 SELinux 配合时可开启标签。
-
如果底层文件系统为 XFS,可使用
ftype=1
格式化,有助于 Overlay 性能。
-
-
Btrfs / ZFS 场景
- Btrfs/ZFS 原生支持写时复制(COW),可在多容器场景下减少层复制开销,提升快照创建速度。
- 代价是需要额外学习与调优,如设置 ZFS
recordsize
、Btrfscompress
等参数。
-
分布式存储与共享
- 对于多节点场景,可结合 Ceph/Rook、GlusterFS、NFS 等分布式存储,统一 Content Store 与 Snapshot Store,减少跨节点拉取延迟。
- 需注意挂载性能、并发访问瓶颈与网络带宽限制。
网络层与 CNI 调优
-
CNI Plugin 选择
- Flannel:易于部署,支持 VXLAN 与 Host-GW 模式,适用于中小规模集群。
- Calico:支持 BGP 路由,网段灵活,可与 Istio 等服务网格无缝集成。
- Weave:支持 mesh 网络,拓扑自愈能力强。
-
IPAM 与 MTU 调整
- 根据集群物理网络 MTU 来调整 CNI 网络 MTU,避免分片带来的性能下降。
- 如物理网络 MTU = 1500,则设置 CNI MTU = 1450(VXLAN 头部开销)或更合适的数值。
-
Host Networking vs Bridge 模式
- Host Networking:容器直接使用宿主机网络,性能最好,但缺少隔离;适用于高性能网络应用(如 DPDK)。
- Bridge 模式:通过 Linux bridge 或虚拟交换机隔离网络,安全与隔离性好,性能略低于 Host。
收敛时间与资源隔离
-
容器启动收敛时间
- 优化镜像体积:尽可能使用精简镜像(如 multistage 编译、distroless),减少拉取与解压时间。
- 本地镜像缓存:部署 Registry Cache 节点或使用 CDN 缓存,以降低跨网络拉取耗时。
-
资源隔离与 QoS
- 使用 cgroup v2 或 systemd cgroup driver,实现对容器 CPU、内存、IO 的精细限制。
- 结合 Kubernetes QoS(Guaranteed/Burstable/BestEffort)策略,保证关键业务容器资源优先级。
常见问题与故障排查
服务无法启动
-
检查 systemd 状态
sudo systemctl status containerd
-
若出现
Failed to start containerd
,查看具体错误日志:sudo journalctl -u containerd -xe
-
-
配置文件语法错误
-
修改
/etc/containerd/config.toml
后,可能出现 TOML 语法错误:- 使用
containerd --config /etc/containerd/config.toml config check
验证(部分版本支持)。 - 也可将配置文件输出到临时文件,尝试用
toml
lint 工具进行校验。
- 使用
-
-
端口或 Socket 冲突
-
默认 gRPC 监听
unix:///run/containerd/containerd.sock
,若 Socket 已被占用,可尝试删除旧文件:sudo rm /run/containerd/containerd.sock sudo systemctl restart containerd
-
若
metrics.address
绑定端口与其他服务冲突,需修改或关闭 Metrics。
-
容器无法拉取镜像
-
网络连通性问题
-
验证节点能否访问外部 Registry:
curl -v https://registry-1.docker.io/v2/
-
若走私有仓库,检查
/etc/hosts
或 DNS 是否正确解析。
-
-
TLS 证书验证失败
-
私有仓库若使用自签名证书,需将根证书添加到节点的系统信任列表:
sudo cp ca.crt /etc/pki/ca-trust/source/anchors/ sudo update-ca-trust sudo systemctl restart containerd
-
或在
config.toml
中启用insecure_skip_verify
(不推荐,仅测试时使用)。
-
-
镜像名称或标签错误
-
Containerd 的
ctr
命令需要指定完整路径,如docker.io/library/nginx:latest
,否则可能拉取失败:sudo ctr images pull docker.io/library/nginx:latest
-
若镜像是私有镜像,需要先登录:
sudo ctr images pull --user=username:password harbor.mycompany.com/project/nginx:latest
-
容器启动失败
-
Runtime 错误
-
查看 shim 与 runc 报错:
sudo journalctl -u containerd -n 50
-
常见原因:Seccomp 或 AppArmor 限制,缺少特权权限或 Capabilities。
- 可在运行时加上
--security-opt seccomp=unconfined
或--privileged
测试。
- 可在运行时加上
-
-
挂载或 Volume 问题
-
检查挂载点是否存在、权限是否正确:
ls -ld /data/myvolume sudo chown 1000:1000 /data/myvolume
-
CNI 网络未准备好,导致容器创建时网络 namespace 创建失败,可通过
ctr network ls
(部分版本)或查看cni
日志定位。
-
-
资源不足
-
查看系统资源:
free -h df -h
-
检查 cgroup 限制:
sudo cgget -r cpu.cfs_quota_us /kubepods.slice sudo cgget -r memory.limit_in_bytes /kubepods.slice
-
性能瓶颈与高内存占用
-
Content Store 与 Metadata Store 数据量过大
-
定期清理无用镜像与快照:
sudo ctr images rm $(sudo ctr images ls -q | grep "<none>") sudo ctr snapshots cleanup
-
确保
GC
插件正常运行,可在config.toml
中调整deletion_threshold
、mutation_threshold
触发频率。
-
-
过多的 Shim 进程
- 每个容器对应一个
containerd-shim-runc-v2
进程,容器数量过多可能占用大量内存。 - 可通过
ctr tasks ls
压测容器并发承载能力,并合理规划节点规模。
- 每个容器对应一个
-
CNI 插件内存泄漏
- 某些版本的 CNI 插件可能存在内存泄漏,升级到最新稳定版本,或切换到更轻量插件如 Flannel VXLAN。
- 定期重启
containerd
与kubelet
,清理可能残留的网络 namespace 与进程。
总结与展望
✅ Containerd 作为 CNCF 顶级项目,已成为当前云原生生态中不可或缺的容器运行时。通过其轻量、插件化、性能优越的特点,成功取代了早期的 Docker Shim,成为 Kubernetes、云平台与企业内部容器平台的首选底层引擎。
核心优势
- 高性能:直接调用 runc,无需额外封装层,启动、停止、删除容器效率高。
- 插件化设计:灵活接入不同存储、网络、运行时插件,满足多种场景需求。
- 社区活跃:CNCF 资助、厂商支持,版本迭代迅速,生态兼容性强。
- 企业实战:已在阿里、腾讯、华为、百度等大规模生产环境中广泛应用,支撑千万级容器规模。
未来展望
- 多样化运行时:与 WebAssembly(WASM)、gVisor、Kata Containers 等运行时深度集成,以满足更高安全隔离需求。
- CNI 与 Service Mesh 深度融合:网络与服务网格(如 Istio、Linkerd)更加紧密结合,为复杂微服务场景提供更高效的流量管理与监控。
- 更丰富的可观察性:通过 eBPF、OpenTelemetry 等技术,提升对容器网络、系统调用、性能指标的可视化与告警能力。
- 边缘与 IoT 场景:针对边缘计算节点资源受限特性,推出更轻量化、自动化的 Containerd 发行版,适配 IoT 与边缘场景。
🎯 技术沉淀:本文从 Containerd 的演进背景切入,深入剖析其架构与关键模块,并结合丰富的企业级实战经验与性能对比,帮助读者全面理解 Containerd 在生产环境中的落地实践。
🚀 社区贡献:欢迎各位技术同仁在 GitHub 上为 Containerd 社区贡献代码、提交 Issue、参与讨论,共同推动云原生生态的繁荣。
参考链接
- Containerd 官方文档
- GitHub: containerd/containerd
- Kubernetes CRI 文档
- CNCF Containerd 监控 Dashboard (Grafana)
- Docker vs Containerd vs CRI-O 对比分析
- OverlayFS 调优最佳实践
- Flannel CNI 插件使用手册
- Calico CNI 插件官方文档
- Kata Containers 官方文档
- gVisor 用户指南