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.
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
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 KubeletNotReadyThe 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
# 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-pagerCommon kubelet crash reasons: certificate expired, disk full so it can't write logs, or a config change that wasn't applied cluster-wide.
# 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-expirationFix — renew certs and restart:
sudo kubeadm certs renew all
sudo systemctl restart kubeletCause 2: Disk Pressure
df -h /var/lib/kubelet /var/lib/containerd
# If /var is above ~85%, kubelet marks DiskPressure=True and stops schedulingUsually this is unpruned container images and dangling volumes.
# 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 --volumesFix — set a garbage collection threshold so this doesn't recur:
# kubelet config
evictionHard:
nodefs.available: "10%"
imagefs.available: "15%"
imageGCHighThresholdPercent: 80
imageGCLowThresholdPercent: 70Cause 3: Container Runtime Down (containerd/CRI-O)
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:
sudo systemctl restart containerd
sudo systemctl restart kubelet # kubelet needs to re-establish the CRI connectionIf containerd keeps crashing, check for a corrupted state directory:
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 nodeCause 4: Network Plugin (CNI) Failure
# 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 --previousFix — restart the CNI pod on the affected node:
kubectl delete pod -n kube-system cilium-xxxxx
# The daemonset controller recreates it automaticallyIf the CNI config file is missing or corrupted on the node itself:
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 rescheduleQuick Diagnostic Checklist
# 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_NAMEIf Nothing Works: Cordon and Drain
# 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-3More Kubernetes troubleshooting? Read our Kubernetes CrashLoopBackOff fix and Kubernetes evicted pods disk pressure fix.
Today I Fixed
Short real fixes from production — posted daily
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
ArgoCD App of Apps Not Syncing — Every Fix (2026)
Your ArgoCD App of Apps pattern stopped syncing. Child apps aren't created, parent shows OutOfSync, or sync is stuck. Here are every cause and the exact fix.
ArgoCD Application Stuck Progressing: Fix in 5 Minutes
ArgoCD Application stuck in Progressing status forever, never reaching Healthy? Here is exactly how to diagnose stuck rollouts, missing health checks, hook failures, and resource hooks that never complete.
ArgoCD Image Updater Not Syncing — Fix Guide
ArgoCD Image Updater detects a new image tag but doesn't update the Application. Here's how to diagnose and fix annotation errors, registry auth issues, write-back problems, and sync failures.