- 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.