🎉 DevOps Interview Prep Bundle is live — 1000+ Q&A across 20 topicsGet it →
All Articles

Kubernetes Node NotReady: Fix in 5 Minutes

Node stuck in NotReady status and pods getting evicted or stuck Pending? Here is exactly how to diagnose kubelet, container runtime, network plugin, and disk pressure causes — and fix each one.

Shubham4 min read
Share:Tweet

A NotReady node stops scheduling new pods and, after 5 minutes (the default pod-eviction-timeout), starts evicting the pods already running there. Here is how to find which of the four real causes you have before you start restarting things randomly.

Step 1: Confirm the Actual Reason

bash
kubectl get nodes
# NAME       STATUS     ROLES    AGE   VERSION
# worker-3   NotReady   <none>   45d   v1.29.2
 
kubectl describe node worker-3 | grep -A 10 "Conditions:"
# Type             Status  Reason
# ----             ------  ------
# MemoryPressure   False   KubeletHasSufficientMemory
# DiskPressure     True    KubeletHasDiskPressure   ← here's your cause
# PIDPressure      False   KubeletHasSufficientPID
# Ready            False   KubeletNotReady

The Conditions block tells you which subsystem is actually failing — don't skip straight to restarting kubelet before reading this.

Cause 1: Kubelet Not Running or Crashed

bash
# SSH to the node (or use a debug pod if SSH isn't available)
ssh worker-3
sudo systemctl status kubelet
 
# If it's crashed, check why
sudo journalctl -u kubelet -n 100 --no-pager

Common kubelet crash reasons: certificate expired, disk full so it can't write logs, or a config change that wasn't applied cluster-wide.

bash
# Certificate expiry is the most common silent killer
sudo journalctl -u kubelet | grep -i "certificate\|x509"
# "x509: certificate has expired or is not yet valid"
 
# Check cert expiry directly
sudo kubeadm certs check-expiration

Fix — renew certs and restart:

bash
sudo kubeadm certs renew all
sudo systemctl restart kubelet

Cause 2: Disk Pressure

bash
df -h /var/lib/kubelet /var/lib/containerd
# If /var is above ~85%, kubelet marks DiskPressure=True and stops scheduling

Usually this is unpruned container images and dangling volumes.

bash
# Check what's actually eating disk
sudo du -sh /var/lib/containerd/io.containerd.content.v1.content/blobs/* 2>/dev/null | sort -rh | head -10
 
# Prune unused images and containers
sudo crictl rmi --prune
# or for docker runtime:
docker system prune -af --volumes

Fix — set a garbage collection threshold so this doesn't recur:

yaml
# kubelet config
evictionHard:
  nodefs.available: "10%"
  imagefs.available: "15%"
imageGCHighThresholdPercent: 80
imageGCLowThresholdPercent: 70

Cause 3: Container Runtime Down (containerd/CRI-O)

bash
sudo systemctl status containerd
sudo journalctl -u containerd -n 50 --no-pager
 
# kubelet logs will show this pattern when the runtime is unreachable:
# "Failed to get status for pod: rpc error: code = Unavailable
#  desc = connection error: desc = "transport: Error while dialing
#  dial unix /run/containerd/containerd.sock: connect: no such file or directory"

Fix:

bash
sudo systemctl restart containerd
sudo systemctl restart kubelet    # kubelet needs to re-establish the CRI connection

If containerd keeps crashing, check for a corrupted state directory:

bash
sudo systemctl stop containerd
sudo mv /var/lib/containerd /var/lib/containerd.bak
sudo systemctl start containerd    # Recreates a clean state — existing containers are lost on this node

Cause 4: Network Plugin (CNI) Failure

bash
# kubelet logs show this when CNI isn't ready:
# "container runtime network not ready: NetworkReady=false
#  reason:NetworkPluginNotReady message:Network plugin returns error:
#  cni plugin not initialized"
 
# Check the CNI daemonset (varies by plugin — this example is Cilium)
kubectl get pods -n kube-system -l k8s-app=cilium -o wide | grep worker-3
kubectl logs -n kube-system cilium-xxxxx --previous

Fix — restart the CNI pod on the affected node:

bash
kubectl delete pod -n kube-system cilium-xxxxx
# The daemonset controller recreates it automatically

If the CNI config file is missing or corrupted on the node itself:

bash
ls /etc/cni/net.d/
# Should contain a config like 05-cilium.conflist — if empty, the CNI
# daemonset never successfully wrote its config on this node
 
# Usually fixed by deleting and letting the daemonset pod reschedule

Quick Diagnostic Checklist

bash
# Run these in order — stop at whichever one shows the problem
kubectl describe node NODE_NAME | grep -A 10 "Conditions:"
ssh NODE_NAME "sudo systemctl status kubelet containerd"
ssh NODE_NAME "df -h /var/lib/kubelet"
ssh NODE_NAME "sudo journalctl -u kubelet -n 50 --no-pager"
kubectl get pods -n kube-system -o wide | grep NODE_NAME

If Nothing Works: Cordon and Drain

bash
# Stop new pods scheduling here while you investigate further,
# and safely move existing workloads off
kubectl cordon worker-3
kubectl drain worker-3 --ignore-daemonsets --delete-emptydir-data
 
# Once fixed and Ready again:
kubectl uncordon worker-3

More Kubernetes troubleshooting? Read our Kubernetes CrashLoopBackOff fix and Kubernetes evicted pods disk pressure fix.

🔧

Today I Fixed

Short real fixes from production — posted daily

Browse fixes
Newsletter

Stay ahead of the curve

Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.

Related Articles

Comments