3. CRI 接口详解:kubelet 与运行时交互的 gRPC 协议、ImageService 与 RuntimeService
容器运行时接口(CRI,Container Runtime Interface)是 kubelet 与容器运行时之间的核心通信协议。它基于 gRPC 定义,将容器生命周期管理抽象为两个独立的服务:RuntimeService(运行时服务)和 ImageService(镜像服务)。理解 CRI 的接口设计,是掌握容器运行时治理与集群生命周期运维的基础。
3.1 CRI 架构与 gRPC 协议基础
CRI 采用客户端-服务器(C/S)架构,kubelet 作为 gRPC 客户端,容器运行时(如 containerd、CRI-O)作为 gRPC 服务端。两者通过 Unix Socket(默认路径 /var/run/crio/crio.sock 或 /var/run/containerd/containerd.sock)建立通信。
关键协议特征:
- 传输层:基于 HTTP/2 的 gRPC 协议,支持双向流、多路复用。
- 序列化:使用 Protocol Buffers(protobuf)定义消息结构,确保跨语言兼容性。
- 认证与安全:通过 Unix Socket 文件权限控制访问,不依赖 TLS 证书。
- 超时控制:kubelet 为每个 gRPC 调用设置超时时间(默认 2 分钟),防止运行时挂死。
3.2 RuntimeService:容器生命周期管理
RuntimeService 负责管理 Pod 沙箱(Sandbox)和容器的完整生命周期。它定义了 kubelet 与运行时之间关于容器运行状态的核心操作。
| RPC 方法 | 方向 | 功能描述 | 关键参数 |
|---|---|---|---|
| RunPodSandbox | kubelet → 运行时 | 创建 Pod 沙箱(隔离环境,如网络命名空间) | PodSandboxConfig(元数据、DNS、端口映射) |
| StopPodSandbox | kubelet → 运行时 | 停止 Pod 沙箱,回收网络资源 | PodSandboxId |
| RemovePodSandbox | kubelet → 运行时 | 删除 Pod 沙箱,清理存储 | PodSandboxId |
| CreateContainer | kubelet → 运行时 | 在指定沙箱内创建容器(不启动) | ContainerConfig(镜像、命令、挂载、资源限制) |
| StartContainer | kubelet → 运行时 | 启动已创建的容器进程 | ContainerId |
| StopContainer | kubelet → 运行时 | 停止容器(支持优雅关闭超时) | ContainerId, GracePeriodSeconds |
| RemoveContainer | kubelet → 运行时 | 删除容器及其存储层 | ContainerId |
| ContainerStatus | kubelet → 运行时 | 查询容器当前状态(Running/Exited/Unknown) | ContainerId |
| ListContainers | kubelet → 运行时 | 列出所有容器(支持按沙箱 ID 过滤) | ContainerFilter |
运维要点:当集群节点出现“容器一直 Terminating”或“Pod 删除卡住”时,通常是 RuntimeService 的
StopContainer 或 RemovePodSandbox 调用超时。此时应检查运行时日志(如 journalctl -u containerd)确认底层容器引擎是否响应。
3.3 ImageService:镜像拉取与管理
ImageService 专注于容器镜像的拉取、查询和删除操作。它不参与容器运行,但直接影响 Pod 启动速度与磁盘空间治理。
| RPC 方法 | 方向 | 功能描述 | 关键参数 |
|---|---|---|---|
| PullImage | kubelet → 运行时 | 拉取镜像到本地存储(支持认证) | ImageSpec(镜像名+标签)、AuthConfig |
| ListImages | kubelet → 运行时 | 列出本地已存储的镜像列表 | ImageFilter |
| ImageStatus | kubelet → 运行时 | 查询单个镜像的详细信息(大小、层数) | ImageSpec |
| RemoveImage | kubelet → 运行时 | 删除本地镜像,释放磁盘空间 | ImageSpec |
| ImageFsInfo | kubelet → 运行时 | 获取镜像文件系统使用情况(容量、已用) | 无 |
安全合规提示:ImageService 的
PullImage 调用是镜像供应链攻击的主要入口。务必在 kubelet 配置中启用 --image-pull-progress-deadline 和镜像签名验证(如 Notary / Cosign),防止拉取被篡改的恶意镜像。
3.4 RuntimeService 与 ImageService 的协作关系
在 Pod 启动过程中,两个服务按严格顺序协作:
- 镜像准备阶段:kubelet 调用 ImageService.PullImage 确保镜像已缓存。
- 沙箱创建阶段:kubelet 调用 RuntimeService.RunPodSandbox 创建隔离环境。
- 容器创建阶段:kubelet 调用 RuntimeService.CreateContainer(引用已拉取的镜像)。
- 容器启动阶段:kubelet 调用 RuntimeService.StartContainer 运行进程。
- 状态监控阶段:kubelet 定期调用 RuntimeService.ContainerStatus 和 ImageService.ImageFsInfo 进行健康检查与 GC。
3.5 CRI 接口版本与兼容性治理
CRI 接口采用语义化版本(SemVer),kubelet 与运行时之间通过版本协商确保兼容性。版本不匹配是集群生命周期运维中常见的故障来源。
| 版本字段 | 说明 | 示例值 |
|---|---|---|
| RuntimeName | 运行时标识符 | containerd / cri-o |
| RuntimeVersion | 运行时自身版本 | 1.6.20 |
| ApiVersion | CRI API 版本(kubelet 与运行时协商) | v1 / v1alpha2 |
版本协商流程:
- kubelet 启动时调用
Version()RPC 获取运行时支持的 API 版本列表。 - kubelet 选择自身支持的最高版本进行通信。
- 若版本不兼容(如 kubelet v1.24 要求 CRI v1,但运行时仅支持 v1alpha2),kubelet 将报错并拒绝启动节点。
3.6 生产环境 CRI 接口监控与故障排查
在集群生命周期运维中,CRI 接口的稳定性直接影响节点健康。以下是关键监控指标与排查方法:
- gRPC 调用延迟:监控
RunPodSandbox和PullImage的 P99 延迟,超过 10 秒应告警。 - 调用失败率:统计
CreateContainer和StartContainer的失败次数,失败率超过 1% 需介入。 - Socket 连接状态:检查
/var/run/*.sock文件是否存在且权限为 660。 - 常见错误码:
NotFound:容器或镜像不存在(通常由并发删除导致)。AlreadyExists:重复创建沙箱或容器(kubelet 重试逻辑异常)。DeadlineExceeded:操作超时(底层引擎卡死或磁盘 I/O 瓶颈)。
快速诊断命令:使用
crictl 工具直接调用 CRI 接口,绕过 kubelet 进行测试:# 查看运行时版本
crictl version
# 列出所有 Pod 沙箱
crictl pods
# 列出所有容器(含已退出)
crictl ps -a
# 拉取镜像测试
crictl pull nginx:latest