DevOps · CNCF daily

containerd: The Industry-Standard Container Runtime

CNCF Graduated. A daemon that pulls images, manages storage and runs containers through runc, and the default runtime Kubernetes talks to through the Container Runtime Interface.

8 min read

CNCF Graduated

  • containerd
  • runc
  • Kubernetes
  • CRI
  • nerdctl
CNCF project page

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:

  1. 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.
  2. 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
    version = 3
    [plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc.options]
      SystemdCgroup = true
    Plugin names and the config version differ between releases, so edit the file generated by your installed version and run containerd config migrate when upgrading.
  3. 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"]
  4. Start and verify the service, then use crictl for Kubernetes-level checks and ctr or nerdctl for 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
  5. 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
  6. 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. crictl talks CRI, ctr is a low-level debugging client, and nerdctl offers a Docker-compatible workflow. Using the wrong one, or the wrong namespace (k8s.io for 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

Spotted something wrong or out of date?Suggest a correction. I review every suggestion before changing the page.