crictl image list 与 ctr images ls 显示镜像不一致,因二者操作不同命名空间:crictl 面向 cri(默认 k8s.io),ctr 默认操作 default 命名空间;需用 ctr -n k8s.io images ls 查看 crictl 镜像。

crictl image list 显示的镜像为什么 ctr images ls 看不到
因为 crictl 和 ctr 默认操作的是不同容器运行时的镜像存储:前者面向 CRI 接口(如 containerd 的 CRI 插件),后者直连 containerd 的原生服务(/run/containerd/containerd.sock)。两者镜像命名空间、拉取路径、甚至存储目录都可能隔离。
常见错误现象:crictl pull nginx:alpine 成功,但 ctr images ls 无输出;或 ctr i pull 拉的镜像在 crictl images 里不显示。
-
crictl使用的 socket 是/run/containerd/containerd.sock(默认)但走的是/v1/runtime_serviceCRI 路径,镜像会打上cri标签并存入独立元数据视图 -
ctr默认连同一 socket,但操作的是原生images命名空间,不识别 CRI 添加的别名和 pause 镜像映射 - 如果用
nerdctl(尤其带--namespace k8s.io),它会主动适配 CRI 行为,默认 namespace 就是k8s.io,所以结果更接近crictl - 验证方式:运行
ctr -n k8s.io images ls,通常就能看到crictl列出的镜像
nerdctl pull 后 crictl images 不显示的三个原因
nerdctl 默认行为比 ctr 更贴近 CRI,但仍可能因配置偏差导致镜像“不可见”。
使用场景:在 Kubernetes 节点上用 nerdctl pull 替代 crictl pull,期望快速拉镜像并被 kubelet 发现。
- 没指定
--namespace k8s.io:nerdctl 默认用defaultnamespace,而 kubelet 和 crictl 都只查k8s.io—— 加上该参数再拉一次即可 - 用了
-q(quiet)但没加--insecure-registry:私有 registry 若无 HTTPS,nerdctl 默认拒绝,crictl 却可能已配置了insecure-registries(见/etc/containerd/config.toml) - 镜像名含端口但没加协议前缀:比如
nerdctl pull harbor.example.com:8080/nginx会失败或存错位置;正确写法是nerdctl pull http://harbor.example.com:8080/nginx(或配 config.toml)
ctr images rm 删除不了 crictl 管理的 pause 镜像
Kubernetes 节点上常见的 gcr.io/google_containers/pause 或 k8s.gcr.io/pause 镜像,crictl 会自动管理其生命周期,但 ctr 直删常失败或无效。
错误现象:ctr images rm k8s.gcr.io/pause:3.6 返回 “not found”,或删除成功但 crictl images 仍显示,且 kubelet 下次启动又自动拉回。
- pause 镜像是由 kubelet 通过 CRI 动态请求的,不是普通镜像 —— 它绑定到
RuntimeClass和 containerd 的untrusted或default_runtime配置 - 真正控制它的配置项在
/etc/containerd/config.toml的[plugins."io.containerd.grpc.v1.cri".sandbox_image]字段,改这里才影响下次拉取 - 强行用
ctr -n k8s.io images rm删除后,只要 kubelet 重启或创建新 Pod,就会触发重拉 —— 不建议手动删,应统一通过修改 CRI 配置 + 重启 containerd 来切换
crictl rmi 和 nerdctl rmi 的实际删除范围差异
crictl rmi 看似简单,其实只触发 CRI 层的“标记删除”,不一定立刻释放磁盘;nerdctl rmi(尤其带 --force)则更激进,可能直清底层 blob。
性能影响:频繁 crictl rmi 后磁盘不释放,容易误判为“删不掉”;而 nerdctl rmi --force 可能破坏其他 namespace 共享的 layer。
-
crictl rmi实际调用的是 CRI 的ImageService.RemoveImage(),containerd 内部只是移除引用,blob 仍保留直到 GC 触发(默认 5 分钟间隔) -
nerdctl rmi默认行为等价于ctr images rm,直接删 manifest 和引用;加--force会连带删未被引用的 layer,风险更高 - 安全做法:删完
crictl rmi后,手动触发 GC:crictl gc(它会调用 CRI 的 garbage collect 接口) - 注意:
nerdctl system prune会清整个 namespace 的 dangling 镜像和 layer,慎用,尤其在多租户环境
最易被忽略的一点:CRI 镜像的标签解析依赖 image_pull_policy 和 sandbox_image 配置,而不是单纯看名字。同一个 digest,出现在 k8s.io 和 default namespace 下,对 kubelet 来说是两个世界。










