containerd is a high-level container runtime, aka container manager. To put it simply, it's a daemon that manages the complete container lifecycle on a single host: creates, starts, stops containers, pulls and stores images, configures mounts, networking, etc.
containerd is designed to be easily embeddable into larger systems. Docker uses containerd under the hood to run containers. Kubernetes can use containerd via CRI to manage containers on a single node. But smaller projects also can benefit from the ease of integrating with containerd - for instance, faasd uses containerd (we need more d's!) to spin up a full-fledged Function-as-a-Service solution on a standalone server.
However, using containerd programmatically is not the only option. It also can be used from the command line via one of the available clients. The resulting container UX may not be as comprehensive and user-friendly as the one provided by the
docker client, but it still can be useful, for instance, for debugging or learning purposes.
How to use containerd with ctr
ctr is a command-line client shipped as part of the containerd project. If you have containerd running on a machine, chances are the
ctr binary is also there.
ctr interface is [obviously] incompatible with Docker CLI and, at first sight, may look not so user-friendly. Apparently, its primary audience is containerd developers testing the daemon. However, since it's the closest thing to the actual containerd API, it can serve as a great exploration means - by examining the available commands, you can get a rough idea of what containerd can and cannot do.
Working with container images using ctr
When pulling images, the fully-qualified reference seems to be required, so you cannot omit the registry or the tag part:
$ ctr images pull docker.io/library/nginx:1.21 $ ctr images pull docker.io/kennethreitz/httpbin:latest $ ctr images pull docker.io/kennethreitz/httpbin:latest $ ctr images pull quay.io/quay/redis:latest
To list local images, one can use:
$ ctr images ls
Surprisingly, containerd doesn't provide out-of-the-box image building support. However, containerd itself is often used to build images by higher-level tools.
Check out my investigation post on what actually happens when you build an image to learn more about image building internals.
Instead of building images with
ctr, you can import existing images built with
docker build or other OCI-compatible software:
$ docker build -t my-app . $ docker save -o my-app.tar my-app $ ctr images import my-app.tar
ctr, you can also mount images for future exploration:
$ mkdir /tmp/httpbin $ ctr images mount docker.io/kennethreitz/httpbin:latest /tmp/httpbin $ ls -l /tmp/httpbin/ total 80 drwxr-xr-x 2 root root 4096 Oct 18 2018 bin drwxr-xr-x 2 root root 4096 Apr 24 2018 boot drwxr-xr-x 4 root root 4096 Oct 18 2018 dev drwxr-xr-x 1 root root 4096 Oct 24 2018 etc drwxr-xr-x 2 root root 4096 Apr 24 2018 home drwxr-xr-x 3 root root 4096 Oct 24 2018 httpbin ... $ ctr images unmount /tmp/httpbin
To remove images using
$ ctr images remove docker.io/library/nginx:1.21
Working with containers using ctr
Having a local image, you can run a container with
ctr run <image-ref> <container-id>. For instance:
$ ctr run --rm -t docker.io/library/debian:latest cont1
Notice that unlike user-friendly
docker run generating a unique container ID for you, with
ctr, you must supply the unique container ID yourself. The
ctr run command also supports only some of the familiar
docker run flags:
--rm, etc. But no port publishing or automatic container restart with
--restart=always out of the box.
Similarly to images, you can list existing containers with:
$ ctr containers ls
Interesting that the
ctr run command is actually a shortcut for
ctr container create +
ctr task start:
$ ctr container create -t docker.io/library/nginx:latest nginx_1 $ ctr container ls CONTAINER IMAGE RUNTIME nginx_1 docker.io/library/nginx:latest io.containerd.runc.v2 $ ctr task ls TASK PID STATUS # Empty! $ ctr task start -d nginx_1 # -d for --detach $ ctr task list TASK PID STATUS nginx_1 10074 RUNNING
I like this separation of
task subcommands because it reflects the often forgotten nature of OCI containers. Despite the common belief, containers aren't processes - containers are isolated and restricted execution environments for processes.
ctr task attach, you can reconnect to the stdio streams of an existing task running inside of a container:
$ ctr task attach nginx_1 2021/09/12 15:42:20 [notice] 1#1: using the "epoll" event method 2021/09/12 15:42:20 [notice] 1#1: nginx/1.21.3 2021/09/12 15:42:20 [notice] 1#1: built by gcc 8.3.0 (Debian 8.3.0-6) 2021/09/12 15:42:20 [notice] 1#1: OS: Linux 4.19.0-17-amd64 2021/09/12 15:42:20 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1024:1024 2021/09/12 15:42:20 [notice] 1#1: start worker processes 2021/09/12 15:42:20 [notice] 1#1: start worker process 31 ...
Much like with
docker, you can execute a task in an existing container:
$ ctr task exec -t --exec-id bash_1 nginx_1 bash # From inside the container: $ root@host:/# curl 127.0.0.1:80 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> ...
Before removing a container, all its tasks must be stopped:
$ ctr task kill -9 nginx_1
Alternatively, you can remove running tasks using the
$ ctr task rm -f nginx_1
Finally, to remove the container, run:
$ ctr container rm nginx_1
How to use containerd with nerdctl
nerdctl is a relatively new command-line client for containerd. Unlike
nerdctl aims to be user-friendly and Docker-compatible. To some extent,
nerdctl + containerd can seamlessly replace
docker + dockerd. However, this does not seem to be the goal of the project:
The goal of
nerdctlis to facilitate experimenting the cutting-edge features of containerd that are not present in Docker. Such features include, but not limited to, lazy-pulling (stargz) and encryption of images (ocicrypt). These features are expected to be eventually available in Docker as well, however, it is likely to take several months, or perhaps years, as Docker is currently designed to use only a small portion of the containerd subsystems. Refactoring Docker to use the entire containerd would be possible, but not straightforward. So we [NTT] decided to create a new CLI that fully uses containerd, but we do not intend to complete with Docker. We have been contributing to Docker/Moby as well as containerd, and will continue to do so.
From the basic usage standpoint, comparing to
- Image building with
- Container networking management
- Docker Compose with
nerdctl compose up
And the coolest part about it is that
nerdctl tries to provide the identical to
podman) command-line UX. So, if you are familiar with
podman) CLI, you are already familiar with
How to use containerd with crictl
Click here to learn more about Kubernetes Container Runtime Interface (CRI).
Kubernetes Container Runtime Interface (CRI) was introduced to make Kubernetes container runtime-agnostic. The Kubernetes node agent, kubelet, implementing the CRI client API, can use any container runtime implementing the CRI server API to manage containers and pods on its node.
Since version 1.1, containerd comes with a built-in CRI plugin. Hence, containerd is a CRI-compatible container runtime. Therefore, it can be used with
crictl was created to inspect and debug container runtimes and applications on a Kubernetes node. It supports the following operations:
attach: Attach to a running container create: Create a new container exec: Run a command in a running container version: Display runtime version information images, image, img: List images inspect: Display the status of one or more containers inspecti: Return the status of one or more images imagefsinfo: Return image filesystem info inspectp: Display the status of one or more pods logs: Fetch the logs of a container port-forward: Forward local port to a pod ps: List containers pull: Pull an image from a registry run: Run a new container inside a sandbox runp: Run a new pod rm: Remove one or more containers rmi: Remove one or more images rmp: Remove one or more pods pods: List pods start: Start one or more created containers info: Display information of the container runtime stop: Stop one or more running containers stopp: Stop one or more running pods update: Update one or more running containers config: Get and set crictl client configuration options stats: List container(s) resource usage statistics
The interesting part here is that with
crictl + containerd bundle, one can learn how pods are actually implemented. But this topic deserves its own blog post 😉
For more information on how to use
crictl with containerd, check out this document (part of the containerd project).
More Containers Posts From This Blog
- Journey From Containerization to Orchestration and Beyond
- Containers aren't Linux processes
- Not every container has an operating system inside
- You don't need an image to run a container
- You need containers to build images
- conman - [the] container manager: inception
- Implementing Container Runtime Shim: runc
- Implementing Container Runtime Shim: First Code
- Implementing Container Runtime Shim: Interactive Containers