Cloud Native 30 min read

Understanding Docker Architecture, CRI, and Containerd: A Comprehensive Guide

This article provides a detailed overview of Docker’s evolution, the role of containerd, runc, and CRI in modern container runtimes, explains how Docker delegates container lifecycle management to containerd‑shim, and offers step‑by‑step instructions for installing, configuring, and using containerd with its CLI tools on Linux.

DevOps Cloud Academy
DevOps Cloud Academy
DevOps Cloud Academy
Understanding Docker Architecture, CRI, and Containerd: A Comprehensive Guide

Before diving into Containerd, it is useful to review Docker’s history because many components such as libcontainer , runc , containerd , CRI , and OCI are frequently mentioned but not always understood.

Docker

Since Docker 1.11, container execution is no longer driven solely by the Docker daemon; instead Docker integrates containerd , runc and other components. The daemon still follows a client‑server (CS) model, handling image management and client interaction, while containerd manages the container lifecycle on each node and exposes a gRPC API to Docker.

When a container is created, Docker asks containerd to create it. containerd spawns a containerd-shim process that becomes the container’s parent, isolating the container from the daemon so that a daemon crash does not kill all containers. The shim also handles stdin, fd management, and state collection.

Namespace and cgroup configuration, as well as root‑fs mounting, follow the OCI (Open Container Initiative) specifications. runc is the reference OCI implementation (originally libcontainer renamed to runc ). Other OCI‑compatible runtimes such as Kata and gVisor also exist.

In practice, the actual container start sequence is: containerd-shim invokes runc , which creates the container and then exits, while the shim remains as the container’s parent process to report status back to containerd and reap any remaining processes.

CRI (Container Runtime Interface)

Kubernetes originally hard‑coded Docker’s API, but to support multiple runtimes it introduced the CRI standard. A CRI shim adapts any runtime to the CRI API; Docker’s built‑in shim is called dockershim . The kubelet communicates with the shim via gRPC, using two services: ImageService (pull, list, delete images) and RuntimeService (manage pods, exec, attach, etc.).

When Docker is used, kubelet talks directly to dockershim , which translates CRI calls into Docker daemon requests. As Docker’s market share declined, the community began deprecating dockershim (removed by default in Kubernetes 1.20‑1.24) and encourages the use of dedicated CRI runtimes such as containerd or CRI‑O .

Containerd

Containerd originated inside Docker Engine but was later split into an independent CNCF project. It is an industrial‑grade container runtime focused on simplicity, robustness, and portability. Its responsibilities include lifecycle management, image pull/push, storage handling, invoking runc , and network interface management.

The architecture follows a client‑server model: a daemon exposes a Unix‑domain‑socket gRPC API, and a CLI client ( ctr ) consumes it. Plugins implement functionality such as content storage, snapshotting, garbage collection, and the CRI integration.

Installation

On a Linux Mint 20.2 host, install libseccomp2 and then download the pre‑built cri-containerd-cni-1.5.5-linux-amd64.tar.gz archive. Extract it to the root filesystem, add /usr/local/bin and /usr/local/sbin to $PATH , and generate a default configuration with containerd config default > /etc/containerd/config.toml . A systemd unit file ( /etc/systemd/system/containerd.service ) is provided; important options are Delegate=yes (allow containerd to manage its own cgroups) and KillMode=process (prevent container loss on daemon restart).

Configuration

The generated config.toml contains sections for cgroup , debug , grpc , metrics , and a large plugins block. The CRI plugin ( plugins."io.containerd.grpc.v1.cri" ) holds sub‑sections for CNI, containerd runtime settings, and registry mirrors. For example, to add a Docker Hub mirror you would edit the registry.mirrors table.

Two paths are defined: root = "/var/lib/containerd" for persistent data (snapshots, metadata, plugins) and state = "/run/containerd" for runtime state (sockets, pids, mounts).

Using the CLI ( ctr )

Run ctr to view commands; it is an unsupported debugging client. Common operations include:

Image management : ctr image pull docker.io/library/nginx:alpine , ctr image ls , ctr image tag , ctr image rm , ctr image export , ctr image import , ctr image mount / unmount .

Container management : ctr container create , ctr container ls , ctr container info , ctr container rm .

Task (runtime) control : ctr task start -d , ctr task ls , ctr task exec --exec-id 0 -t , ctr task pause , ctr task resume , ctr task kill , ctr task rm , ctr task metrics , ctr task ps .

Namespaces : ctr ns ls , ctr ns create test , ctr ns rm test . Docker uses the moby namespace, while Kubernetes defaults to k8s.io .

These commands demonstrate how to pull images, create containers, start them as tasks, inspect runtime metrics, and clean up resources, providing a hands‑on introduction to containerd’s workflow.

Summary

Containerd abstracts the low‑level container lifecycle from Docker and Kubernetes, offering a lightweight, plugin‑driven runtime that complies with OCI and CRI standards. By installing containerd, configuring its systemd service, and using the ctr CLI, developers can manage images, containers, and tasks directly, gaining deeper insight into the mechanics behind modern cloud‑native platforms.

cloud nativeDockerKubernetescontainerdCRIrunccontainer runtime
DevOps Cloud Academy
Written by

DevOps Cloud Academy

Exploring industry DevOps practices and technical expertise.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.