3. CRI(Container Runtime Interface)概述:CRI的诞生背景、接口定义与主流实现
3.1 CRI 的诞生背景:从“紧耦合”到“标准化”
在 Kubernetes 早期版本(v1.5 之前),kubelet 与容器运行时的交互是硬编码的。kubelet 内部直接通过 Docker API 调用 Docker Engine 来创建、启动、删除容器。这种架构存在三个核心痛点:
- 供应商锁定:Kubernetes 与 Docker 深度绑定,无法接入其他容器运行时(如 rkt、Hyper.sh、Kata Containers)。
- 版本耦合:kubelet 必须跟随 Docker API 的版本升级而修改代码,维护成本极高。
- 社区分裂风险:每个运行时都想成为 Kubernetes 的“一等公民”,但缺乏统一的接入标准。
为了解决上述问题,Kubernetes 社区在 2016 年提出了 CRI(Container Runtime Interface),作为 kubelet 与容器运行时之间的中间层抽象。CRI 使用 Protocol Buffers(protobuf) 定义 gRPC 服务,将容器生命周期管理、镜像管理、Pod 沙箱管理等操作标准化。从此,任何实现了 CRI 接口的运行时都可以无缝接入 Kubernetes。
关键里程碑:Kubernetes v1.5 引入 CRI(Alpha),v1.6 进入 Beta,v1.10 正式 GA。Dockershim 作为 Docker 的 CRI 适配器被内置在 kubelet 中,直到 v1.24 被彻底移除。
3.2 CRI 接口定义:RuntimeService 与 ImageService
CRI 将容器运行时管理拆分为两个独立的 gRPC 服务:
| 服务名称 | 核心职责 | 关键 RPC 方法 |
|---|---|---|
| RuntimeService | 管理 Pod 沙箱(Sandbox)和容器的完整生命周期 | RunPodSandbox、StopPodSandbox、CreateContainer、StartContainer、StopContainer、RemoveContainer、ContainerStatus |
| ImageService | 管理容器镜像的拉取、列表、检查和删除 | PullImage、ListImages、ImageStatus、RemoveImage、ImageFsInfo |
设计要点:Pod 在 CRI 中被抽象为“沙箱”(Sandbox)。对于基于 VM 的运行时(如 Kata Containers),一个沙箱就是一个轻量级虚拟机;对于传统容器运行时,沙箱通常对应一个隔离的 Linux 命名空间(Network、PID、IPC 等)。
以下是一个典型的 RunPodSandboxRequest 消息结构示例:
message RunPodSandboxRequest {
// Pod 沙箱的唯一标识
string pod_sandbox_id = 1;
// 沙箱配置,包含 Pod 名称、UID、命名空间、DNS 等
PodSandboxConfig config = 2;
// 运行时特定的扩展配置
RuntimeConfig runtime_config = 3;
}
message PodSandboxConfig {
string name = 1;
string uid = 2;
string namespace = 3;
// 主机名、DNS 配置、端口映射、标签、注解等
DNSConfig dns_config = 4;
repeated PortMapping port_mappings = 5;
map<string, string> labels = 6;
map<string, string> annotations = 7;
LinuxPodSandboxConfig linux = 8;
}
3.3 主流 CRI 实现对比
目前社区主流的 CRI 实现有三个:containerd、CRI-O 和 Docker(通过 Dockershim)。Dockershim 已在 Kubernetes v1.24 中被移除,但仍有大量存量集群在使用。
| 特性 | containerd | CRI-O | Docker + Dockershim(已弃用) |
|---|---|---|---|
| 所属组织 | CNCF(毕业项目) | CNCF(孵化项目) | Docker Inc. |
| 核心定位 | 工业级容器运行时,强调稳定性和性能 | 专为 Kubernetes 优化的轻量级运行时 | 通用容器平台,通过适配器接入 K8s |
| 镜像格式 | OCI 镜像规范 | OCI 镜像规范 | Docker 镜像 + OCI 兼容 |
| CRI 实现方式 | 内置 CRI 插件(cri) |
原生 CRI 实现 | kubelet 内置 Dockershim 适配器 |
| 资源开销 | 低(无 Docker daemon 开销) | 极低(最小化依赖) | 高(需运行完整 Docker daemon) |
| Kubernetes 默认 | v1.24+ 默认运行时 | OpenShift 默认运行时 | v1.23 及之前默认(已弃用) |
3.4 如何选择 CRI 实现?
在选择 CRI 实现时,建议从以下维度评估:
- Kubernetes 版本兼容性:v1.24+ 推荐 containerd,OpenShift 推荐 CRI-O。
- 运维复杂度:containerd 和 CRI-O 都比 Docker 轻量,无需管理 Docker daemon。
- 生态集成:如果需要与 Docker Compose、Docker Swarm 等工具共存,Docker 仍有优势(但需注意 K8s 已弃用)。
- 性能与资源:containerd 和 CRI-O 在启动延迟、内存占用上优于 Docker。
注意:从 Kubernetes v1.24 开始,Dockershim 已被彻底移除。如果集群仍在使用 Docker 作为运行时,必须迁移到 containerd 或 CRI-O,否则无法升级到 v1.24+。