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 主动调用 → 运行时响应 → 状态上报”的同步模型。

CRI 与 Kubelet 交互模型 CRI 与 Kubelet 交互模型 Kubelet 节点代理 CRI gRPC RuntimeService / ImageService 容器运行时 containerd / CRI-O 调用流程(以创建 Pod 为例): 1. kubelet 调用 RunPodSandbox 创建 Pod 沙箱 2. kubelet 调用 CreateContainer 创建 Init 容器 / 业务容器 3. kubelet 调用 StartContainer 启动容器进程 4. 运行时返回状态,kubelet 更新 Pod 状态到 API Server 状态上报机制: • kubelet 定期调用 ListPodSandbox / ListContainers 获取运行时状态 • 运行时返回 PodSandboxStatus / ContainerStatus 结构体 • kubelet 将状态同步到 API Server 的 PodStatus 字段

交互模型的关键特征:

  • 同步调用: kubelet 通过 gRPC 同步调用运行时接口,等待返回结果后继续执行。
  • 无状态设计: 运行时不维护 kubelet 的会话状态,每次调用都是独立的。
  • 事件驱动: kubelet 监听 Pod 变更事件,触发对应的 CRI 调用序列。
  • 健康检查: kubelet 通过 RuntimeService.Status() 检测运行时是否可用。

3.3 常见 CRI 实现:containerd 与 CRI-O

目前社区主流的 CRI 实现是 containerd 和 CRI-O,两者都遵循 OCI(Open Container Initiative)标准,但在架构设计和生态定位上存在差异。

containerd 与 CRI-O 架构对比 containerd 与 CRI-O 架构对比 containerd 架构 CRI Plugin (内置) containerd 核心 (ctr) OCI Runtime (runc / kata) • CRI 作为内置插件,无需额外 shim • 支持多租户命名空间隔离 • 镜像拉取、快照管理一体化 • 默认使用 runc 作为 OCI runtime CRI-O 架构 CRI-O 守护进程 conmon (容器监控) OCI Runtime (runc / crun) • 专为 Kubernetes 设计,无多余功能 • 依赖 conmon 管理容器进程 • 镜像拉取使用 containers/image • 支持 crun (C 语言实现) 作为 runtime

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 进行调试。