containerd 的命令行工具:ctr、nerdctl 与 crictl
三个命令行工具,三种不同的用途 —— 何时该用哪一个。
当 Docker 不再是节点上运行容器的组件时,docker ps 和 docker logs 在那里就不再可用了。有三个工具填补了这个空缺,它们由两个不同的社区为两种不同的目的而构建。在节点上直接排查问题时,用错工具是最常见的困惑来源。
三个工具一览
| 工具 | 开发方 | 通信对象 | 用途 | 类似 Docker? |
|---|---|---|---|---|
ctr | containerd 项目 | 直接与 containerd 通信 | 调试 containerd 本身 | 否,精简且偏底层 |
nerdctl | containerd 项目 | 直接与 containerd 通信 | 通用容器管理 | 是,与 docker 高度相似 |
crictl | Kubernetes 项目 | 任何兼容 CRI 的运行时 | 从 Kubernetes 的视角调试运行时 | 部分相似,感知 Pod |
ctr:自带、精简、仅用于调试
ctr 随 containerd 一起发布,因此只要有 containerd 的地方它就一定可用,但它明确是一个调试工具,功能集刻意保持很小,并不适合日常的容器管理:
ctr images pull docker.io/library/redis:7
ctr run docker.io/library/redis:7 my-redis
ctr containers list
containerd 项目本身建议,除调试和检查 containerd 自身状态之外,不要将 ctr 用于其他用途。如果你发现自己想用它编写部署脚本,这就是该改用 nerdctl 的信号。
nerdctl:类似 Docker 的日常主力
nerdctl 是另一个命令行工具,同样来自 containerd 项目,它的设计目标是在外观和行为上足够像 docker CLI,以至于大多数 docker 命令只需替换二进制名称就能运行:
nerdctl run -d -p 8080:80 nginx:1.25
nerdctl ps
nerdctl logs my-container
nerdctl build -t myapp:latest .
除了与熟悉的 Docker 工作流保持一致之外,nerdctl 还提供了 Docker 所没有的 containerd 原生能力:加密镜像、lazy pulling、P2P 镜像分发、镜像签名与验证,以及直接与 containerd 自身数据模型中的 Kubernetes 命名空间交互。对于安装了 containerd 但没有 Docker 的机器上的一般容器工作,nerdctl 是该用的工具。
crictl:从 Kubernetes 的视角
crictl 由 Kubernetes 项目自己维护,而不是 containerd,它使用 CRI(也就是 kubelet 所用的同一接口)通信,而不是 containerd 的原生 API。这意味着它在 containerd、CRI-O 或任何其他兼容 CRI 的运行时上表现一致,并且它理解 ctr 和 nerdctl 所不理解的 Kubernetes 概念,最重要的是 Pod,而不仅仅是容器:
crictl images
crictl ps
crictl pods
crictl exec -it CONTAINER_ID sh
crictl logs CONTAINER_ID
注意 crictl pods:无论是 ctr、nerdctl,还是更早的 Docker,都没有原生的 Pod 概念,即一组共享网络和存储的容器。这是 Kubernetes 特有的,而 crictl 正是为直接处理它而构建的工具。
和 ctr 一样,crictl 用于检查和调试,而不是创建工作负载。如果你用它启动了一个 Kubernetes 不知道的容器,kubelet 对此没有任何记录,一旦发现就会将其删除,因为在 Kubernetes 看来,节点上出现意料之外的容器是需要被纠正的漂移,而不是需要保留的工作负载。
crictl 连接哪个端点
由于 crictl 可以跨运行时工作,它需要知道要连接哪一个。如果不做配置,它会按顺序尝试一组固定的默认套接字(历史上依次是 dockershim 的、containerd 的、CRI-O 的,以及其他)。在现代节点上这种歧义很少造成影响,因为只安装了一个运行时,但在装有多个运行时的节点上,或在排查套接字路径问题时,请显式设置:
crictl --runtime-endpoint unix:///run/containerd/containerd.sock ps
# or
export CONTAINER_RUNTIME_ENDPOINT=unix:///run/containerd/containerd.sock
如何在它们之间选择
- 检查或排查 Kubernetes 本身所看到的情况,即将
kubectl describe pod报告的内容与节点上实际运行的内容对照,使用crictl。 - 在节点上或本地开发中进行一般容器工作,例如快速运行某个东西、构建镜像、查看日志,使用
nerdctl。 - 调试 containerd 自身的内部状态,也就是某些特定于 containerd、而非与运行时无关的 CRI 视图的问题,使用
ctr,并做好需要同时打开 containerd 自己文档的准备。