2. CRI 接口基础:设计理念与核心接口定义

容器运行时接口(Container Runtime Interface,CRI)是 Kubernetes 在 1.5 版本引入的插件化抽象层,它定义了 kubelet 与容器运行时之间的标准通信协议。CRI 的诞生解决了早期 Kubernetes 对 Docker 的强依赖问题,使得任何实现了 CRI 接口的容器运行时(如 containerd、CRI-O、Kata Containers)都能无缝接入 Kubernetes 集群。

2.1 CRI 的设计理念

CRI 的设计遵循三个核心原则:解耦、标准化、最小化。这三个原则共同确保了 kubelet 与运行时之间的边界清晰、协议稳定、实现轻量。

设计原则 核心含义 工程价值
解耦 kubelet 不直接调用运行时 API,而是通过 gRPC 调用 CRI 定义的抽象接口 运行时实现可独立演进,kubelet 无需感知底层容器引擎差异
标准化 定义统一的 Pod 生命周期管理、镜像管理、执行命令等操作语义 所有符合 CRI 的运行时提供一致的调用体验,降低运维心智负担
最小化 只暴露 kubelet 必须的操作,不包含运行时内部实现细节 接口稳定、版本兼容性好,运行时实现方有充分的优化空间
关键洞察: CRI 不是容器运行时的通用 API,而是 kubelet 视角的运行时抽象。它只关心 kubelet 需要做什么(创建 Pod、启动容器、挂载卷),不关心运行时怎么做(使用 runc、runv 还是 gVisor)。

2.2 CRI 核心接口定义

CRI 基于 gRPC 协议定义了两组核心服务:RuntimeService 和 ImageService。前者负责 Pod 和容器的生命周期管理,后者负责镜像的拉取、列表和删除。以下是最核心的接口方法及其语义:

2.2.1 RuntimeService(运行时服务)

接口方法 请求/响应 功能描述
RunPodSandbox RunPodSandboxRequest / RunPodSandboxResponse 创建 Pod 沙箱(如 Linux 网络命名空间、cgroup 父目录),返回 PodSandboxID
StopPodSandbox StopPodSandboxRequest / StopPodSandboxResponse 停止 Pod 沙箱,回收网络和存储资源
RemovePodSandbox RemovePodSandboxRequest / RemovePodSandboxResponse 删除 Pod 沙箱,清理所有残留资源
CreateContainer CreateContainerRequest / CreateContainerResponse 在指定 PodSandbox 内创建容器,返回 ContainerID
StartContainer StartContainerRequest / StartContainerResponse 启动已创建的容器进程
StopContainer StopContainerRequest / StopContainerResponse 停止容器(支持 GracePeriod 优雅关闭)
RemoveContainer RemoveContainerRequest / RemoveContainerResponse 删除容器,释放存储层资源
ExecSync ExecSyncRequest / ExecSyncResponse 在容器内同步执行命令,返回 stdout/stderr/exit_code

2.2.2 ImageService(镜像服务)

接口方法 请求/响应 功能描述
ListImages ListImagesRequest / ListImagesResponse 列出节点上所有已拉取的镜像,包含 repoTag、大小、UID
PullImage PullImageRequest / PullImageResponse 从镜像仓库拉取镜像,支持认证配置和镜像拉取策略
RemoveImage RemoveImageRequest / RemoveImageResponse 删除节点上的指定镜像,释放磁盘空间
ImageStatus ImageStatusRequest / ImageStatusResponse 查询镜像的详细元数据,用于判断镜像是否存在
实践提示: 在节点扩容场景中,PullImage 和 RunPodSandbox 是最关键的接口。扩容时 kubelet 会频繁调用这两个接口,它们的性能直接影响 Pod 启动速度。建议在 containerd 或 CRI-O 中开启镜像预拉取(Image Pre-pulling)和沙箱缓存(Sandbox Cache)来优化扩容效率。

2.3 CRI 接口调用流程

下图展示了 kubelet 通过 CRI 接口创建 Pod 的完整调用链,从 PodSandbox 创建到容器启动,清晰呈现了 RuntimeService 各方法的协作关系:

CRI 接口调用流程:Pod 创建 CRI 接口调用流程:kubelet 创建 Pod kubelet RuntimeService 容器运行时 1. RunPodSandbox 2. CreateContainer 3. StartContainer PodSandboxID ContainerID 启动成功 说明: 1. kubelet 先调用 RunPodSandbox 创建 Pod 沙箱(网络命名空间 + cgroup 父目录)。 2. 沙箱创建成功后,依次调用 CreateContainer 和 StartContainer 启动业务容器。 3. 所有调用均通过 gRPC 双向流,支持超时和重试机制。

2.4 CRI 与 OCI 的关系

CRI 和 OCI(Open Container Initiative)是两个不同层次的标准化接口,经常被混淆。CRI 是 kubelet 与容器运行时之间的接口,而 OCI 是 容器运行时与底层操作系统之间的接口。一个典型的 CRI 实现(如 containerd)内部会调用 OCI 兼容的 runtime(如 runc)来真正创建容器。

维度 CRI(Container Runtime Interface) OCI(Open Container Initiative)
定位 Kubernetes 与容器运行时的抽象层 容器运行时与操作系统的标准化规范
协议 gRPC(protobuf 定义) OCI Runtime Spec(JSON 配置 + 命令行调用)
管理对象 PodSandbox、Container、Image 容器进程(namespace、cgroup、rootfs)
典型实现 containerd、CRI-O、Kata Containers runc、crun、youki
调用方 kubelet 容器运行时(如 containerd 的 shim 进程)
常见误区: 不要将 CRI 与 OCI 混为一谈。在节点扩容场景中,CRI 接口的调用频率和超时配置直接影响 Pod 调度速度,而 OCI 层的配置(如 cgroup 驱动、runc 版本)则影响容器启动后的资源隔离效果。两者需要分别优化。

2.5 CRI 接口的版本演进与兼容性

CRI 接口从 v1alpha1 演进到 v1(稳定版),经历了多次迭代。当前主流版本为 v1(Kubernetes 1.20+ 默认启用)。CRI 的版本兼容性遵循以下规则:

  • kubelet 与运行时必须使用相同 Major 版本:例如 kubelet 使用 v1,运行时也必须实现 v1 接口。
  • Minor 版本向后兼容:v1.2 的运行时可以处理 v1.0 的请求,但反之不保证。
  • 版本协商机制:kubelet 启动时会通过 Version RPC 查询运行时支持的版本,选择双方都兼容的最高版本。
扩容实践建议: 在节点扩容前,务必确认新节点上安装的容器运行时版本与集群 kubelet 版本匹配。建议使用 crictl version 命令验证 CRI 版本一致性,避免因版本不兼容导致 Pod 创建失败。