containerd 元数据与文件不一致导致镜像拉取失败
问题背景
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路径变更后,旧路径的数据不会自动迁移,需手动处理或重新拉取所有镜像。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)