Andrew Mercer
on this page
  • https://kubernetes.io/docs/setup/production-environment/container-runtimes/

How the pieces fit

The kubelet doesn't run containers itself. It talks gRPC over a Unix socket to a CRI (Container Runtime Interface) implementation, which pulls images and manages pod sandboxes. That runtime then calls a low-level OCI runtime to create the actual Linux namespaces and cgroups.

kubelet ──CRI (gRPC)──▶ containerd / CRI-O ──▶ runc (OCI runtime) ──▶ container process

Since Kubernetes 1.24 (dockershim removal), Docker Engine isn't a supported runtime without the third-party cri-dockerd shim. Images built with Docker still run fine.

Runtimes

Runtime Role Default CRI socket
containerd High-level CRI runtime, the most common choice unix:///run/containerd/containerd.sock
CRI-O High-level CRI runtime built only for Kubernetes unix:///var/run/crio/crio.sock
runc Low-level OCI runtime used by both of the above n/a

kubeadm autodetects the CRI socket when only one runtime is installed. If more than one is present, pass --cri-socket to kubeadm init/join.

Cgroup driver

The kubelet and the runtime must use the same cgroup driver. kubeadm defaults the kubelet to systemd (since v1.22), so the runtime must also be set to systemd. For containerd that means SystemdCgroup = true. A mismatch causes pods to restart in a loop and the control-plane static pods to flap.

in this section
* containerd
* cri-o
* runc