Container Runtimes in Kubernetes

Container runtimes are the software that actually runs containers. This guide covers containerd, CRI-O, Docker Engine, and how they integrate with Kubernetes through the Container Runtime Interface (CRI).

containerd CRI-O Docker Engine CRI
What is a Container Runtime?

A container runtime is the software that actually runs containers. It's responsible for pulling images, creating namespaces, managing cgroups, and executing container processes. Kubernetes doesn't run containers directly—it delegates to a container runtime through the Container Runtime Interface (CRI).

The most common container runtimes for Kubernetes are containerd (the current default), CRI-O (designed specifically for Kubernetes), and Docker Engine (via cri-dockerd). Each has different trade-offs in terms of features, performance, and compatibility.

In Kubernetes v1.24 and later, Docker Engine support requires the cri-dockerd adapter. containerd is the default runtime for most Kubernetes distributions.
CRI: The Container Runtime Interface

The Container Runtime Interface (CRI) is a plugin interface that allows Kubernetes to use different container runtimes without recompiling. CRI defines gRPC APIs for managing containers, images, and pods. Any runtime that implements CRI can be used with Kubernetes.

# CRI API operations - RunPodSandbox / StopPodSandbox - CreateContainer / StartContainer / StopContainer - ListImages / PullImage / RemoveImage - ContainerStatus / PodSandboxStatus # Check which CRI runtime your node is using kubectl get nodes -o wide # Look at CONTAINER-RUNTIME column # Check runtime on node crictl info crictl ps crictl images
OCI: The Open Container Initiative

OCI defines standards for container formats and runtimes. Most container runtimes (containerd, CRI-O, Docker, runc) are OCI-compliant. The OCI runtime specification defines how to run a container (using runc as the reference implementation).

Kubernetes
(gRPC via CRI)
Container Runtime (containerd / CRI-O / cri-dockerd)
(OCI)
OCI Runtime (runc)
Linux Kernel (namespaces, cgroups, seccomp)
Container Runtimes Comparison
Runtime Maintainer Default In CRI Support
containerd Cloud Native Computing Foundation (CNCF) Kubernetes v1.24+ Native
CRI-O Red Hat / CNCF OpenShift, Fedora CoreOS Native
Docker Engine Docker Inc Older K8s versions (via dockershim) Via cri-dockerd adapter
Containerd: The Industry Standard

Containerd is a high-level container runtime that manages the complete container lifecycle. It's the default runtime for Kubernetes (v1.24 and later). Containerd is used by Docker (under the hood), and by many cloud providers. It's fast, stable, and production-proven at massive scale.

Key features: OCI image format support, container lifecycle management, image pull/push, network management (CNI integration), and snapshot management. Containerd is CNCF graduated and used by AWS EKS, Google GKE, and Azure AKS.

# Check containerd version containerd --version ctr version # List containers with ctr ctr containers list # List images with ctr ctr images list # Namespaces in containerd ctr namespace ls ctr -n k8s.io containers list # Check containerd configuration cat /etc/containerd/config.toml # Restart containerd sudo systemctl restart containerd
CRI-O: Lightweight CRI Implementation

CRI-O is a lightweight container runtime specifically designed for Kubernetes. It implements the CRI directly and uses OCI-compliant runtimes (like runc) underneath. CRI-O is developed by Red Hat and is the default runtime for OpenShift and Fedora CoreOS.

Key features: Native CRI implementation (no adapter needed), minimal footprint, strong focus on Kubernetes integration, and support for multiple OCI runtimes (runc, kata, gVisor).

# Check CRI-O version crio --version runc --version # List containers with crictl crictl ps crictl images # Check CRI-O configuration cat /etc/crio/crio.conf # Restart CRI-O sudo systemctl restart crio # View CRI-O logs journalctl -u crio -f
Docker Engine (via cri-dockerd)

Docker Engine was the original runtime for Kubernetes. In Kubernetes v1.20, dockershim (the Docker CRI adapter) was deprecated, and in v1.24 it was removed. To continue using Docker Engine, you need cri-dockerd, which translates CRI calls to Docker API calls.

While still possible, using Docker Engine with Kubernetes is no longer recommended for new clusters. It adds an extra layer (cri-dockerd) and has performance overhead compared to containerd or CRI-O.

# Install cri-dockerd git clone https://github.com/Mirantis/cri-dockerd.git cd cri-dockerd make sudo make install # Start cri-dockerd service sudo systemctl start cri-docker # Check kubelet config to use cri-dockerd # /var/lib/kubelet/kubeadm-flags.env # --container-runtime=remote # --container-runtime-endpoint=unix:///var/run/cri-dockerd.sock # Check Docker version docker version # Check cri-dockerd logs journalctl -u cri-docker -f
Docker Engine is not recommended for new Kubernetes clusters. Migrate to containerd or CRI-O for better performance and support.
RuntimeClass: Multiple Runtimes in One Cluster

RuntimeClass allows you to use different container runtimes for different pods in the same cluster. This is useful for running specialized workloads (like Kata Containers or gVisor) alongside standard containers.

# Define RuntimeClass for Kata Containers apiVersion: node.k8s.io/v1 kind: RuntimeClass metadata: name: kata handler: kata # Define RuntimeClass for gVisor apiVersion: node.k8s.io/v1 kind: RuntimeClass metadata: name: gvisor handler: runsc # Use RuntimeClass in pod apiVersion: v1 kind: Pod metadata: name: secure-pod spec: runtimeClassName: gvisor containers: - name: app image: nginx # List available RuntimeClasses kubectl get runtimeclass
Choosing the Right Container Runtime
  • Use containerd for most clusters - It's the default, mature, and supported by all major cloud providers.
  • Use CRI-O for OpenShift or RHEL environments - Tight integration with Red Hat ecosystem, lightweight, and Kubernetes-native.
  • Avoid Docker Engine for new clusters - Legacy option. Use containerd instead.
  • Use RuntimeClass for special isolation - Kata Containers or gVisor for multi-tenant security.
For most users, containerd is the best choice. It's fast, stable, and the default for Kubernetes.
Checking Which Runtime Your Cluster Uses
# Check nodes for container runtime kubectl get nodes -o wide # Check kubelet logs journalctl -u kubelet | grep -i "container runtime" # On node: check containerd sudo systemctl status containerd crictl info # On node: check CRI-O sudo systemctl status crio # On node: check Docker sudo systemctl status docker
Migrating from Docker to containerd

If you're still using Docker Engine with Kubernetes, plan to migrate to containerd. Here's a migration plan:

# Step 1: Drain the node kubectl drain node-name --ignore-daemonsets # Step 2: Stop kubelet systemctl stop kubelet # Step 3: Install containerd apt-get update && apt-get install -y containerd # Step 4: Configure containerd mkdir -p /etc/containerd containerd config default > /etc/containerd/config.toml systemctl restart containerd # Step 5: Configure kubelet to use containerd # Edit /var/lib/kubelet/kubeadm-flags.env # Add: --container-runtime=remote # Add: --container-runtime-endpoint=unix:///run/containerd/containerd.sock # Step 6: Restart kubelet systemctl start kubelet # Step 7: Uncordon the node kubectl uncordon node-name
Frequently Asked Questions
What happened to dockershim in Kubernetes?
Dockershim was deprecated in Kubernetes v1.20 and removed in v1.24. To use Docker Engine, you now need cri-dockerd. For new clusters, use containerd.
Can I still use Docker commands with containerd?
Yes, you can use nerdctl, a Docker-compatible CLI for containerd. It works almost identically to Docker CLI.
Which runtime is fastest?
containerd and CRI-O have similar performance (both use runc underneath). Docker Engine (via cri-dockerd) has slight overhead.
Does containerd support Windows containers?
Yes, containerd supports Windows containers. CRI-O is Linux-only.
What is runc?
runc is the reference implementation of the OCI runtime spec. It's the low-level runtime that actually creates and runs containers. containerd and CRI-O both use runc by default.
Can I use gVisor with Kubernetes?
Yes! gVisor (runsc) provides stronger isolation using a user-space kernel. Configure it as a RuntimeClass and use runtimeClassName: gvisor in your pods.
Which cloud providers use which runtime?
AWS EKS, Google GKE, and Azure AKS all use containerd as the default runtime.
How do I build images without Docker Engine?
Use alternatives like Podman, buildah, or kaniko. containerd doesn't include an image builder out of the box.
Previous: Migrating from Swarm to Kubernetes Next: Kubernetes Architecture

Container runtimes are the foundation of Kubernetes. Choose containerd for most clusters, CRI-O for Red Hat environments, and use RuntimeClass for special isolation needs.