Skip to main content

Container Runtime Interface

A Kubernetes plugin interface that defines how Kubernetes communicates with container runtimes. CRI allows Kubernetes to work with containerd, CRI-O, and other runtimes — and explains why Kubernetes deprecated Docker as a runtime in version 1.24.

Container Runtime Interface — How Kubernetes Runs Containers

What Is the Container Runtime Interface in Simple Terms?

Kubernetes does not run containers directly — it delegates that work to a container runtime via a standard API called the Container Runtime Interface (CRI). Any runtime that implements CRI can work with Kubernetes — containerd, CRI-O, and others.

This is why Kubernetes deprecated Docker in version 1.24. Docker was not CRI-compliant. Kubernetes used a special adapter called the Docker shim to bridge Docker and CRI. When Kubernetes removed the shim, it switched to containerd directly — which is faster, simpler, and was always the actual engine doing the work anyway.

◈ DIAGRAM
Before Kubernetes 1.24:
kubelet -> Docker shim -> Docker daemon -> containerd -> runc
^
| extra layer, maintained by Kubernetes team
After Kubernetes 1.24:
kubelet -> CRI -> containerd -> runc
^
| clean interface, much simpler

What This Means for You

Bash
If you are a developer:
Almost nothing changes.
Images built with Docker still work perfectly.
Docker images ARE OCI images — containerd runs them.
docker build, docker push still work.
Only the runtime on Kubernetes nodes changed.
If you are running Kubernetes:
Kubernetes 1.24+: use containerd, not Docker
Check runtime on your nodes:
kubectl get nodes -o wide
# Container Runtime: containerd://1.7.8
# <- containerd is the runtime, not docker

CRI Implementations

TEXT
containerd (most common):
Created by Docker, donated to CNCF
Default runtime for most Kubernetes distributions
Powers: EKS, GKE, AKS, kubeadm clusters
Docker images work natively
CRI-O:
Designed specifically for Kubernetes
Minimal footprint
Used by: OpenShift, some kubeadm clusters
Docker images work natively
gVisor (sandboxed runtime):
Google's container runtime with its own kernel
VM-level isolation with container speed
Used for: untrusted workloads, multi-tenant
Kata Containers:
Lightweight VMs that look like containers
True VM isolation via hardware virtualization
Used for: strict compliance requirements

Checking Your Runtime

Bash
# On a Kubernetes node
kubectl get nodes -o wide
# CONTAINER-RUNTIME
# containerd://1.7.8
# Check containerd directly on the node
sudo ctr version
ctr containers list
# crictl — CRI-compatible kubectl for node debugging
crictl ps
crictl images
crictl logs container-id
Remember

The Docker deprecation in Kubernetes does not affect your workflow as a developer. You still build images with Docker, push to registries, and pull them in Kubernetes. The change was only on the Kubernetes node side — containerd runs your Docker images directly without needing Docker installed on the node.

Frequently Asked Questions

Why did Kubernetes need CRI instead of just calling Docker directly?

Early Kubernetes had Docker-specific code hardwired into the kubelet, which meant supporting any other runtime (rkt, containerd directly) required custom, non-standardized integration work. CRI defined a standard gRPC API so the kubelet could talk to any compliant runtime the same way, decoupling Kubernetes' release cycle from any single runtime's internals and letting the ecosystem support containerd, CRI-O, and others as first-class, interchangeable options.

Why did Kubernetes drop Docker support in 1.24, and does that mean Docker images stopped working?

Docker itself was never CRI-compliant — Kubernetes used a shim called dockershim to translate between the CRI and Docker's own API, and that shim was removed in 1.24 because maintaining it duplicated functionality containerd (which Docker itself uses under the hood) already provided natively via CRI. This didn't break Docker-built images at all — OCI-compliant images run fine on containerd or CRI-O; only the daemon used to run them at the node level changed.