containerd containerd

containerd's CLI Tools: ctr, nerdctl, and crictl

Three command-line tools, three different jobs — which one to reach for and when.

10 min Beginner

Once Docker isn’t the thing running containers on a node, docker ps and docker logs stop working there. Three tools fill that gap, built by two different communities for two different purposes. Reaching for the wrong one is the most common source of confusion when troubleshooting a node directly.

The three tools at a glance

ToolBuilt byTalks toPurposeDocker-like?
ctrcontainerd projectcontainerd directlyDebugging containerd itselfNo, minimal and low-level
nerdctlcontainerd projectcontainerd directlyGeneral container managementYes, closely mirrors docker
crictlKubernetes projectany CRI-compatible runtimeDebugging the runtime from Kubernetes’ perspectivePartially, Pod-aware

ctr: bundled, minimal, debugging-only

ctr ships with containerd itself, which makes it always available wherever containerd is, but it’s explicitly a debugging tool with a deliberately small feature set, not something meant for day-to-day container management:

ctr images pull docker.io/library/redis:7
ctr run docker.io/library/redis:7 my-redis
ctr containers list

The containerd project itself recommends against using ctr for anything beyond debugging and inspecting containerd’s own state. If you find yourself trying to script deployments with it, that’s a sign to reach for nerdctl instead.

nerdctl: the Docker-like daily driver

nerdctl is a separate CLI, also from the containerd project, designed to look and behave like the docker CLI closely enough that most docker commands work by substituting the binary name:

nerdctl run -d -p 8080:80 nginx:1.25
nerdctl ps
nerdctl logs my-container
nerdctl build -t myapp:latest .

Beyond parity with familiar Docker workflows, nerdctl exposes containerd-native capabilities Docker doesn’t have: encrypted images, lazy pulling, P2P image distribution, image signing and verification, and direct interaction with Kubernetes namespaces in containerd’s own data model. For general container work on a machine with containerd installed but not Docker, nerdctl is the tool to reach for.

crictl: from Kubernetes’ point of view

crictl is maintained by the Kubernetes project itself, not containerd’s, and it talks CRI, the same interface the kubelet uses, rather than containerd’s native API. That means it works identically across containerd, CRI-O, or any other CRI-compliant runtime, and it understands Kubernetes concepts ctr and nerdctl don’t, most importantly Pods, not just containers:

crictl images
crictl ps
crictl pods
crictl exec -it CONTAINER_ID sh
crictl logs CONTAINER_ID

Notice crictl pods: neither ctr nor nerdctl, nor Docker before them, had a native concept of a Pod, a group of containers sharing network and storage. That’s Kubernetes-specific, and crictl is the tool built to reason about it directly.

crictl is, like ctr, meant for inspection and debugging rather than creating workloads. If you use it to start a container that Kubernetes doesn’t know about, the kubelet has no record of it and will delete it as soon as it notices, since as far as Kubernetes is concerned, an unexpected container on a node is drift to be corrected, not a workload to preserve.

Which endpoint crictl talks to

Since crictl works across runtimes, it needs to know which one to connect to. Without configuration, it tries a fixed list of default sockets in order (historically dockershim’s, then containerd’s, then CRI-O’s, then others). On a modern node this ambiguity rarely matters because only one runtime is installed, but on a node with more than one, or when troubleshooting a socket path issue, set it explicitly:

crictl --runtime-endpoint unix:///run/containerd/containerd.sock ps
# or
export CONTAINER_RUNTIME_ENDPOINT=unix:///run/containerd/containerd.sock

Choosing between them

  • Inspecting or troubleshooting what Kubernetes itself sees, matching what kubectl describe pod is reporting against what’s actually running on the node, use crictl.
  • General container work on a node or in local development, running something quickly, building an image, checking logs, use nerdctl.
  • Debugging containerd’s own internal state, something specific to containerd rather than to the runtime-agnostic CRI view, reach for ctr, and expect to need containerd’s own documentation open alongside it.

Popular Guides