问题背景

containerd默认位置/var/lib/containerd 磁盘小(40G)
正在运行的ack,频繁告警,决定迁移一下到另外的磁盘分区/data/containerd,由于又有pod在该节点,nodepool不宽裕,所以在线rsync过去了,发现此问题,比较蛋疼,让qoder帮我处理了,记录一下。

修改 /etc/containerd/config.toml 后,containerd 的 content store 和 overlayfs snapshotter 元数据(bolt DB)与实际文件出现不一致,导致 K8s Pod 持续 ImagePullBackOff / CreateContainerError

错误信息:

blob sha256:dee4e82... expected at /data/containerd/io.containerd.content.v1.content/blobs/sha256/dee4e82...: blob not found
failed to create containerd container: failed to stat parent: stat /data/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/9695/fs: no such file or directory

根因分析

现象 原因
ctr content ls 能看到 manifest 记录 bolt DB 有元数据
blob 文件不存在于磁盘 文件与元数据不一致
镜像 pull 成功但 unpack 失败 overlayfs snapshot 引用了已丢失的父快照 ID
K8s Secret 认证正常 kubelet 通过 CRI 传递凭据,与 containerd config 无关

修复步骤

第一步:确认问题

# 查看 Pod 报错事件
kubectl describe pod <pod-name> -n <namespace> | tail -30
​
# 确认 blob 文件是否真的丢失
ls /data/containerd/io.containerd.content.v1.content/blobs/sha256/<digest>
​
# 确认 containerd 元数据里有这个记录
ctr -n k8s.io content ls | grep <digest>

第二步:停止 kubelet(避免干扰清理过程)

systemctl stop kubelet

第三步:删除损坏的镜像记录

# 删除 tag 和 digest 两条记录
ctr -n k8s.io images rm \
  "registry.cn-beijing.aliyuncs.com/yd-base/skywalking-oap-server:9.1.0" \
  "registry.cn-beijing.aliyuncs.com/yd-base/skywalking-oap-server@sha256:dee4e82284524f841f73f5bd620cea76d5364111fac9724caa8e24c0691c23a2"

第四步:删除所有相关 content blobs

# manifest blob
ctr -n k8s.io content rm sha256:dee4e82284524f841f73f5bd620cea76d5364111fac9724caa8e24c0691c23a2
​
# image config
ctr -n k8s.io content rm sha256:b21800a57a2b56ee84031cbdea65834fd15eb8731f9c9bf2deaa0aeae12d0aa6
​
# image layers
ctr -n k8s.io content rm \
  sha256:405f018f9d1d0f351c196b841a7c7f226fb8ea448acd6339a9ed8741600275a2 \
  sha256:9c045aca8dd90fbfb1afd1343ec6ce2e08ab62f20e8943d3e313dd745e22ee37 \
  sha256:106421360c5cd72b7fd60bc22e213e0b164520c4f38b59358ff4badc098623d5 \
  sha256:0ba85ff342cb69c26bcd1a2828d05d82f4622ef9fcc3ff0651092f12d986a5b7 \
  sha256:8358633f2f848b308f461b0e9f5f04545f67779df1e2cf929f3a785b727af90f \
  sha256:4c900b4961da18489060587fa3eb5bae0925c62db0fb426e17ac0423ea219c31 \
  sha256:be35fec8792ec72d9f32ff4fd092fd6de3b18b10f598af0d62d9d0bd103e72bc \
  sha256:84c006ec435ef6c5a610161b50b1e80a4573c8356a2052437af262321a22ed32 \
  sha256:9655d4b74d758afeec8365a8d1357ff23e82314259dc2672f227b2e8bd8957d1 \
  sha256:d35699fdfe3b00ca0539b0a8afdfcf42e4250ada6fd5765068338df4b0ba6742 \
  sha256:6092d0c325501310003d0f8e202901a45a9883cc2d8acbb92b2ca5768476fe2a

第五步:清理孤立的 sha256 格式 snapshot 记录

这些是 overlayfs snapshotter bolt DB 里有记录但磁盘文件不存在的快照。

ctr -n k8s.io snapshots ls | grep "^sha256:" | awk '{print $1}' | while read snap; do
  ctr -n k8s.io snapshots rm "$snap" 2>/dev/null && echo "removed: $snap"
done

第六步:启动 kubelet,让 K8s 重新拉取镜像

systemctl start kubelet
​
# 观察 Pod 状态
watch kubectl get pods -n infra | grep oap

kubelet 会通过 CRI 接口携带 imagePullSecret(awr)中的凭据自动完成拉取和解包, 无需在 config.toml 里配置 registry 认证。

第七步:验证

# Pod 应变为 1/1 Running
kubectl get pods -n infra | grep oap
​
# 查看启动日志确认服务正常
kubectl logs -n infra <oap-pod-name> --tail=10

通用排查方法(适用于其他镜像)

# 1. 查看 Pod 事件,确认是 blob not found 还是 snapshot not found
kubectl describe pod <pod> -n <ns> | grep -E "Warning|Failed|Error"
​
# 2. 确认镜像的 manifest digest
kubectl get pod <pod> -n <ns> -o jsonpath='{.status.containerStatuses[*].image}'
​
# 3. 删除对应镜像(ctr 会自动关联删除 GC 可回收的内容)
ctr -n k8s.io images rm <image:tag>
​
# 4. 手动触发 containerd GC
ctr -n k8s.io content gc
​
# 5. 如果 GC 后仍有孤立 snapshot,手动删除
ctr -n k8s.io snapshots rm <snapshot-key>
​
# 6. 重建 Pod
kubectl delete pod <pod> -n <ns>

注意事项

  • ctr pull 不会使用 K8s Secret,只能测试 registry 连通性(不带认证)。 私有仓库用 ctr pull --user user:pass 或直接让 kubelet 处理。

  • config_path 配置的目录若不存在,不影响 kubelet 通过 CRI 传递的认证, 但会影响直接用 ctr pull 拉取需要认证的镜像。

  • containerd root 路径变更后,旧路径的数据不会自动迁移,需手动处理或重新拉取所有镜像。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐