2. 主流容器运行时对比:containerd、CRI-O、Docker(通过 dockershim)的架构差异、性能特点与选型建议
在 Kubernetes 生态中,容器运行时是负责拉取镜像、创建容器、管理容器生命周期的核心组件。自 Kubernetes v1.24 正式移除 dockershim 后,社区对容器运行时的选择变得更加聚焦。本章从架构差异、性能特点与选型建议三个维度,对 containerd、CRI-O 以及已退役的 Docker(通过 dockershim)进行深度对比。
2.1 架构差异对比
三种运行时的核心差异在于:组件耦合度、CRI 适配层实现方式以及守护进程模型。下图展示了三者在 Kubernetes 节点中的架构层级关系。
架构关键差异:containerd 和 CRI-O 是“原生 CRI 运行时”,而 Docker 是“通用容器引擎 + 适配层”。dockershim 的移除标志着 Kubernetes 不再为通用引擎的适配层买单。
2.2 性能特点对比
性能差异主要体现在容器启动延迟、镜像拉取效率、内存占用和并发吞吐量四个维度。以下表格基于社区基准测试数据(Kubernetes Node Performance Test)整理。
| 性能指标 | containerd | CRI-O | Docker + dockershim |
|---|---|---|---|
| 容器启动延迟 (P99) | ~120ms | ~135ms | ~180ms |
| 镜像拉取吞吐量 | 高(并发层优化好) | 中(依赖底层存储驱动) | 中(Docker 层序列化开销) |
| 常驻内存占用 | ~30MB | ~35MB | ~120MB(含 dockershim) |
| 并发 Pod 创建速率 | ~50 Pod/s | ~45 Pod/s | ~30 Pod/s |
| CRI 调用延迟 | 低(原生 gRPC) | 低(原生 gRPC) | 中(API 转换开销) |
| 存储驱动兼容性 | overlay2, devicemapper | overlay2, aufs | overlay2, aufs, devicemapper |
性能调优提示:在 containerd 中,通过调整
[plugins."io.containerd.grpc.v1.cri".containerd] 下的 snapshotter 和 discard_unpacked_layers 参数,可以进一步降低镜像解压延迟。CRI-O 则可通过 conmon 的 --exit-delay 参数优化容器退出时的资源回收速度。
2.3 选型建议与场景匹配
选型不能只看性能数字,还需考虑社区活跃度、生态兼容性、运维复杂度和安全需求。以下决策树和表格可帮助团队快速定位。
2.4 选型建议总结
- 生产环境 Kubernetes 集群:首选 containerd。它是 CNCF 毕业项目,社区活跃度最高,性能均衡,与 Kubernetes 集成最紧密。推荐版本 v1.7.x 以上。
- 安全敏感场景(多租户、金融、边缘):推荐 CRI-O + crun/kata。CRI-O 架构更精简,配合 crun(C 语言重写的 OCI 运行时)可进一步降低启动延迟;结合 Kata Containers 实现硬件虚拟化隔离。
- 开发/CI 环境:可继续使用 Docker。虽然 dockershim 已移除,但通过
cri-dockerd适配器仍可接入 Kubernetes,且 Docker 的开发者体验和调试工具链更成熟。 - 边缘计算/资源受限节点:推荐 CRI-O。其内存占用略低于 containerd,且不依赖 Docker 的复杂组件栈,适合 2C4G 以下的节点。
避坑指南:不要在生产环境同时部署多个容器运行时。每个节点只能注册一个 CRI 运行时给 kubelet。混合部署会导致 kubelet 无法正确识别 Pod 状态,引发调度混乱。迁移运行时前,务必在测试集群验证
kubectl drain 和 kubelet 重启 流程。
2.5 迁移路径参考
如果当前集群仍在使用 Docker + dockershim,建议按以下步骤迁移至 containerd:
- 评估兼容性:检查所有工作负载是否依赖 Docker 特有功能(如
docker exec、docker logs的特定参数)。 - 节点打标与排水:使用
kubectl cordon和kubectl drain逐节点下线。 - 安装 containerd:通过包管理器或二进制安装 containerd v1.7+,配置
/etc/containerd/config.toml启用 CRI 插件。 - 更新 kubelet 配置:修改
/var/lib/kubelet/kubeadm-flags.env中的--container-runtime=remote和--container-runtime-endpoint=unix:///run/containerd/containerd.sock。 - 重启 kubelet:
systemctl restart kubelet,验证节点状态为 Ready。 - 逐步上线:每次迁移 1-2 个节点,观察集群稳定性后再批量操作。
# containerd 核心配置示例(/etc/containerd/config.toml)
version = 2
[plugins."io.containerd.grpc.v1.cri"]
sandbox_image = "registry.k8s.io/pause:3.9"
[plugins."io.containerd.grpc.v1.cri".containerd]
snapshotter = "overlayfs"
default_runtime_name = "runc"
discard_unpacked_layers = true
[plugins."io.containerd.grpc.v1.cri".registry]
config_path = "/etc/containerd/certs.d"
迁移验证命令:迁移完成后,使用
crictl info 查看运行时版本和 CRI 插件状态;使用 crictl pods 和 crictl ps 验证 Pod 和容器列表是否正常。