containerd is a container runtime that runs as a daemon on Linux and Windows and manages the complete container lifecycle on its host: transferring and storing images, creating and supervising containers, managing low-level storage and attaching networks. It is deliberately a small, stable layer: it does not build images or provide a developer-facing workflow, which leaves that to tools above it, while it hands the actual process isolation to an OCI runtime such as runc. It addresses the need for a portable, well-defined runtime underneath Docker, Kubernetes and other platforms, instead of each reimplementing container execution. containerd began at Docker in 2014 as a lower-level runtime manager for the Docker engine, was accepted into the CNCF in March 2017, and was announced as graduated on February 28, 2019, the fifth project to do so after Kubernetes, Prometheus, Envoy and CoreDNS. Release 2.4 followed on September 16, 2026.
CNCF daily · Sprint 1, day 5 · Container Runtime
At a glance
| Category | Container Runtime |
| CNCF status | Graduated. Accepted March 2017; graduation announced February 28, 2019 |
| Written in | Go |
| License | Apache 2.0 |
| Interfaces | gRPC API, the Kubernetes Container Runtime Interface (CRI) plugin and Go client library |
| Standards | OCI Image Spec and OCI Runtime Spec, with runc as the default runtime |
| Extensibility | Plugins, snapshotters, shim runtimes and the Node Resource Interface (NRI) |
| Platforms | Linux and Windows (the Windows runtime and snapshot plugins are not yet marked stable) |
| Release status | 2.4 (September 2026, active); 2.3 (April 2026, LTS to April 2028); 2.2 active until November 2026 |
Architecture
flowchart TB
KUBELET[kubelet] -->|CRI over gRPC| CRI
CLI[nerdctl, ctr, crictl, Docker Engine] -->|containerd API| CORE
subgraph CD[containerd daemon]
CRI[CRI plugin<br/>pods and sandboxes] --> CORE[Core services<br/>content, images, containers, tasks]
CORE --> CS[Content store<br/>image layers by digest]
CORE --> SN[Snapshotters<br/>overlayfs and others]
CORE --> NRI[NRI plugins<br/>runtime customisation]
end
CORE -->|task API| SHIM[Shim v2<br/>one per pod or container]
SHIM --> RUNC[OCI runtime<br/>runc, gVisor, Kata]
RUNC --> CTR[Container processes<br/>namespaces and cgroups]
CORE -->|pull and push| REG[Container registry<br/>Harbor, ECR, GHCR]
| Component | Responsibility |
|---|---|
| CRI plugin | Implements the Kubernetes Container Runtime Interface, turning pod and container requests from the kubelet into containerd operations. |
| Content store | A content-addressable store for image layers and manifests, keyed by digest. |
| Snapshotters | Prepare container filesystems from image layers. overlayfs is the default, and alternatives support lazy pulling and other storage backends. |
| Core services | Images, containers, tasks, leases and namespaces, exposed over a gRPC API. |
| Shim v2 | A small process that stays alive beside the container, so the daemon can restart without killing running workloads. |
| OCI runtime | Creates the container with Linux namespaces and cgroups. runc is the default, and gVisor or Kata Containers plug in for stronger isolation. |
| NRI | The Node Resource Interface, which lets plugins adjust container configuration at creation time. |
Design principle. containerd keeps a narrow scope: store content, prepare filesystems, and start and watch processes. Everything else is pluggable, from the OCI runtime to the snapshotter and the CRI front end, and the shim design means the daemon is not on the critical path of a running container. This is why Kubernetes distributions and Docker could both build on it without carrying runtime code of their own.
Production reference design
On most Kubernetes clusters containerd is already the runtime. Managed offerings and distributions such as K3s install and configure it for you, so the work is tuning, upgrading and observing it. A common self-managed pattern on Ubuntu nodes for kubeadm clusters:
- Install containerd from your distribution, the Docker apt repository (
containerd.io) or the official release tarball, and pick a supported release line from the release table, with an LTS release such as 2.3 for long-lived fleets. Check that it matches your Kubernetes version in the compatibility table. - Generate and edit the configuration. Start from the default and enable the systemd cgroup driver, which must match the kubelet:
sudo mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml
Plugin names and the config version differ between releases, so edit the file generated by your installed version and runversion = 3 [plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc.options] SystemdCgroup = truecontainerd config migratewhen upgrading. - Point registry settings at a certs directory and configure mirrors or private registries per host, rather than in the main file:
# /etc/containerd/certs.d/docker.io/hosts.toml server = "https://registry-1.docker.io" [host."https://mirror.example.com"] capabilities = ["pull", "resolve"] - Start and verify the service, then use
crictlfor Kubernetes-level checks andctrornerdctlfor runtime-level ones:sudo systemctl enable --now containerd sudo crictl --runtime-endpoint unix:///run/containerd/containerd.sock ps sudo ctr -n k8s.io images ls - Add sandboxed runtimes when workloads need isolation. Register a handler such as gVisor or Kata in the containerd configuration, then expose it to Kubernetes:
apiVersion: node.k8s.io/v1 kind: RuntimeClass metadata: { name: gvisor } handler: runsc - Roll upgrades node by node. Drain, upgrade containerd, restart and uncordon, since a restart does not stop running containers but does need the kubelet to reconnect. Monitor image pull latency, disk use under the containerd root, and the daemon’s logs.
Typical production uses include the runtime for Kubernetes nodes, the engine inside Docker, local development clusters such as kind, edge distributions such as K3s, and build or CI hosts that run containers through nerdctl.
Operational considerations
- Match the cgroup driver. The kubelet and containerd must use the same cgroup driver, normally systemd. A mismatch causes pods to flap or fail to start.
- Watch the support window. Non-LTS releases are supported for about eight months, and one release a year is designated LTS. Plan upgrades against the published schedule, since 1.7 reached the end of its listed support on September 30, 2026.
- Plan for disk and image garbage collection. Layers and snapshots accumulate on busy nodes. Size the root directory, set kubelet image garbage-collection thresholds, and alert on disk pressure.
- Secure the socket and the supply chain. Anyone with access to the containerd socket controls the node, so restrict it. Pull from trusted registries, pin digests and verify signatures where your pipeline supports it.
- Know the tooling split.
crictltalks CRI,ctris a low-level debugging client, andnerdctloffers a Docker-compatible workflow. Using the wrong one, or the wrong namespace (k8s.iofor Kubernetes), hides images and containers.
Adoption
- The CNCF graduation announcement named IBM, whose IBM Cloud Kubernetes Service moved to containerd as its container engine, and Alibaba Cloud, which uses it in its Kubernetes and Serverless Kubernetes services. Docker standardised on it inside Docker Engine.
- At graduation the project reported 14 committers, 166 contributors and more than 4,400 commits, with contributing companies including Alibaba, Cruise Automation, Docker, Facebook, Google, Huawei, IBM, Microsoft, NTT and Tesla.
- containerd is the runtime embedded in K3s, so it also runs in many edge and small-cluster deployments.
Alternatives
| Solution | Model | Best suited to |
|---|---|---|
| CRI-O | A runtime built specifically for Kubernetes | OpenShift and clusters that want a Kubernetes-only runtime |
| Docker Engine with cri-dockerd | Docker daemon bridged to the CRI by an adapter | Legacy setups that still depend on Docker on the node |
| Podman | Daemonless container engine | Developer machines and rootless workflows rather than cluster nodes |
| runc, crun or youki directly | Low-level OCI runtimes | Embedding a runtime where no daemon is needed |
| Firecracker or Kata with containerd | Micro-VM isolation | Multi-tenant platforms that need stronger isolation, used together with containerd |
Strengths and limitations
| Strengths | Limitations |
|---|---|
| Stable, small and widely deployed in Kubernetes | Not a developer tool: no image building or friendly CLI of its own |
| Clear standards: OCI, CRI and a documented gRPC API | Configuration format and plugin names change between major lines |
| Pluggable runtimes and snapshotters for isolation and lazy pulling | Low-level debugging tools such as ctr and crictl have a learning curve |
| Shim design keeps containers running through daemon restarts | Windows runtime and snapshot support is not yet marked stable |
| Published release and LTS policy with Kubernetes compatibility tables | Short support windows for non-LTS releases require regular upgrades |
Recommendation
Adopt containerd as the container runtime for Kubernetes nodes, as it is the default on most distributions and managed services. Choose an LTS release for long-lived fleets, keep it within the published support window and aligned with the Kubernetes compatibility table, and standardise on the systemd cgroup driver. Add a sandboxed runtime through RuntimeClass where workloads need stronger isolation, and consider CRI-O only when your platform, such as OpenShift, already standardises on it.
References: CNCF project page · CNCF: containerd graduation announcement · containerd website · containerd releases and Kubernetes compatibility · containerd on GitHub