4. CRI 接口核心数据结构:PodSandbox、Container、Image 等核心 protobuf 消息定义、字段含义与生命周期映射
CRI(Container Runtime Interface)是 kubelet 与容器运行时之间的核心 gRPC 协议。其底层数据模型通过 Protocol Buffers(protobuf)定义,涵盖 PodSandbox、Container、Image 三大核心对象。理解这些消息的字段含义及其与 Kubernetes 资源生命周期的映射关系,是进行 CRI 适配与运行时开发的基础。
4.1 核心 protobuf 消息概览
CRI 的 protobuf 定义位于 k8s.io/cri-api/pkg/apis/runtime/v1 包中。以下表格列出了最核心的五个消息类型及其用途:
| 消息名称 | 用途 | 对应 Kubernetes 资源 |
|---|---|---|
| PodSandbox | 描述 Pod 级别的隔离环境(如 Linux Namespace、Cgroup 父路径) | Pod(逻辑沙箱) |
| PodSandboxConfig | 创建 PodSandbox 时传入的配置参数 | PodSpec 中的部分字段 |
| Container | 描述运行中的容器实例 | Pod 内的 Container |
| ContainerConfig | 创建容器时传入的配置参数 | Container 的 Image、Command、Env 等 |
| Image | 描述容器镜像的元数据 | 镜像仓库中的镜像 |
4.2 PodSandbox 消息定义与生命周期映射
PodSandbox 是 CRI 中最重要的抽象之一,它代表一个“沙箱环境”,通常对应一个 Linux 网络命名空间和一组共享资源。其核心字段如下:
message PodSandbox {
// 沙箱的唯一标识符,由运行时生成
string id = 1;
// 沙箱的元数据,包含 Pod 名称、UID、Namespace 等
PodSandboxMetadata metadata = 2;
// 沙箱当前状态
PodSandboxState state = 3;
// 沙箱创建后的标签(Labels)
map<string, string> labels = 4;
// 沙箱的注解(Annotations)
map<string, string> annotations = 5;
// 运行时特定的沙箱状态信息(如 Linux Namespace 路径)
PodSandboxStatus runtime_status = 6;
}
enum PodSandboxState {
SANDBOX_READY = 0; // 沙箱已就绪,可以创建容器
SANDBOX_NOTREADY = 1; // 沙箱未就绪(如正在初始化或已停止)
}
关键映射:PodSandbox 的
state 字段直接映射到 Kubernetes Pod 的 PodStatus.Phase。当 PodSandbox 处于 SANDBOX_READY 时,Pod 才能进入 Running 阶段;若沙箱失败,Pod 将进入 Failed 或 Pending。
4.3 Container 消息定义与生命周期映射
Container 消息描述运行在 PodSandbox 内的单个容器实例。其字段设计紧密对应 Docker/containerd 的容器状态机:
message Container {
// 容器唯一标识符
string id = 1;
// 容器所属的 PodSandbox ID
string pod_sandbox_id = 2;
// 容器元数据(名称、尝试次数等)
ContainerMetadata metadata = 3;
// 容器镜像的引用(如 "nginx:1.21")
ImageSpec image = 4;
// 容器当前状态
ContainerState state = 5;
// 容器创建时间(Unix 时间戳)
int64 created_at = 6;
// 容器标签与注解
map<string, string> labels = 7;
map<string, string> annotations = 8;
}
enum ContainerState {
CONTAINER_CREATED = 0; // 容器已创建但未启动
CONTAINER_RUNNING = 1; // 容器正在运行
CONTAINER_EXITED = 2; // 容器已退出(正常或异常)
CONTAINER_UNKNOWN = 3; // 状态未知(如运行时重启后丢失状态)
}
生命周期映射:Container 的
state 与 Kubernetes 的 ContainerStatus 中的 State 字段一一对应。例如,CONTAINER_RUNNING 对应 Running 状态,CONTAINER_EXITED 对应 Terminated 状态。适配时需确保状态转换的原子性。
4.4 Image 消息定义与生命周期映射
Image 消息描述容器镜像的元数据,主要用于镜像拉取、列表查询和状态检查:
message Image {
// 镜像的唯一标识(通常是镜像 ID 的 SHA256 摘要)
string id = 1;
// 镜像的仓库标签列表(如 ["nginx:1.21", "nginx:latest"])
repeated string repo_tags = 2;
// 镜像的摘要列表(如 ["nginx@sha256:abc123"])
repeated string repo_digests = 3;
// 镜像大小(字节)
uint64 size = 4;
// 镜像的配置信息(如 Entrypoint、Cmd、Env 等)
ImageSpec spec = 5;
// 镜像的创建时间(Unix 时间戳)
int64 created_at = 6;
}
适配注意:Image 的
id 字段在 CRI 中必须是全局唯一的,通常使用镜像的 manifest digest。如果运行时返回的镜像 ID 不唯一(如 Docker 的短 ID),会导致 kubelet 的镜像缓存冲突。建议在适配层将短 ID 扩展为完整 SHA256。
4.5 生命周期映射关系图
下图展示了 PodSandbox、Container、Image 三者与 Kubernetes Pod 生命周期的映射关系:
4.6 关键字段对比表
以下表格对比了 PodSandbox、Container、Image 三个消息中容易混淆的字段:
| 字段 | PodSandbox | Container | Image |
|---|---|---|---|
| id | 沙箱 ID(运行时生成) | 容器 ID(运行时生成) | 镜像 ID(SHA256 摘要) |
| metadata | PodSandboxMetadata(name、uid、namespace、attempt) | ContainerMetadata(name、attempt) | 无(镜像无元数据) |
| state | READY / NOTREADY | CREATED / RUNNING / EXITED / UNKNOWN | 无(镜像无状态) |
| labels/annotations | 继承自 Pod 的 Labels/Annotations | 继承自 Container 的 Labels/Annotations | 无(镜像元数据通过 repo_tags 表达) |
| runtime_status | 包含 Linux Namespace 路径等运行时信息 | 包含 ExitCode、Reason 等退出信息 | 无 |
4.7 生命周期映射的适配实战要点
- PodSandbox 创建顺序:必须先创建 PodSandbox 并等待其进入
SANDBOX_READY状态,才能在该沙箱内创建容器。如果沙箱创建失败,所有容器创建请求都应被拒绝。 - Container 状态转换:容器从
CONTAINER_CREATED到CONTAINER_RUNNING的转换必须是幂等的。如果 kubelet 在状态查询时发现容器仍处于CREATED状态,可能会触发重试或超时。 - Image 缓存一致性:kubelet 会缓存
Image列表。如果运行时在镜像拉取后返回的id与缓存不一致,会导致镜像被重复拉取。建议在适配层使用repo_digests作为缓存键。 - PodSandbox 清理:当 Pod 被删除时,kubelet 会先停止所有容器,然后调用
RemovePodSandbox。运行时必须确保沙箱内的所有资源(网络命名空间、挂载点等)被彻底清理。
实战案例:在适配 containerd 时,PodSandbox 的
id 对应 containerd 的 SandboxID,而 Container 的 id 对应 ContainerID。两者通过 pod_sandbox_id 字段关联。如果 containerd 的沙箱被意外删除,所有关联容器的状态查询应返回 CONTAINER_UNKNOWN,而不是 CONTAINER_EXITED,以避免 kubelet 误判。
4.8 消息字段与 gRPC 接口的对应关系
CRI 的每个核心消息都对应一组 gRPC 接口。以下表格列出了最常用的接口及其输入/输出消息:
| gRPC 接口 | 请求消息 | 响应消息 | 核心字段 |
|---|---|---|---|
RunPodSandbox |
RunPodSandboxRequest | RunPodSandboxResponse | config(PodSandboxConfig)→ pod_sandbox_id |
CreateContainer |
CreateContainerRequest | CreateContainerResponse | pod_sandbox_id, config(ContainerConfig)→ container_id |
ListImages |
ListImagesRequest | ListImagesResponse | filter → images(repeated Image) |
ContainerStatus |
ContainerStatusRequest | ContainerStatusResponse | container_id → status(ContainerStatus) |
PodSandboxStatus |
PodSandboxStatusRequest | PodSandboxStatusResponse | pod_sandbox_id → status(PodSandboxStatus) |