← Back to docs

Kubernetes Troubleshooting Runbook

Production-ready runbook for diagnosing and resolving common Kubernetes issues: CrashLoopBackOff, pending pods, OOM kills, networking, and more.


Overview

This runbook covers the most common Kubernetes production issues and their resolution paths. Designed to be followed at 3am when something is on fire.

Quick Reference: First 60 Seconds

# Cluster health
kubectl get nodes
kubectl top nodes

# Namespace overview
kubectl get pods -n <namespace> --sort-by='.status.startTime'
kubectl get events -n <namespace> --sort-by='.lastTimestamp' | tail -20

# Problem pod
kubectl describe pod <pod> -n <namespace>
kubectl logs <pod> -n <namespace> --tail=100
kubectl logs <pod> -n <namespace> --previous  # previous crashed container

Issue: CrashLoopBackOff

Symptoms: Pod keeps restarting, back-off delay increasing.

Diagnosis:

kubectl describe pod <pod> -n <ns>
# Look at: Exit Code, Reason, Last State

kubectl logs <pod> -n <ns> --previous
# Shows logs from the crashed container

Common Causes & Fixes:

Exit CodeMeaningFix
1Application errorCheck app logs, fix the bug
137OOM KilledIncrease resources.limits.memory
143SIGTERM (graceful)Check readiness probe, increase terminationGracePeriodSeconds
126Permission deniedCheck container user, file permissions
127Command not foundCheck image, entrypoint, PATH

Issue: Pod Stuck in Pending

Diagnosis:

kubectl describe pod <pod> -n <ns>
# Look at Events section for scheduling failures

Common Causes:

Event MessageCauseFix
Insufficient cpu/memoryCluster out of resourcesScale nodes or reduce requests
no nodes available to scheduleNode selector/affinity mismatchCheck nodeSelector, tolerations
persistentvolumeclaim not foundPVC not boundCheck StorageClass, PVC status
0/N nodes are available: taintTaints blocking schedulingAdd tolerations or remove taint
# Check node resources
kubectl describe nodes | grep -A5 "Allocated resources"

# Check PVC
kubectl get pvc -n <ns>

Issue: OOMKilled (Exit Code 137)

Diagnosis:

kubectl describe pod <pod> -n <ns> | grep -A3 "Last State"
# Reason: OOMKilled

kubectl top pod <pod> -n <ns>

Fix:

  1. Increase memory limits:
resources:
  requests:
    memory: "256Mi"
  limits:
    memory: "512Mi"  # Increase this
  1. If the app genuinely needs more memory, profile it (heap dump, pprof).
  2. If it's a memory leak, fix the application code.

Prevention: Set up alerts on container_memory_working_set_bytes / container_spec_memory_limit_bytes > 0.8.


Issue: Service Not Reachable

Diagnosis flow:

# 1. Is the pod running?
kubectl get pods -l app=<app> -n <ns>

# 2. Is the service pointing to the pod?
kubectl get endpoints <service> -n <ns>
# If empty → labels don't match

# 3. Can you reach from inside the cluster?
kubectl run tmp --rm -it --image=busybox -- wget -qO- http://<service>.<ns>.svc:port

# 4. Is Ingress configured?
kubectl describe ingress <ingress> -n <ns>

Common Issues:

ProblemCheck
No endpointsService selector doesn't match pod labels
Connection refusedPod is up but app not listening on expected port
502/504 from IngressPod failing health checks → Ingress removes it
DNS not resolvingCoreDNS pods healthy? kubectl get pods -n kube-system -l k8s-app=kube-dns

Issue: ImagePullBackOff

kubectl describe pod <pod> -n <ns>
# Look for: Failed to pull image

Fixes:

CauseFix
Image doesn't existCheck tag, repo URL
Private registry, no authCreate imagePullSecret, reference in pod spec
Rate limited (Docker Hub)Use authenticated pulls or mirror to private registry
Wrong platform (arm64 vs amd64)Build multi-arch or specify correct image

Issue: High Pod Restart Count

# Find pods with high restart counts
kubectl get pods -n <ns> --sort-by='.status.containerStatuses[0].restartCount'

# Check why
kubectl describe pod <pod> -n <ns>
kubectl logs <pod> -n <ns> --previous

Common pattern: Liveness probe failing → kubelet kills the pod → restarts.

Fix: Tune liveness probe (increase initialDelaySeconds, timeoutSeconds, failureThreshold). Make sure the probe endpoint is lightweight.


Issue: Node NotReady

kubectl get nodes
kubectl describe node <node>

# Check kubelet
# (SSH to node)
systemctl status kubelet
journalctl -u kubelet --since "10 minutes ago"

Common Causes:

  • Kubelet crashed or resource exhaustion
  • Network partition (node can't reach API server)
  • Disk pressure (kubectl describe node → Conditions)
  • Certificate expiry

Issue: Deployment Not Rolling Out

kubectl rollout status deployment/<name> -n <ns>
kubectl describe deployment <name> -n <ns>
kubectl get replicasets -n <ns> -l app=<app>

Common causes:

  • New pods failing health checks → old pods stay, new pods don't become Ready
  • maxUnavailable: 0 + no extra capacity → deadlock
  • Resource quota exceeded in namespace

Useful Aliases

alias k=kubectl
alias kgp='kubectl get pods'
alias kgn='kubectl get nodes'
alias kdp='kubectl describe pod'
alias kl='kubectl logs'
alias klp='kubectl logs --previous'
alias ktp='kubectl top pods'
alias ktn='kubectl top nodes'

Monitoring Queries (Prometheus)

# Pods in CrashLoopBackOff
kube_pod_container_status_waiting_reason{reason="CrashLoopBackOff"} > 0

# OOM kills
kube_pod_container_status_last_terminated_reason{reason="OOMKilled"} > 0

# Pending pods
kube_pod_status_phase{phase="Pending"} > 0

# High restart count
kube_pod_container_status_restarts_total > 5

# Node not ready
kube_node_status_condition{condition="Ready",status="true"} == 0

Reactions & comments