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.
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 simplerWhat This Means for You
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 dockerCRI Implementations
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 requirementsChecking Your Runtime
# On a Kubernetes nodekubectl get nodes -o wide# CONTAINER-RUNTIME# containerd://1.7.8 # Check containerd directly on the nodesudo ctr versionctr containers list # crictl — CRI-compatible kubectl for node debuggingcrictl pscrictl imagescrictl logs container-idRememberThe 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.