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 各方法的协作关系:
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 启动时会通过
VersionRPC 查询运行时支持的版本,选择双方都兼容的最高版本。
扩容实践建议: 在节点扩容前,务必确认新节点上安装的容器运行时版本与集群 kubelet 版本匹配。建议使用
crictl version 命令验证 CRI 版本一致性,避免因版本不兼容导致 Pod 创建失败。