容器沙盒镜像引用格式错误导致 Pod 无法启动
概述
在 Kubernetes 集群中,每个 Pod 的启动都依赖于一个称为沙盒(sandbox)的基础镜像(通常是 pause 镜像)来初始化其网络命名空间和共享进程空间。容器运行时接口(CRI)插件(如 containerd 的 CRI)负责解析和拉取此镜像。本页记录了 containerd 在特定版本(2.3.x)中的一个关键缺陷:当沙盒镜像的配置使用了 tag@digest 格式(如 pause:3.10.1@sha256:...)时,会导致 RunPodSandbox RPC 调用失败,进而使得整个节点无法调度任何 Pod。这是一个严重的可靠性问题,直接违反了节点的可用性 SLO。
核心概念
CRI 与沙盒镜像
- CRI (Container Runtime Interface): Kubernetes 定义的容器运行时与 kubelet 之间的标准接口。containerd 通过内置的 CRI 插件实现此接口。
- 沙盒镜像 (Sandbox Image): Pod 沙盒的核心镜像,由 CRI 插件配置中的
pinned_images.sandbox(或遗留配置sandbox_image)字段指定。kubelet 在调用RunPodSandbox时会引用此镜像。
镜像引用格式
容器镜像引用可以有多种格式:
registry/image:tag(最常用)registry/image@digest(基于内容哈希的不可变引用)registry/image:tag@digest(同时包含标签和摘要,旨在提供唯一性和人类可读性)
问题本质
此缺陷暴露了 containerd CRI 插件在镜像解析逻辑上的一个回归。在 2.3.x 版本中,插件在执行 RunPodSandbox 时,无法正确处理 tag@digest 格式的引用。尽管容器运行时在接收到请求后能够成功拉取该镜像,但其内部查找逻辑(可能在后续步骤中)将镜像存储为其规范名称(即仅 @digest 形式),导致使用包含标签的原始引用进行查找时报告“未找到”。
实践
复现步骤
- 环境准备: 获取 containerd 2.3.x 版本和
crictl工具。 - 配置 containerd: 创建一个配置文件,在
pinned_images.sandbox字段中使用tag@digest格式指定镜像。[plugins."io.containerd.cri.v1.images".pinned_images] sandbox = "registry.k8s.io/pause:3.10.1@sha256:278fb9dbcca9518083ad1e11276933a2e96f23de604a3a08cc3c80002767d24c" - 启动测试 containerd: 使用该配置文件启动一个独立的 containerd 实例。
- 尝试启动 Pod: 使用
crictl runp命令尝试创建一个 Pod 沙盒。 - 观察失败: 命令会立即失败,返回
NotFound错误,提示无法找到沙盒镜像。 - 验证镜像存在: 使用
ctr images ls检查 containerd 的镜像存储,会发现镜像确实已被拉取并存储,但名称格式为registry.k8s.io/pause@sha256:278fb9...(仅有摘要)。
解决方案与规避措施
- 升级版本: 关注并升级到已修复此问题的 containerd 版本(参考关联的 PR #13513)。
- 修改配置格式 (推荐): 避免在沙盒镜像配置中使用
tag@digest格式。仅使用单一标识符:- 仅使用标签:
pause:3.10.1 - 仅使用摘要:
pause@sha256:278fb9dbcca9518083ad1e11276933a2e96f23de604a3a08cc3c80002767d24c使用仅摘要的格式通常是最佳实践,因为它确保了不可变性和可重复性。
- 仅使用标签:
SRE 要点
对可靠性的影响
这是一个 P0 级别的可靠性缺陷。它会导致受影响节点完全无法工作(NotReady 状态),无法调度任何新的 Pod,从而直接降低集群容量并可能导致工作负载中断。此类问题会严重影响节点的 SLO,特别是“Pod 启动成功率”和“节点可用性”指标。
事件响应与故障排查
当集群中出现多个节点 Pod 无法启动,且错误信息涉及沙盒镜像未找到时,SRE 应立即:
- 检查节点 containerd 的版本。
- 审查容器运行时配置中的
pinned_images.sandbox或sandbox_image字段,确认是否使用了tag@digest格式。 - 通过
crictl pods或kubectl describe pod <pod-name>查看 Pod 事件,确认失败原因为“failed to get sandbox image”。
最佳实践与反模式
- 最佳实践:
- 在关键基础设施配置(如沙盒镜像)中使用摘要(digest)引用,以确保一致性和防止供应链攻击。
- 保持容器运行时(containerd、CRI-O)及其配置与 Kubernetes 主版本的兼容性矩阵。
- 对节点初始化配置和关键组件配置进行版本管理和变更记录。
- 反模式:
- 在生产环境中使用未充分测试的或包含已知缺陷的容器运行时版本。
- 使用复杂且可能被不同组件以不同方式解析的复合引用格式(如
tag@digest)配置关键镜像。
相关指标与监控
- SLI: 节点上 Pod 调度成功率、节点状态为
Ready的时间比例。 - SLO: 集群应确保节点可用性(例如 99.9%),此缺陷会直接导致违反该 SLO。
- 监控建议: 监控 kubelet 和 containerd 日志中与“sandbox image”、“not found”相关的错误模式,并设置告警。同时监控节点状态变化。
关联页面: container-runtime-interface kubernetes-pod-scheduling node-health-monitoring incident-response-runbook