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
- containerd/containerd repository (created 2015-11-13)
- First commit 15a96783ca — 'Initial commit', Michael Crosby (2015-11-05)
- Docker blog: Containerd, a daemon to control runC (2015-12-17)
- Docker blog: Docker 1.11, first engine built on runC and containerd (2016-04-13)
- CNCF accepts containerd as incubating project (2017-03-29)
- containerd v1.1.0 release notes — CRI plugin GA (2018-04-24)
- CNCF announces containerd graduation — fifth project (2019-02-28)
- Kubernetes: Updated Dockershim Removal FAQ (2022-02-17)
- Kubernetes docs: Container Runtimes — the containerd section
- containerd 2.0 release notes (2024-11-05)
- containerd.io — Versioning and release (LTS policy, release-state table)
- containerd 2.4.0 release notes (2026-09-16)
- containerd 2.4.1 release notes — CVE-2026-53493 security patch (2026-09-24)
- GHSA-pg57-6jwg-q645 / CVE-2026-53493 — image-pull DoS via OCI index graph amplification
- GHSA-p7v4-vr35-mj6f / CVE-2026-95837 — checkpoint-restore security-context bypass (critical, 2026-09-01)
- GHSA-xhf5-7wjv-pqxp / CVE-2026-53488 — image-config LABEL to host-root execution (critical)
- PR #13871: cri: remove restore in CreateContainer (merged 2026-07-31, samuelkarp)
- PR #13822: cri: implement pod-level checkpoint/restore, KEP-5823 (open)
- runc PR #4324: move crosbymichael to EMERITUS, remove chief maintainer role (merged 2024-06-25)
- containerd/.project EMERITUS.md — Michael Crosby emeritus (2025-06-06)
- containerd/.project maintainers.yaml — current maintainer roster
- AKS core concepts: containerd on Linux node pools 1.19+ (Microsoft Learn)
- KEP-2008: Forensic Container Checkpointing (kubernetes.dev)
- AWS blog: Forensic container checkpointing on Amazon EKS
- CRIU image security documentation
- Docker docs: daemon configuration — containerd image store
- endoflife.date/containerd — branch support windows
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
- 2015-11-05 — First commit
15a96783ca("Initial commit", Michael Crosby); repository created . Eight days later, "Making containers run and delete." - 2015-12-17 — Docker publicly announces containerd: "a daemon to control runC," built for performance and density, "eventually built into Docker Engine." The scope is deliberately narrow plumbing.
- 2016-04 — Docker Engine 1.11 ships as the first runtime built on runC and containerd. Docker's engine now depends on a daemon it donated to a foundation it doesn't control.
- 2017-03-29 — CNCF accepts containerd as an incubating project, explicitly to guarantee neutrality as the runtime layer under Kubernetes' CRI.
- 2017-12-12 — v1.0.0 published. The first stable release of the "industrial-grade container runtime."
- 2018-04-24 — v1.1.0: the CRI plugin goes GA, built into the daemon and enabled by default. Kubernetes can now talk to containerd directly, without the intermediate cri-containerd daemon — which is declared end-of-life in the same release notes. The feature that would put containerd under every kubelet.
- 2020-12 — Kubernetes 1.20 announces dockershim deprecation. The shim that let kubelets talk to Docker Engine has a removal date; every cluster on earth now needs a CRI runtime. containerd is the path of least resistance.
- 2022-02-16 — v1.6.0 published; AKS has already defaulted Linux node pools to containerd (Kubernetes 1.19+), GKE follows with 1.21, EKS with 1.24. The managed clouds complete the migration dockershim's removal forced.
- 2022-05 — Kubernetes 1.24 removes dockershim outright. containerd becomes the de facto default runtime of the ecosystem — not by winning a bake-off, but by being the neutral, graduated, already-integrated option when the deadline arrived.
- 2023-03-10 — v1.7.0 published: CRI v1alpha2 deprecated, sandboxed CRI support, transfer service preview. The last 1.x minor; the branch will ship 36 patches, the final one a security fix.
- 2024-11-05 — v2.0.0 published, eight years in: API module split, sandboxed CRI by default, NRI enabled by default, CRI v1alpha2 removed, aufs snapshotter removed, static-binary variants added for non-glibc distributions. The first release of the "containerd 2.x" era — same daemon, modernized edges.
- 2026-06-18 — Coordinated security batch: five advisories published the same day — three critical (CVE-2026-53488, image LABEL to host-root execution; CVE-2026-53492, CDI annotation smuggling during checkpoint restore; CVE-2026-50195, checkpoint import tag poisoning), one high (CVE-2026-53489, host file read via symlink in the restore path), one medium (CVE-2026-47262, unbounded group parsing DoS) — with patched builds (v2.3.2, v2.2.5, v2.1.9, v2.0.10, v1.7.33) shipping within minutes of each other. Four of the five touch the CRI checkpoint/restore path.
- 2026-07-31 — PR #13871 ("cri: remove restore in CreateContainer", samuelkarp) merges: the feature the critical advisories circled is deleted outright rather than patched again.
- 2026-09-01 — CVE-2026-95837 (critical): CRIU checkpoint restore bypasses the destination security context — restored processes come back with the checkpoint's own credentials, capabilities, and seccomp state instead of the ones the orchestrator requested. Patched in 2.2.7 / 2.3.4 by disabling restore via CreateContainer; a new
enable_experimental_restore_via_createoption exists for users who need it back and accept the risk. - 2026-09-16 — v2.4.0 published: first release of the post-purge era — restore-via-CreateContainer removed entirely, id-mapping label hardening in unpack, mount manager for CRI image mounts, UserNamespacesHostNetwork default-on. A regular (non-LTS) branch with a shorter support window.
- 2026-09-24 — v2.4.1, v2.3.6, v2.2.9, v2.0.13, v1.7.36 published in one wave: CVE-2026-53493 (image-pull DoS via crafted OCI index graph amplification — "no known workarounds", medium) patched across five live branches at once. The five-branch reality of 2026-era containerd, in one afternoon.
- 2026-09-30 — v1.7 branch reaches end-of-life per the project's support table — six days after its final security patch. The 1.x era ends, on schedule, quietly.
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.)