Kubernetes Container Runtime Interface (CRI) Explained
The Kubernetes Container Runtime Interface (CRI) is the contract that lets the kubelet ask node-level software to prepare Pod sandboxes, run containers, and manage images. It matters to cluster operators choosing or troubleshooting a runtime, and to developers trying to understand what happens between a Pod being assigned to a node and its process starting. CRI is a local node interface, not the container format or the cluster network.
What Is Kubernetes CRI?
The Kubernetes project is an open-source system for orchestrating containerized applications. Each node needs software that can turn the kubelet’s desired Pod state into running processes. The Container Runtime Interface documentation defines the protocol used between those two components, so Kubernetes can support different runtime implementations without embedding each runtime’s private API in the kubelet.
CRI is a versioned gRPC API described with Protocol Buffers. On a typical Linux node, the kubelet connects to the runtime through a local Unix socket; Windows nodes use a named pipe. The protocol is normally not exposed as a public cluster endpoint. Its gRPC transport uses HTTP/2, whose framing and multiplexing are specified by IETF RFC 9113.
The interface has two related services:
- Runtime service: creates and manages Pod sandboxes and containers, reports their state, and supports operations such as starting, stopping, and removing them.
- Image service: pulls, lists, inspects, and removes container images.
The kubelet is the CRI client. The runtime implements the server side and performs the node-local work. The interface itself does not schedule Pods, store cluster state, or decide which node receives a workload.
Why Does CRI Exist?
Without a standard boundary, the kubelet would need a separate integration for every container runtime. That would couple Kubernetes releases to runtime implementation details and make it harder for distributions or operators to replace the component responsible for executing containers.
CRI keeps the orchestration decision separate from the local execution mechanism. The control plane schedules a Pod and records desired state. The kubelet on the selected node observes that assignment, prepares the Pod locally through CRI, and reports status back to Kubernetes. A compatible runtime can implement the same contract while using different internal components for image storage, sandbox creation, and process execution.
This separation also helps explain an older source of confusion: Docker Engine is not itself a Kubernetes CRI implementation. Kubernetes removed its built-in dockershim integration. Clusters that need Docker Engine as the underlying engine can use an adapter such as cri-dockerd, which translates CRI requests to Docker Engine’s API. Most installations instead use a runtime with CRI support built in.
How CRI Works
The path from a scheduled Pod to a running process usually looks like this:
Kubernetes API server
|
| Pod assigned to a node
v
kubelet
|
| gRPC over a local socket or named pipe
v
CRI-compatible runtime
|
+--> image service: pull or inspect image
|
+--> runtime service: create Pod sandbox and containers
|
+--> network setup through the node's networking integration
+--> OCI runtime (for example, runc) starts the process
The API server does not call the runtime directly. The kubelet reconciles the Pod specification on its node and uses the CRI endpoint configured for that node. For a new Pod, the runtime prepares a sandbox that represents the Pod’s shared execution context, then creates the requested application containers inside it. The sandbox is not the same thing as an application container: it is the runtime’s representation of the Pod-level environment, including shared namespaces where applicable.
Before a container can start, its image must be available. The kubelet asks the image service to pull or inspect it according to the Pod’s image-pull policy. The runtime service then creates and starts containers, monitors their state, and returns status to the kubelet. The kubelet continues reconciling so that restarts, deletions, and changes in desired state are reflected on the node.
CRI is an abstraction, not a promise that every implementation has identical behavior. Runtimes may differ in configuration, logging, snapshotters, security integrations, supported features, and the low-level runtime used to start a process. The gRPC model defines unary and streaming calls; CRI API versions determine which Kubernetes operations and messages are available.
One newer example is CRI list streaming. Standard list calls return all matching containers, sandboxes, or images in one response. On a node with a very large number of objects, that response can become too large for common gRPC message limits. Kubernetes documents CRI list streaming as an alpha feature, disabled by default; when enabled and supported by the runtime, it can send results in multiple messages. It is an opt-in compatibility feature, not a requirement for every cluster.
Components and Runtime Choices
CRI describes the kubelet-to-runtime boundary. It is distinct from the standards that describe image packaging and low-level process execution. The Open Container Initiative (OCI) publishes specifications for container images and runtimes. A CRI implementation can use OCI-compatible images and invoke an OCI runtime, but CRI and OCI solve different parts of the stack.
| Component | Relationship to CRI | Typical responsibility | Important distinction |
|---|---|---|---|
| containerd | Implements CRI through its CRI plugin | Image management and container lifecycle on a node | The containerd project is a general container runtime; Kubernetes uses its CRI integration |
| CRI-O | Implements Kubernetes CRI directly | Runs Kubernetes Pods and manages their images | It is designed specifically to provide a Kubernetes runtime implementation |
Docker Engine with cri-dockerd |
Adapter translates CRI requests to Docker Engine | Retains a Docker Engine-based execution setup | Docker Engine alone is not a CRI server |
OCI runtime such as runc |
Normally called below a CRI implementation | Creates the configured container process using host-kernel features | It does not replace the kubelet-facing CRI service |
These are not all alternatives at the same architectural layer. For example, containerd’s CRI plugin or CRI-O can handle Kubernetes requests and then use an OCI runtime to start a process. The OCI Runtime Specification describes the lower-level execution interface; it does not define Pod scheduling, kubelet communication, or Kubernetes image-pull policy.
Other node systems remain separate as well. A Container Network Interface (CNI) plugin configures Pod networking, while a Container Storage Interface (CSI) driver handles persistent storage. CRI-related runtime integration coordinates Pod sandbox creation with networking, but CRI is not a replacement for CNI or CSI.
Real-World Uses
Choosing a node runtime: Platform teams can select a CRI implementation based on their operating system, distribution support, operational tooling, and required runtime features. The kubelet-facing API gives Kubernetes a common integration point, while administrators still need to validate the runtime’s version and configuration against their cluster.
Diagnosing Pod startup: If a Pod remains in a waiting state, the failure may be in image retrieval, sandbox creation, runtime configuration, or application startup. Knowing that the kubelet communicates with a CRI endpoint helps narrow the investigation to the right node service rather than assuming the control plane directly launches the container.
Operating high-density nodes: Large CI or batch nodes can accumulate many stopped and running containers. Runtime list behavior, garbage collection, and image storage then become operational concerns. The optional streaming API addresses oversized list responses where both the Kubernetes release and runtime support it; it does not eliminate the need to monitor disk space and container churn.
Comparing container layers: CRI explains how Kubernetes requests local container lifecycle operations, while a snapshotter determines how image filesystem layers are prepared. See container image lazy loading and remote snapshotters for a closer look at that storage path.
Getting Started: Inspect a CRI Runtime
You generally do not install CRI as a separate daemon. Install a supported container runtime for each node, configure the kubelet to use its endpoint, and ensure the kubelet and runtime agree on relevant node settings. Follow the Kubernetes container runtime setup guide for platform-specific installation and configuration. It documents containerd’s common Linux socket as /run/containerd/containerd.sock and its Windows named pipe as npipe://./pipe/containerd-containerd.
On a Linux node with crictl installed, point the tool at the runtime endpoint to inspect the service and its objects:
sudo crictl --runtime-endpoint unix:///run/containerd/containerd.sock info
sudo crictl --runtime-endpoint unix:///run/containerd/containerd.sock pods
sudo crictl --runtime-endpoint unix:///run/containerd/containerd.sock ps -a
The endpoint must match the runtime configured for the node; do not assume every distribution uses the same socket. Use read-only inspection first, and avoid changing a live node’s runtime endpoint or cgroup driver as a troubleshooting shortcut.
If a Pod does not start, check the node and the two local services before changing configuration:
kubectl get nodes -o wide
kubectl describe pod <pod-name> -n <namespace>
sudo systemctl status containerd
sudo journalctl -u kubelet -n 100 --no-pager
sudo journalctl -u containerd -n 100 --no-pager
Replace containerd with the actual runtime service name when using CRI-O or another implementation. Check the kubelet’s configured endpoint, verify that the runtime’s CRI service is enabled, and compare the kubelet and runtime logs for connection or version errors. Also confirm that the kubelet and runtime use compatible cgroup-driver settings; mismatches can make node resource management unstable. A node that cannot connect to its runtime may fail to register or may be unable to create Pod sandboxes even when the API server is healthy.
Common Misconceptions
“CRI is the container runtime”
CRI is the API between the kubelet and a runtime implementation. It defines requests and responses, not the complete software stack that stores images or starts processes.
“Kubernetes talks directly to Docker Engine”
The kubelet requires a CRI-compatible endpoint. Docker Engine does not implement that interface itself; a separate adapter is needed to place Docker Engine behind CRI.
“CRI and OCI are competing standards”
They describe different boundaries. CRI connects Kubernetes node management to a runtime service; OCI specifications cover image formats and low-level container execution. One implementation can use both.
“CRI handles all Pod networking and storage”
CRI coordinates the runtime’s Pod lifecycle operations, but networking and persistent storage use their own interfaces and plugins. A healthy CRI endpoint cannot compensate for a broken CNI configuration or unavailable CSI volume.
Related Articles
- Start with the broader Kubernetes architecture overview to see where the kubelet and node runtime fit.
- Compare runtime internals with our guide to Docker containers, images, and runtimes.
- Learn how CNI plugins and Pod interfaces work in container networking.
- Explore the filesystem side of container startup in container image lazy loading and remote snapshotters.
Changelog
- 2026-10-27: Published this explainer.

