Containerd Image Store, Snapshotters, Runtime Internals, OCI Runtime Specs, and Docker Engine Evolution: Configuration, Design Choices, and Tradeoffs
Choose between containerd-backed and classic storage architectures, snapshotter strategies, Engine abstraction and direct containerd platforms, and migration timing using observable prerequisites and rollback boundaries.
Learning objectives
- Compare containerd image-store and classic graph-driver architectures without reducing the choice to “new versus old.”
- Evaluate snapshotter choices by kernel/filesystem support, portability, performance, observability, and operational ownership.
- Decide when Docker Engine abstraction is preferable to direct containerd platforms such as Kubernetes/CRI or purpose-built runtime stacks.
- Build a migration plan that preserves images/containers and downgrade options instead of relying on hidden on-disk state.
- Document version/platform/trust prerequisites for every design choice.
1. Design starts with the supported control plane
Containerd is a general container runtime platform, but Docker Engine is more than a thin alias for containerd. Docker owns API compatibility, networking, volumes, build integration, image semantics, restart/health behavior, logging, Compose integration, and the lifecycle expectations taught throughout this course. When you use Docker Engine, its managed containerd is an implementation component, not an invitation to split lifecycle ownership between Docker and low-level clients.
2. Choice: containerd image store versus classic graph-driver store
| Criterion | containerd image store | Classic graph-driver store |
|---|---|---|
| Engine 29 default | Fresh installs | Usually upgraded/compatibility installs |
| Filesystem mechanism |
containerd snapshotters; default overlayfs
|
Docker classic driver such as overlay2 |
| Multi-platform local images | Native image-index support | Limited; external builder/registry often needed |
| Attestations in local store | Supported | Classic-store limitations |
| Disk model | Compressed content + unpacked snapshots can increase disk use | Primarily classic unpacked layer model |
| Compatibility | Current direction; userns-remap limitation remains | Useful for legacy constraints and some remap/upgrade scenarios |
| Migration risk | Requires explicit plan for upgraded hosts | No migration if you intentionally stay put |
3. Choice: snapshotter strategy
The default overlayfs snapshotter is the sensible
baseline for ordinary Linux Engine deployments. Advanced
snapshotters can support lazy pulling, peer-to-peer distribution,
filesystem-specific behavior, or different performance
characteristics. Those benefits come with prerequisites and new
failure domains: kernel modules, FUSE/userspace components, external
services, registry format expectations, and monitoring requirements.
| Question | Default overlayfs | Advanced/remote snapshotter |
|---|---|---|
| Prerequisites | Well-understood Linux OverlayFS support | Specific kernel/filesystem/plugin/service prerequisites |
| Portability | High for supported Linux hosts | Varies by snapshotter and platform |
| Startup behavior | Traditional pull/unpack | May defer/lazily fetch content |
| Failure isolation | Mostly local host storage | Can add network/plugin/control-plane dependencies |
| Audit evidence | Docker info + local storage evidence | Also record plugin/version/config/remote availability |
4. Choice: Docker abstraction versus direct containerd platform
Use Docker Engine when you need Docker’s API, image/build/Compose workflow, local developer ergonomics, and operational semantics. Use direct containerd integrations when the platform is designed around containerd’s API/CRI model and you are prepared to own that lifecycle independently—for example, Kubernetes nodes use container runtimes through CRI rather than the Docker Engine API.
5. Choice: migrate now, later, or rebuild fresh
Docker’s current recommendation makes fresh installations the low-risk path. For an upgraded Engine, switching the storage backend can make images and containers from the other store temporarily hidden while leaving them on disk. That is not data deletion, but it can look like one if the change is made without inventory and rollback notes.
Before any migration, record exact Engine version, storage mode, image digests/tags, stopped/running containers, volumes, Compose project definitions, registry availability, disk capacity, and downgrade constraints. Export or push images that cannot be rebuilt quickly. Back up application data independently of image storage.
6. Manual switch versus experimental automatic migration
Docker documents a manual
containerd-snapshotter feature switch for upgraded
hosts and an experimental
containerd-migration feature that can automatically
migrate under bounded conditions. A production course must treat
“experimental” as a lifecycle risk signal, not as a convenience
flag.
7. Data-root and capacity tradeoff
With the containerd image store, changing Docker’s
data-root does not automatically relocate containerd
image/snapshot data. Docker documents
/var/lib/containerd as the default Linux location for
those objects and /var/lib/docker for other Docker
daemon data. A host whose root partition is small can therefore fill
unexpectedly after a migration even if
/var/lib/docker was previously moved elsewhere.
Capacity planning must include compressed registry content, unpacked snapshots, writable layers, BuildKit caches, logs, volumes, and growth/cleanup policies. Do not use broad prune as a capacity-management strategy.
8. Docker Desktop is a separate platform boundary
Docker Desktop uses a Linux VM on macOS/Windows and has its own
settings and storage lifecycle. Desktop has used the containerd
image store by default in modern releases and can expose a UI
setting to switch stores. Do not transplant Linux host paths such as
/var/lib/containerd into Windows/macOS operational
runbooks as if they were native host directories.
9. Engine 29.7+ embedded containerd is not a migration shortcut
Embedded containerd changes how Engine hosts the containerd server, not the high-level ownership model. Docker labels it experimental. Enabling it should be treated as a daemon topology experiment with compatibility/performance goals, not as a method for repairing image-store corruption or bypassing ordinary containerd deployment constraints.
10. Decision table
| Scenario | Recommended direction | Prerequisites/evidence |
|---|---|---|
| Fresh Linux Engine 29 host | Use containerd image-store default unless a documented incompatibility exists | Engine version, filesystem/kernel support, userns-remap requirement, disk capacity |
| Upgraded stable production host on classic overlay2 | Do not switch only for novelty; schedule migration when benefits justify change | Inventory, registry/export path, maintenance window, rollback test, free disk |
| Host requires daemon userns-remap | Keep supported compatible architecture; do not disable remap just to gain image-store features | Security requirement, current Docker limitation, compensating features |
| High-scale lazy-pull requirement | Evaluate supported advanced snapshotter in a dedicated performance/reliability test | Plugin/version, registry, kernel, outage behavior, metrics |
| Kubernetes/containerd node | Use the platform’s supported container runtime/CRI ownership | Cluster/runtime documentation; never point Docker tools at its state |
| Docker developer workstation | Stay behind Docker Engine/Desktop abstraction | Record Desktop/Engine version and local store mode |
11. Worked scenario: an upgraded CI host
A CI host upgraded from Engine 28 to 29 still reports classic
overlay2. The team wants local multi-platform indexes
and attached attestations. A defensible plan is: inventory
jobs/images/caches; confirm builders already push reproducible
artifacts to a registry; create a fresh parallel Engine 29 host with
containerd image store; replay representative builds; compare disk
use and cleanup; move jobs gradually; retire the old host after
evidence retention. That avoids an in-place storage experiment on a
critical runner.
12. Design checklist
- Which component owns lifecycle: Docker Engine or another containerd-based platform?
- What exact Engine/containerd/runtime/spec versions are in scope?
- Which image-store mode and snapshotter are active?
- Does userns-remap/rootless/security policy constrain the design?
- Where do compressed content, snapshots, Docker data, volumes, and build cache live?
- Can every important image be rebuilt or restored from a registry/export?
- What is the rollback path if switched state becomes hidden or incompatible?
- Which metrics prove performance/capacity improvements rather than assumptions?
Knowledge check
Why might an upgraded Engine 29 host remain on overlay2?
Docker preserves the prior classic storage architecture for upgrades unless the operator switches/migrates; fresh Engine 29 installs default to the containerd image store.
Why is an advanced snapshotter not automatically “better”?
It can add kernel, plugin, network, registry, observability, and operational dependencies that must be justified by workload benefits.
What is the safest way to gain a new storage architecture on a critical CI host?
Often a fresh parallel host and controlled workload migration, because it provides a clean rollback boundary and avoids in-place state conversion risk.
Does switching image stores necessarily delete the old images?
No. Docker documents that objects in the inactive store can remain on disk but become hidden until you switch back. Treat visibility and disk retention separately.
When should ctr be the lifecycle control plane for Docker-managed state?
Never. If you intentionally run a direct containerd platform, that is a separate architecture and state ownership model.
Official references and version notes
Design baseline date: 2026-09-22. Docker’s current
guidance makes the containerd image store the fresh Engine 29
default, keeps upgraded hosts on their prior architecture until
switched, documents overlayfs as the default
snapshotter, and marks automatic migration/embedded-containerd paths
as experimental where noted.
- Docker Docs — containerd image store with Docker Engine — Engine 29 fresh-install defaults, snapshotters, disk layout, switching, and experimental migration guidance.
- Docker Docs — Storage drivers — distinction between classic graph drivers and the Engine 29 containerd image store.
- Docker Docs — Select a storage driver — current storage-backend matrix and platform notes.
-
Docker Docs — Docker daemon configuration overview
—
/var/lib/dockerversus/var/lib/containerdand data-root implications. - Docker Docs — Run containerd in the Docker daemon — Engine 29.7+ experimental embedded-containerd mode and debugging endpoint warning.
- Docker Engine 29 release notes — Engine 29.8.1 baseline, containerd 2.3.5 static-binary packaging, BuildKit 0.33.0 and runc 1.5.1 updates.
- containerd 2.3 — Features — namespaces, images, root filesystems, snapshots, containers, tasks, and OCI runtime integration.
-
containerd — Snapshotters
— core snapshotter behavior and the
overlayfsnaming used by containerd. - OCI Image Specification 1.1.1 — image indexes, manifests, configs, layers, and content-addressable descriptors.
-
OCI Runtime Specification 1.3.0
— runtime bundle,
config.json, execution environment, and lifecycle model.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this
address.