containerd: The Daemon Docker Cut Loose and the Whole Industry Adopted

Docker needed plumbing between its engine and OCI's runc; Michael Crosby built the daemon, Kubernetes made it the default, and the industry inherited the maintenance.

Sources

There is one daemon that almost every Kubernetes node on earth runs, that Docker itself now builds on, that Amazon, Google, and Microsoft all ship as the default container runtime — and it started as a Docker employee's side project to control a different tool. containerd's story is the story of how the container ecosystem's "boring plumbing" became its most load-bearing layer, survived the company that founded it losing the orchestrator war, absorbed Kubernetes' garbage-collected runtime interface, and in 2026 found out what happens when a decade-old daemon carries too many features: a security crisis that ended with the project deleting its own checkpointing feature and patching five release branches at once.

The Origin: Plumbing Docker Didn't Want to Be

A daemon to control runC (2015)

containerd begins, as half the container ecosystem does, with Michael Crosby. The git archaeology is unusually clean: the repository was created on , and the deepest commit page reads:

# Deepest page of containerd/containerd commit history:
$ gh api "repos/containerd/containerd/commits?until=2015-12-08T00:00:00Z&per_page=100"

DATE        SHA         AUTHOR          MESSAGE
2015-11-05  15a96783ca  Michael Crosby  Initial commit
2015-11-05  05683fb0ee  Michael Crosby  Fix build errors
2015-11-06  2af0f297fe  Michael Crosby  Add basic counters
2015-11-06  5f5f4904e0  Michael Crosby  Making containers run and delete
2015-11-06  1005dfb224  Michael Crosby  Fix panic on nil container

# One author, eight days of evening-mode commits, "Making containers
# run and delete" — a runtime manager being sketched in public.

The context: the Open Container Initiative had standardized the image format and the low-level runtime — Docker's donated runc — in mid-2015. What was missing was the layer above: supervising container lifecycles, managing image pulls, handling snapshots and filesystems. Docker announced containerd on in a blog post titled "Containerd: a daemon to control runC": "we're releasing a new daemon to control runC called: containerd. It's built for performance and density, and will eventually be built into Docker Engine." The explicit framing was plumbing — infrastructure that Docker committed to releasing as open source "to help the community," with a design scoped deliberately narrow: execution and supervision, not networking, not orchestration, not build. That narrowness, annoying at the time, is why the daemon survived.

Docker Engine 1.11 shipped in April 2016 as the first engine built on runC and containerd — Docker's own runtime stack, refactored into a separate daemon it didn't fully control. The CNCF accepted containerd as an incubating project on , and in February 2019 it became the foundation's fifth graduated project — after Kubernetes, Prometheus, Envoy, and CoreDNS, per the graduation press release. The press release also carries the origin line the project still uses: "Born at Docker in 2014, containerd started out as a lower-layer runtime manager for the Docker engine" — the 2014 date refers to the internal prototype that predated the public 2015 repository.

The Timeline: From Docker Plumbing to the Runtime Under Everything

Crisis Points & Architectural Pivots

1. The dockershim windfall (2020–2022) — becoming the default by being there

containerd's dominance is not a marketing story; it's a deadline story. Kubernetes 1.20 (December 2020) announced that dockershim — the kubelet-side shim that translated CRI calls into Docker Engine calls — would be removed. When 1.24 shipped in May 2022 and the shim went away, every cluster still on Docker Engine needed a CRI runtime, and the dockershim removal FAQ said moving to containerd "should be a relatively easy swap and will have strictly better performance and less overhead." The three managed clouds had already made the choice for their customers: AKS defaulted Linux node pools to containerd at Kubernetes 1.19, GKE followed at 1.21, EKS at 1.24. A kubelet upgrade did the migration silently. That is how a runtime becomes a monoculture: not by winning arguments, but by being the graduated, neutral option sitting in the path of a forced migration.

The irony compounds. Docker had lost the orchestration war, but its donated plumbing now runs under the thing that beat it — and Docker eventually came back to it: modern Docker Engine builds on containerd, and Docker's own daemon documentation describes the containerd image store as the default for current Docker Engine. The company that invented the daemon for its own engine now runs its engine on the daemon the community matured.

2. The v2.0 modernization (2024) — eight years of quiet refactor

containerd 2.0 (November 2024) was the rare major that was mostly subtraction and relocation: the API split into its own Go module, the non-sandboxed CRI implementation removed, CRI v1alpha2 dropped, the aufs snapshotter deleted, NRI (Node Resource Interface) enabled by default, CDI (the Container Device Interface, for GPU exposure) enabled by default, and the migration documented. Nothing about the core daemon changed — the bet was that the value lives in the plugin surface staying stable while the edges get rebuilt. The release also introduced static-binary tarballs for distributions that don't run glibc, which sounds like packaging trivia until you notice the 2026 advisory cadence: every security patch now has to land as both a glibc-linked and a static build, across five branches.

3. The checkpoint/restore purge (2026) — the feature that became a liability

The most consequential crisis in containerd's history didn't come from an outside attacker — it came from a feature the ecosystem asked for. Forensic container checkpointing (KEP-2008) added a kubelet API to snapshot a running container's full state — memory, processes, network connections — via CRIU, aimed at incident responders who need to capture a compromised container without stopping it. Amazon built an unprivileged checkpoint agent for EKS around it; CRIU's Kubernetes page tracked the feature from alpha in 1.25 to beta in 1.30.

Then the feature's security bill arrived, all at once. On June 18, 2026, the project published five advisories in one coordinated batch — four of them touching checkpoint/restore: CDI annotation smuggling during restore (CVE-2026-53492, critical), checkpoint import image-tag poisoning (CVE-2026-50195, critical), host file read via symlinks in the restore path (CVE-2026-53489, high), alongside the image-LABEL-to-host-root execution bug (CVE-2026-53488, critical) and an unbounded group-parsing DoS (CVE-2026-47262, medium). On September 1, CVE-2026-95837 (critical) landed the deepest cut: CRIU restore brings back process credentials, capabilities, no_new_privs, and seccomp state from the checkpoint data, not from the destination's CRI ContainerConfig — a restored container can come back as root with full capabilities while the status reporting shows the requested, restrictive configuration. The CRIU project's own image-security documentation had warned that checkpoint images are executable state, not data.

The project's answer is the most senior-engineer move in this whole story: stop patching, remove the feature. Restore-via-CreateContainer was deprecated in 2.3, disabled by default in the September patches (behind enable_experimental_restore_via_create), and deleted outright in 2.4.0 via PR #13871. The pod-level checkpoint/restore redesign (KEP-5823, PR #13822) is still open. Forensic checkpointing export — the incident-response use case — survives; what died is restoring untrusted checkpoint data through the container-creation path. The lesson generalizes: a feature that serializes a process's privilege state into a portable artifact and then restores it under a different security context is not a feature, it's a permanent CVE factory.

4. The five-branch patch reality (2026) — the cost of being infrastructure

CVE-2026-53493 (September 2026) is a study in what containerd's success costs its maintainers. A crafted OCI image index with deeply nested or heavily fanned-out descriptor graphs drives unbounded CPU and memory consumption during PullImage — a registry-adjacent DoS with, per the advisory, "no known workarounds." The fix — bounded traversal, deduplicated descriptors — shipped on September 24 as five coordinated releases: 2.4.1, 2.3.6, 2.2.9, 2.0.13, and 1.7.36. Five branches, because five branches were alive: 2.4 (active), 2.3 (LTS until April 2028), 2.2 (active until November 2026), 2.0 (extended support to March 2027, for Kubernetes 1.33 via GKE), and 1.7 (end-of-life September 30 — patched one final time, 25 days before retirement). Notice what's missing: 2.1, which reached end-of-life on July 3, 2026, is unpatched — anyone still running it carries a DoS that has no workaround. The project's release policy page now defines this reality formally: minors every four months synchronized with Kubernetes, one LTS per year supported at least two years, regular branches supported eight months. Being the runtime under everything means the surface area is every supported branch times every Kubernetes version times every distribution — and the static-binary matrix multiplies it again.

Community Engine & Corporate Influence: Who Actually Built It

The contributor table is the story of the runtime layer's neutralization. Per the GitHub contributors API (October 2026):

CONTRIBUTIONS  LOGIN           WHO
2143           dmcgowan        Derek McGowan — Docker; top all-time contributor
1831           crosbymichael   Michael Crosby — founder, chief maintainer until 2025
1591           estesp          Phil Estes — AWS
1523           Random-Liu      Lantao Liu — Google; kubelet/CRI integration era
1199           mxpv            Maksym Pavlenko — Docker, then Netflix
1043           AkihiroSuda     Akihiro Suda — NTT
 780           fuweid          Fu Wei — Microsoft
 760           thaJeztah       Sebastiaan van Stijn — Docker
 514           stevvooe        Stephen Day — early core
 451           mikebrow        Mike Brown — IBM
 424           samuelkarp      Samuel Karp — Google; removed the restore feature
 418           mlaventure      Kenfe-Mickaël Laventure
 313           kzys            Kazuyoshi Kato — Baseten
 114           dcantah         Danny Canter

Read the affiliations and the neutralization is visible: the current ten committers — the project's actual maintainers, per maintainers.yaml — span Docker, AWS, Google, Microsoft, NTT, IBM, Netflix, and Nvidia. No single employer holds a majority; the CNCF graduation in 2019 was the formal recognition of what the contributor graph already showed. The corporate handoff is generational: the founder-era maintainers moved to emeritus one by one — Lantao Liu, Dawn Chen, Yu-Ju Hong in October 2023, Stephen Day in November 2023, Kevin Parsons in January 2025, and finally Michael Crosby himself in June 2025, who also stepped down as runc's chief maintainer (PR #4324, merged June 2024, archived the role rather than re-filling it). He now builds apple/containerization, Swift containers for macOS — the same design instincts, a new substrate.

The 2026 security response also showed who actually staffs the runtime layer now: the September critical (CVE-2026-95837) was fixed by Google's Samuel Karp, the same maintainer who owns the 2.0 branch's GKE-driven extended support; the June critical (CVE-2026-53488) was independently discovered and disclosed by Anthropic Research "in collaboration with Claude," the GKE Security Team "using Gemini," and an independent researcher — AI-assisted vulnerability discovery, arriving at the runtime layer. And the ecosystem's periphery keeps expanding containerd's job description: firecracker-containerd (AWS, since 2018) runs containers as Firecracker microVMs, Kubernetes 1.37's runtime requirements now assume containerd-grade CRI behavior, and Windows support is a first-class release track. The commercial gravity is diffuse by design: AWS, Google, and Microsoft each embed containerd in their managed Kubernetes and each employ maintainers — which is exactly what a graduated, neutral runtime is supposed to look like, and exactly why no one can fork it into a product.

Current Trajectory: The Verdict

Eleven days before this tale was written, containerd shipped v2.4.1 — a patch release that fixed a no-workaround image-pull DoS across five branches, plugged a task-leak in failed container starts, and hardened id-mapping label filtering. That is the project's 2026 cadence in miniature: security-first, multi-branch, deliberately boring. The official documentation and CNCF project page describe a mature graduated project; the release policy page describes an institution — LTS designations, synchronized cadence, formal end-of-life tables.

The open threads are visible if you read the last three months of activity as a set. First, the branch matrix is the tax: five live branches means every future CVE is a five-release afternoon, and anyone parked on an EOL branch (2.1) is silently exposed — platform teams should treat containerd version hygiene as a first-class node-image concern, not an incidental one, and the endoflife.date/containerd tracker is the honest place to check yours. Second, the checkpoint/restore redesign (KEP-5823, still open) will test whether the project can add back a dangerous feature class with a better architecture, or whether the 2026 purge becomes permanent precedent. Third, Kubernetes 1.38 will drop the cgroup-driver fallback that old kubelets rely on, which forces yet another round of runtime upgrades through fleets that just finished the dockershim migration.

Verdict: containerd is the rare infrastructure monoculture that earned its position — neutral governance, narrow scope, and the discipline to delete its own features when the security math turns against them. The "boring plumbing" Docker cut loose in 2015 now carries most of the world's containers, and its current maintainers — a rotating roster funded by the cloud vendors who depend on it — respond to criticals in days across five branches. That's not luck; that's the CNCF working as designed. The risk isn't that containerd fails; it's that almost nobody can name what runs their containers, and the next checkpoint-restore-shaped feature lands in a daemon nobody remembers upgrading. (For the version-by-version mechanics of the latest releases, see our containerd 2.4.1 release page and the 2.4.0 release page — and for the runtime's sibling-in-arms on the CNI side, our Cilium tale.)