When Kubelet Dies Silently: Diagnosing Container Runtime Failures
One of the most frustrating alerts in Kubernetes operations is seeing a node drop to a NotReady or NodeStatusUnknown state. When you run kubectl describe node, the only clue you get is:
Kubelet stopped posting node status.
Where do you even begin to look when the primary node agent dies silently?
This post gathers several incidents from my bare-metal homelab, from read-only filesystem lockdowns to misconfigured network plugins, that all ended the same way.
Impact
- The node drops to
NotReady/NodeStatusUnknownand stops running workloads. - Pods on it are stuck (for example in
ContainerCreating), and the only visible symptom isKubelet stopped posting node status.
Timeline
The pattern seen across these incidents:
- A lower layer fails: the disk goes read-only, or the CNI plugins can't be found.
containerdcrashes or locks up, and its CRI socket disappears.- The
kubeletloses its socket and crash-loops. - The node stops posting status and drops to
NotReady.
In the CNI case specifically: I deployed the Flannel Container Network Interface (CNI), pods refused to leave the ContainerCreating state, and shortly after the node dropped offline entirely.
Root cause
The Kubelet does not exist in a vacuum. The kubelet depends entirely on its Container Runtime Interface (CRI) socket. In modern setups this is usually containerd, listening at /var/run/containerd/containerd.sock. If the kubelet cannot communicate with that socket, it doesn't just log an error and wait: it intentionally crash-loops.
The two most common reasons containerd was dead:
- The hardware lock. When the node's SSD suffers a panic and remounts as read-only,
containerdcrashes immediately because it can no longer write container logs or manage overlay filesystems. Whencontainerddies, the CRI socket disappears, andkubeletfollows it to the grave. - The CNI path mismatch. Debian's
containerdpackage expects CNI plugins to live in/usr/lib/cni/, but the Flannel installer put them in the standard/opt/cni/bin/.containerdcouldn't initialize the network, locked up, and dragged thekubeletdown with it.
Actions
- When SSH'd into a node with a dead
kubelet, don't start withsystemctl restart kubelet. Look down the stack first:
sudo systemctl status containerd
- If
containerdis dead because the disk went read-only, recover the filesystem first (see The Read-Only Lockdown). - For the CNI path mismatch, a symbolic link fixed the entire chain:
sudo ln -sf /opt/cni/bin/* /usr/lib/cni/
Lessons learned
- Kubernetes is a layered architecture. When a high-level agent like the
kubeletstops reporting, don't just restart it: look at the foundation it stands on. - If the container runtime is dead, the node is dead. Fix the runtime, and the
kubeletrecovers automatically.