Welcome to day 3 of our series on containerd internals! This post will cover ctr, a command-line tool for containerd.

What is ctr?

containerd is a long-lived daemon for managing the lifecycle of containers and their associated resources (images, filesystems, processes, etc). containerd itself isn’t really interactive; the only way to make it do things is via one of the API surfaces it exposes. Most containerd installations have two API surfaces: containerd’s primary first-party gRPC API and the Kubernetes Container Runtime Interface (CRI) API. An API client is how you can interact with containerd. Higher-level tools like Docker, Kubernetes, or nerdctl are containerd clients. containerd also provides a Go client library for interacting with the gRPC API.

ctr is a command-line client of containerd that we built as a development tool and a demonstrator for how to integrate with the containerd API through our Go client library.

What isn’t ctr?

As a development tool and demonstrator, ctr isn’t the recommended way to use containerd in a production setting. While ctr is what we use for our own development (and thus, should work), we’ve explicitly excluded it from our stability guarantees.

Screenshot of the table of stability guarantees, with the ctr row outlined by a red box

This means that, while we don’t usually intentionally break ctr’s behavior, we don’t consider it to be a high-priority to fix changes like that or to address bugs in it. The exception would be when a change (exposed through ctr) is breaking for other reasons; for example, if a Go client library change introduces a break in ctr it likely also introduces a break in other importers of the client library. In a case like that, we’d fix the client library and ctr would get fixed as a result.

When should I use ctr?

ctr is our development tool and a demonstration of using the client library. If you are developing new features in containerd, or if you are integrating with containerd, ctr is a great thing to use! Debugging and finding out about deprecations are other good use-cases.

Development tool

When we first implement new features in containerd, ctr is usually how we test them! Lots of the subcommands and tools are a direct mapping to either the API or to a higher-level action that needs to be accomplished.

For example, the content and snapshots subcommands expose lower-level details of how containerd manages the actual content of container filesystems, while the images subcommand demonstrates how the internal Images service ties together content and snapshots into a standard workflow for both container image interchange (push, pull) and using images with containers.

Some subcommands, like shim, go beyond the normal containerd gRPC API and client library too. This subcommand bypasses the containerd daemon and can interact directly with the shims that supervise processes within a container.

Demonstrator

The source code of ctr is designed to be read and can serve as an example for your own integrations with containerd. You can look at what it takes to run a container, or push an image, or subscribe to events.

Debugging

When something goes wrong, ctr can also be a helpful debugging tool. Because it offers the same set of tools we use for developing features, it also can expose a lot of useful information about the runtime state of containerd. The tasks, snapshots, events, and shim subcommands can be really helpful for investigating “what does containerd think is going on” and “what is the state of associated components”, while the events and pprof subcommands can dig deeper into the sequence of events that occurs as well as the runtime state (goroutines, heap, CPU profiles, etc) of the daemon.

Deprecations

ctr is also our preferred tool for helping you find out about deprecation warnings. ctr deprecations list will expose any usage of deprecated features that are expected to be removed in future versions of containerd. This can be really helpful in preparing for an upgrade to 2.0.

What should I use instead of ctr in production?

Production use of containerd should be through a fully-supported client (such as Kubernetes, crictl, or nerdctl) or by directly integrating with the gRPC API.