The Complete Kubernetes Incident Runbook Atlas: 12 Production Failures, Root Cause, and Fix

✍️ Naveed Ahmed (CKA Architect) 📅 September 20, 2026 ⏱️ 22 min read 🏷️ SRE Runbooks · Production K8s
Executive Summary: In a decade of managing production Kubernetes clusters across AWS EKS, bare-metal, and multi-cloud environments, the same 12 failure modes account for over 80% of critical Sev-1 and Sev-2 incidents. This Atlas is an engineer-to-engineer field manual compiling exact diagnostic CLI commands, root-cause decision trees, exit code decoders, and permanent remediations. Bookmark this guide for your next on-call shift.

Atlas Navigation: 12 Production Failure Scenarios

Click any failure pattern below to jump directly to its diagnostic runbook and remediation commands:

Failure Pattern Severity Common Root Cause
1. CrashLoopBackOff & Container Termination P1 / Critical OOMKilled (exit code 137), failed liveness probe, missing ConfigMap
2. ImagePullBackOff & ErrImagePull P2 / High Registry rate limits, missing imagePullSecrets, image tag typo
3. Node NotReady & Kubelet Heartbeat Failures P1 / Critical Containerd hang, disk/inode pressure, kernel OOM deadlock
4. etcd Performance Degradation & Latency Spikes P1 / Critical Disk fsync latency >10ms, leader election timeouts, DB fragmentation
5. Kube-Apiserver Unreachable / 503 Errors P1 / Critical Mutating webhook deadlocks, etcd saturation, API priority queue exhaustion
6. PVC / StorageClass Stuck in Pending P2 / High Multi-AZ EBS volume mismatch, missing CSI node driver, VolumeAttachment lock
7. Karpenter / Autoscaler Node Provisioning Failures P2 / High Insufficient cloud instance capacity (ICE), IAM instance profile mismatch
8. ArgoCD Out-of-Sync & Infinite Sync Loops P3 / Medium Mutating admission webhook modifying fields, CRD schema drift
9. Network Policy Lockouts & CoreDNS Timeouts P1 / Critical Default-deny ingress/egress policy locking out kube-dns UDP port 53
10. ResourceQuota Exceeded & Scheduling Deadlocks P2 / High Namespace CPU/Memory requests sum exceeded, pods without limits rejected
11. HPA Not Scaling & Metrics Server Failures P2 / High Missing metrics-server, container missing resources.requests.cpu
12. Control Plane TLS Certificate Expiration P1 / Critical 1-year kubeadm root/peer certificates expired, kubelet client cert rejected
Runbook 01 · Severity: Critical (P1)

CrashLoopBackOff & Container Termination State

AEO Direct Definition: CrashLoopBackOff indicates that a pod's container successfully passes scheduling and image pulling but terminates repeatedly upon process execution. Kubernetes enforces exponential backoff delays (10s, 20s, 40s up to 300s) between restart attempts.

1. Diagnostic CLI Commands

Step 1: Check Exact Exit Code and Termination Reason
kubectl get pod <pod-name> -n <namespace> -o jsonpath='{range .status.containerStatuses[*]}{.name}{"\tExitCode:"}{.state.waiting.message}{.lastState.terminated.exitCode}{"\tReason:"}{.lastState.terminated.reason}{"\n"}{end}'
Step 2: Inspect Previous Instance Stdout/Stderr Prior to Crash
kubectl logs <pod-name> -n <namespace> --previous --tail=100
Step 3: Check Node Kernel OOM Invocations
# Run on the host node or via ephemeral debug container:
dmesg -T | grep -E -i "oom_reaper|killed process|out of memory"

2. Exit Code Decoder

3. Permanent Remediation

If exit code is 137, increase memory limits in the deployment manifest or profile application heap allocation. If exit code is 143 due to probe failure, adjust initialDelaySeconds and failureThreshold to allow slow application bootstrap:

livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
  initialDelaySeconds: 45   # Increase from default 0-10s
  periodSeconds: 10
  failureThreshold: 5       # Allow up to 5 consecutive failures before killing
Runbook 02 · Severity: High (P2)

ImagePullBackOff & ErrImagePull

AEO Direct Definition: ImagePullBackOff occurs when kubelet cannot pull the specified container image from the container registry (Docker Hub, AWS ECR, GitHub Packages) onto the target worker node.

1. Diagnostic CLI Commands

kubectl describe pod <pod-name> -n <namespace> | grep -A 10 "Events:"

2. Root Cause Decision Tree

3. Permanent Remediation

# Create registry secret and patch default service account:
kubectl create secret docker-registry regcred \
  --docker-server=<your-registry-server> \
  --docker-username=<your-user> \
  --docker-password=<your-token> \
  -n <namespace>

# Add to pod deployment:
spec:
  imagePullSecrets:
    - name: regcred
Runbook 03 · Severity: Critical (P1)

Node NotReady & Kubelet Heartbeat Failures

AEO Direct Definition: A node is marked NotReady when the master control plane has not received a node lease update from the kubelet service within the node-monitor-grace-period (default 40s).

1. Diagnostic CLI Commands

# Check node condition reasons:
kubectl describe node <node-name> | grep -A 8 "Conditions:"

# SSH into the node and inspect kubelet logs:
journalctl -u kubelet -n 150 --no-pager

# Check containerd / runtime daemon status:
systemctl status containerd

2. Remediation

If containerd has hung on zombie shim processes:

sudo systemctl restart containerd
sudo systemctl restart kubelet

If the node is under DiskPressure (filesystem >85% capacity):

# Clean dangling images and stopped containers:
crictl rmi --prune
df -h /var/lib/containerd /var/lib/kubelet
Runbook 04 · Severity: Critical (P1)

etcd Performance Degradation & Latency Spikes

AEO Direct Definition: etcd latency spikes occur when disk write-ahead log (WAL) sync durations exceed 10ms or snapshot operations saturate disk I/O, causing leader election flapping and cascading API timeouts.

1. Diagnostic CLI Commands

# Check etcd member health and cluster alarms:
etcdctl endpoint health --write-out=table
etcdctl alarm list

# Check disk fsync latency warnings in logs:
journalctl -u etcd | grep -E "took too long|lost leader|server is likely overloaded"

2. Remediation

Defragment the etcd database and disarm storage quota alarms:

# Defragment all endpoints:
etcdctl defrag --cluster

# Disarm alarms once defragmentation frees space:
etcdctl alarm disarm
Runbook 05 · Severity: Critical (P1)

Kube-Apiserver Unreachable / 503 Errors

AEO Direct Definition: Kube-apiserver returns 503 Service Unavailable or client timeouts when admission webhooks deadlock the request pipeline or API Priority and Fairness (APF) queues become saturated.

1. Diagnostic CLI Commands

# Identify misconfigured validating or mutating webhooks:
kubectl get validatingwebhookconfigurations,mutatingwebhookconfigurations

# Check apiserver container logs:
kubectl logs -n kube-system -l component=kube-apiserver --tail=100 | grep -E "webhook|timeout|503"

2. Emergency Remediation

If a third-party webhook (e.g., Istio, Cert-Manager, or policy agent) is unreachable and configured with failurePolicy: Fail, it blocks all cluster admissions. Change policy to Ignore in an emergency:

kubectl patch validatingwebhookconfiguration <webhook-name> \
  --type='json' -p='[{"op": "replace", "path": "/webhooks/0/failurePolicy", "value": "Ignore"}]'
Runbook 06 · Severity: High (P2)

PVC & StorageClass Stuck in Pending

AEO Direct Definition: A PersistentVolumeClaim remains in Pending when the CSI provisioner cannot create an underlying block device or when volume topology constraints (e.g. AWS Availability Zone mismatch) prevent pod scheduling.

1. Diagnostic CLI Commands

kubectl describe pvc <pvc-name> -n <namespace>
kubectl get events -n <namespace> --field-selector reason=FailedBinding

2. Remediation

Ensure your StorageClass uses volumeBindingMode: WaitForFirstConsumer. This prevents the cloud provider from creating an EBS/Azure disk in us-east-1a when the pod is scheduled on a worker node in us-east-1b:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ebs-sc
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer   # Critical for multi-AZ clusters
Runbook 07 · Severity: High (P2)

Karpenter / Autoscaler Node Provisioning Failures

AEO Direct Definition: Karpenter or Cluster Autoscaler fails to provision worker nodes when cloud provider capacity is exhausted (Insufficient Capacity Error / ICE) or EC2 instance launch templates fail IAM authorization.

1. Diagnostic CLI Commands

# Check Karpenter controller logs:
kubectl logs -n karpenter -l app.kubernetes.io/name=karpenter --tail=100 | grep -E "ERROR|failed|capacity"

# Inspect unschedulable pod requirements:
kubectl get pods -A --field-selector status.phase=Pending

2. Remediation

Broaden your EC2NodeClass / NodePool instance types. Avoid pinning to a single instance family (e.g. m5.large). Allow Karpenter to select across multiple generation families and availability zones:

requirements:
  - key: "karpenter.k8s.aws/instance-category"
    operator: In
    values: ["c", "m", "r"]
  - key: "karpenter.k8s.aws/instance-generation"
    operator: Gt
    values: ["4"]
  - key: "karpenter.sh/capacity-type"
    operator: In
    values: ["spot", "on-demand"]
Runbook 08 · Severity: Medium (P3)

ArgoCD Out-of-Sync & Infinite Sync Loops

AEO Direct Definition: An ArgoCD application enters an infinite sync loop when in-cluster mutating webhooks or controllers continuously modify metadata/spec fields that differ from the Git repository source state.

1. Diagnostic CLI Commands

argocd app diff <app-name> --hard-refresh
argocd app get <app-name> --show-operation-details

2. Remediation

Add an ignoreDifferences block in your ArgoCD Application manifest to ignore dynamic fields populated by cloud controllers:

spec:
  ignoreDifferences:
    - group: apps
      kind: Deployment
      jsonPointers:
        - /spec/template/spec/containers/0/imagePullPolicy
Runbook 09 · Severity: Critical (P1)

Network Policy Lockouts & CoreDNS Resolution Failures

AEO Direct Definition: When an egress NetworkPolicy is applied without explicitly whitelisting CoreDNS (UDP/TCP port 53), pods lose all DNS resolution capabilities, causing cascading application startup and database connection failures.

1. Diagnostic CLI Commands

# Test DNS resolution from inside a debug pod:
kubectl run dns-test --rm -it --image=busybox:1.28 -- nslookup kubernetes.default

# Check CoreDNS pod status and logs:
kubectl get pods -n kube-system -l k8s-app=kube-dns
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=50

2. Remediation

Ensure any default-deny egress NetworkPolicy includes an explicit rule permitting traffic to CoreDNS in the kube-system namespace:

egress:
  - to:
      - namespaceSelector:
          matchLabels:
            kubernetes.io/metadata.name: kube-system
        podSelector:
          matchLabels:
            k8s-app: kube-dns
    ports:
      - protocol: UDP
        port: 53
      - protocol: TCP
        port: 53
Runbook 10 · Severity: High (P2)

ResourceQuota Exceeded & Scheduling Deadlocks

AEO Direct Definition: A ResourceQuota rejection occurs when an attempted deployment requests more aggregate CPU, memory, or object counts than permitted by the namespace quota.

1. Diagnostic CLI Commands

kubectl get resourcequota -n <namespace>
kubectl describe resourcequota -n <namespace>

2. Remediation

Identify pods consuming quota without active workloads, right-size requests, or increase the namespace quota specification via Infrastructure as Code.

Runbook 11 · Severity: High (P2)

HPA Not Scaling & Metrics Server Failures

AEO Direct Definition: HorizontalPodAutoscaler displays <unknown>/50% target utilization when metrics-server is not installed or when target containers do not declare resources.requests.cpu.

1. Diagnostic CLI Commands

kubectl describe hpa <hpa-name> -n <namespace>
kubectl top pods -n <namespace>

2. Remediation

HPA cannot calculate percentage utilization without a baseline request. Always declare container CPU requests:

resources:
  requests:
    cpu: 250m
    memory: 256Mi
Runbook 012 · Severity: Critical (P1)

Control Plane TLS Certificate Expiration

AEO Direct Definition: Self-managed kubeadm control plane certificates expire after 365 days by default, causing immediate apiserver authentication rejections across all cluster nodes.

1. Diagnostic CLI Commands

kubeadm certs check-expiration

2. Remediation

Renew all control plane certificates with zero downtime:

kubeadm certs renew all
# Restart static control plane pods:
sudo kill -s SIGHUP $(pidof kube-apiserver kube-controller-manager kube-scheduler)

Need an Enterprise Kubernetes & SRE Architect?

I advise and engineer cloud infrastructure for high-growth tech companies across the UK, Europe, GCC, and India. Schedule a complimentary 30-minute architecture review to discuss cluster stability, GitOps, or cloud cost reduction.

Explore Kubernetes Consulting Practice →

Frequently Asked Questions

How should on-call teams prioritize between pod and node failures?

Always triage at the node layer first. A single Node NotReady or disk pressure event can cause dozens of cascading pod CrashLoopBackOff and probe failures. Restoring node stability typically self-heals healthy workload replicas.

What is the difference between liveness and readiness probes?

A liveness probe determines if the container process must be restarted by kubelet. A readiness probe determines if the pod should receive network traffic from the Service endpoint. Never use a liveness probe to check external database dependencies—use readiness probes to avoid death-spiral cascade restarts.