All Articles

containerd vs Docker vs CRI-O — Which Container Runtime Should You Use? (2026)

Kubernetes deprecated Docker as a runtime in 2020. In 2026, containerd and CRI-O run most production clusters. Here's the difference and which one to pick.

DevOpsBoysApr 12, 20264 min read
Share:Tweet

Docker was Kubernetes' original container runtime. In 2020, Kubernetes deprecated it. In 2026, most production clusters run containerd or CRI-O. Here's what changed, why, and which runtime to choose.

Why Kubernetes Dropped Docker

Kubernetes needs a runtime that implements the Container Runtime Interface (CRI) — a standard API for creating, running, and managing containers.

Docker was never built for CRI. Kubernetes used a shim called dockershim to bridge the gap. Maintaining dockershim was extra work, and it added latency.

Old (pre-1.24):
kubectl → API Server → kubelet → dockershim → Docker → containerd → container

New (1.24+):
kubectl → API Server → kubelet → CRI → containerd/CRI-O → container

Docker was removed from the middle. The actual containers still run the same OCI format — just without Docker in the path.


What's the CRI?

The Container Runtime Interface is a gRPC API that kubelet uses to:

  • Create/delete containers
  • Pull images
  • Manage pod sandboxes

Any runtime implementing CRI works with Kubernetes. Today that's containerd, CRI-O, and (via plugins) others.


containerd

What it is

containerd started as Docker's internal component for container lifecycle management. Docker Inc. donated it to CNCF in 2017. It's now a standalone runtime.

Architecture

kubelet → CRI plugin → containerd → runc → container

containerd handles:

  • Image pull and storage
  • Container lifecycle (create, start, stop)
  • Networking (via CNI plugins)
  • Snapshotters for storage

Key facts

  • Default runtime on EKS, GKE, AKS
  • Written in Go
  • Small footprint (~50MB)
  • CRI plugin built-in (no extra shim)
  • Supports both Docker and OCI images

Check if your node uses containerd

bash
kubectl get node <node-name> -o jsonpath='{.status.nodeInfo.containerRuntimeVersion}'
# Output: containerd://1.7.x

containerd CLI tool

bash
# crictl — works with any CRI runtime
crictl ps           # list containers
crictl images       # list images
crictl logs <id>    # container logs
crictl exec -it <id> /bin/sh  # exec into container

CRI-O

What it is

CRI-O was built from scratch specifically for Kubernetes. Red Hat created it. The name comes from CRI + OCI (Open Container Initiative).

Architecture

kubelet → CRI-O → runc/kata/etc → container

CRI-O is minimal by design. It does exactly what Kubernetes needs — nothing more.

Key facts

  • Default on OpenShift (Red Hat)
  • Follows Kubernetes release cycle exactly (CRI-O 1.28 = K8s 1.28)
  • Smaller than containerd
  • No standalone Docker CLI compatibility
  • Better suited for security-hardened environments

Check CRI-O

bash
kubectl get node -o wide
# Look at CONTAINER-RUNTIME column: cri-o://1.28.x

Docker (for development)

Docker still exists and is useful — just not as a Kubernetes runtime. In 2026:

  • Docker Desktop — still the standard for local development on Mac/Windows
  • Docker CLI — most engineers use it to build images and run containers locally
  • Docker Compose — local multi-service dev environments
  • docker build — building OCI-compatible images (usable by all runtimes)

The key insight: images built with docker build run on containerd, CRI-O, or any OCI-compliant runtime. The image format is standard.


Side-by-Side Comparison

FeaturecontainerdCRI-ODocker (runtime)
CRI compliantYesYesNo (removed K8s 1.24)
Default onEKS, GKE, AKSOpenShiftNowhere (K8s)
Image formatOCI + DockerOCI + DockerOCI + Docker
CLI toolcrictl, nerdctlcrictldocker
FootprintSmall (~50MB)SmallestLarge (~200MB+)
K8s supportAll versionsAll versions≤ K8s 1.23
CNCF projectYes (graduated)Yes (incubating)No
Release cycleIndependentTied to K8sIndependent
Security focusGoodExcellentGood
Windows supportYesNoYes

Performance

In practice, the performance difference is negligible for most workloads. Both CRI-O and containerd use runc as the low-level runtime (the thing actually creating the container process).

For very high pod churn (thousands of pod creates/deletes per minute), CRI-O has shown slightly better performance in benchmarks due to its simpler architecture.


Which Should You Use?

Use containerd if:

✅ You're using managed Kubernetes (EKS, GKE, AKS) — it's already set up
✅ You need Windows node support
✅ You want maximum ecosystem compatibility
✅ You're self-managing Kubernetes with kubeadm

Use CRI-O if:

✅ You're running OpenShift or RHEL-based nodes
✅ You need the tightest Kubernetes version pairing
✅ You have strict security requirements (CIS hardening)
✅ You want the minimal-footprint option

Use Docker (still) if:

✅ Local development on your laptop
✅ Building images in CI pipelines
✅ Running non-Kubernetes containers (docker run)


Migration: From dockershim to containerd

If you have old nodes still on Docker (K8s ≤ 1.23):

bash
# 1. Drain the node
kubectl drain <node> --ignore-daemonsets --delete-emptydir-data
 
# 2. Install containerd
apt-get install containerd.io
containerd config default > /etc/containerd/config.toml
# Edit: SystemdCgroup = true
 
# 3. Update kubelet to use containerd
# /etc/default/kubelet or /var/lib/kubelet/kubeadm-flags.env
--container-runtime-endpoint=unix:///run/containerd/containerd.sock
 
# 4. Restart kubelet
systemctl restart kubelet containerd
 
# 5. Uncordon
kubectl uncordon <node>

nerdctl — Docker-compatible CLI for containerd

If you miss docker commands on nodes running containerd:

bash
# Install nerdctl
wget https://github.com/containerd/nerdctl/releases/latest/download/nerdctl-linux-amd64.tar.gz
tar xvf nerdctl-linux-amd64.tar.gz
mv nerdctl /usr/local/bin/
 
# Works just like docker
nerdctl build -t myapp:latest .
nerdctl run -d nginx
nerdctl ps
nerdctl images

Summary

In 2026, containerd is the safe default for most teams. It's battle-tested on all major cloud providers, well-documented, and the most widely used. CRI-O is the right choice if you're on OpenShift or need the tightest security posture.

Docker is alive and well — just not as a Kubernetes runtime. You'll still build images with it every day.


Learn More

Newsletter

Stay ahead of the curve

Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.

Related Articles

Comments