Linux crictl 的 image 管理与 ctr / nerdctl 的命令对比

1次阅读

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

Linux crictl 的 image 管理与 ctr / nerdctl 的命令对比

crictl image list 显示的镜像为什么 ctr images ls 看不到

因为 crictlctr 默认操作的是不同容器运行时的镜像存储:前者面向 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_service CRI 路径,镜像会打上 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 默认用 default namespace,而 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/pausek8s.gcr.io/pause 镜像,crictl 会自动管理其生命周期,但 ctr 直删常失败或无效。

错误现象:ctr images rm k8s.gcr.io/pause:3.6 返回 “not found”,或删除成功但 crictl images 仍显示,且 kubelet 下次启动又自动拉回。

  • pause 镜像是由 kubelet 通过 CRI 动态请求的,不是普通镜像 —— 它绑定到 RuntimeClass 和 containerd 的 untrusteddefault_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_policysandbox_image 配置,而不是单纯看名字。同一个 digest,出现在 k8s.iodefault namespace 下,对 kubelet 来说是两个世界。

text=ZqhQzanResources