3. CRI接口基础:容器运行时接口(CRI)定义、CRI与Kubelet交互模型、常见CRI实现(containerd/cri-o)
3.1 容器运行时接口(CRI)定义
CRI(Container Runtime Interface)是 Kubernetes 在 v1.5 引入的插件化接口协议,用于解耦 kubelet 与底层容器运行时。CRI 定义了 kubelet 与容器运行时之间的 gRPC 通信契约,使得任何实现了该接口的运行时都能无缝接入 Kubernetes 集群。
核心设计目标: 将容器运行时的实现细节从 kubelet 中剥离,实现“一次实现,随处运行”的插件化架构。
CRI 接口主要包含两个 gRPC 服务:
| 服务名称 | gRPC 服务定义 | 核心方法 | 职责 |
|---|---|---|---|
| RuntimeService | runtime.RuntimeService |
RunPodSandbox, CreateContainer, StartContainer, StopContainer, RemoveContainer |
管理 Pod 沙箱和容器的生命周期 |
| ImageService | runtime.ImageService |
PullImage, ListImages, RemoveImage, ImageStatus |
管理容器镜像的拉取、列表和删除 |
关键概念: Pod 沙箱(PodSandbox)是 CRI 中的一等公民,它对应 Kubernetes 中的 Pod 级别隔离环境(如 Linux Namespace 和 Cgroups)。容器必须运行在某个沙箱内。
3.2 CRI 与 Kubelet 交互模型
kubelet 作为 Kubernetes 节点代理,通过 CRI 接口与容器运行时通信。整个交互流程遵循“kubelet 主动调用 → 运行时响应 → 状态上报”的同步模型。
交互模型的关键特征:
- 同步调用: kubelet 通过 gRPC 同步调用运行时接口,等待返回结果后继续执行。
- 无状态设计: 运行时不维护 kubelet 的会话状态,每次调用都是独立的。
- 事件驱动: kubelet 监听 Pod 变更事件,触发对应的 CRI 调用序列。
- 健康检查: kubelet 通过
RuntimeService.Status()检测运行时是否可用。
3.3 常见 CRI 实现:containerd 与 CRI-O
目前社区主流的 CRI 实现是 containerd 和 CRI-O,两者都遵循 OCI(Open Container Initiative)标准,但在架构设计和生态定位上存在差异。
3.4 关键差异对比
| 对比维度 | containerd | CRI-O |
|---|---|---|
| 起源 | Docker 公司开源,CNCF 毕业项目 | Red Hat / SUSE 主导,OCI 原生 |
| CRI 集成方式 | 内置 CRI Plugin(io.containerd.grpc.v1.cri) |
原生 CRI 实现,无额外 shim |
| 镜像管理 | 自研快照器(snapshotter),支持 overlayfs/devicemapper | 使用 containers/image 库,支持多种存储驱动 |
| 容器监控 | 内置 metrics 端点,支持 Prometheus | 依赖 conmon 进程收集日志和退出状态 |
| 默认 OCI Runtime | runc | runc / crun(可选) |
| 社区生态 | 广泛用于 Docker Desktop、K3s、Rancher | OpenShift 默认运行时,Fedora CoreOS 集成 |
| 配置复杂度 | 中等,需配置 /etc/containerd/config.toml |
较低,/etc/crio/crio.conf 结构清晰 |
3.5 节点扩容场景下的 CRI 角色
在集群节点扩容时,CRI 接口承担以下关键职责:
- 运行时初始化: 新节点加入集群后,kubelet 通过 CRI 检测容器运行时是否就绪。
- 镜像预热: 扩容时可能需要提前拉取业务镜像,CRI 的
PullImage接口负责执行。 - Pod 调度执行: 调度器将 Pod 分配到新节点后,kubelet 通过 CRI 创建沙箱和容器。
- 状态同步: 扩容过程中,kubelet 通过 CRI 的
ListContainers接口获取运行时状态,确保 Pod 状态与 API Server 一致。
扩容注意事项: 如果节点上容器运行时未正确配置 CRI 端点(默认 Unix socket 路径
/run/containerd/containerd.sock 或 /var/run/crio/crio.sock),kubelet 将无法启动,导致节点处于 NotReady 状态。务必在节点初始化脚本中验证 CRI socket 的存在性。
3.6 验证 CRI 接口可用性
在节点上可以使用 crictl 工具直接与 CRI 运行时通信,验证接口是否正常工作:
# 查看 CRI 运行时版本
crictl version
# 列出所有 Pod 沙箱
crictl pods
# 列出所有容器
crictl ps -a
# 拉取测试镜像
crictl pull nginx:alpine
# 查看运行时状态
crictl info
生产建议: 在节点扩容的自动化脚本中,建议加入
crictl info 的健康检查步骤,确保 CRI 接口在 kubelet 启动前已就绪。如果使用 containerd,还可以通过 ctr 命令直接操作 containerd 核心 API 进行调试。