Happy Dussehra! May good always win. Happy Diwali! Wishing you a bright year ahead. Merry Christmas! Warm wishes from Vizag. Happy New Year! Here’s to a great year ahead.

Archive ยท Kubernetes

Troubleshooting Pods: A Short Checklist

A decision-tree approach to Pending, ImagePullBackOff, CrashLoopBackOff, OOMKilled, probe failures and stuck Terminating pods, with the exact kubectl commands to use.

4 min read

  • Kubernetes 1.23
  • kubectl 1.23
  • kubectl debug
  • ephemeral containers

When a pod misbehaves, the status column tells you which part of the system to look at. Memorise the status-to-cause mapping and you will fix most problems in a few commands, without guessing.

Versions in use on this date. Kubernetes and kubectl 1.23. In 1.23, ephemeral containers and kubectl debug are beta and enabled by default, which makes debugging minimal images much easier.

Start from the status

flowchart TB
  S[kubectl get pods] --> ST{STATUS}
  ST -->|Pending| P1[Scheduling - describe pod Events]
  ST -->|ContainerCreating| P2[Volumes, secrets, network setup]
  ST -->|ImagePullBackOff or ErrImagePull| P3[Image name tag registry credentials]
  ST -->|CreateContainerConfigError| P4[Missing ConfigMap or Secret key]
  ST -->|CrashLoopBackOff| P5[App exits - logs --previous]
  ST -->|Running but not Ready| P6[Readiness probe or app port]
  ST -->|OOMKilled or Error 137| P7[Memory limit too low or leak]
  ST -->|Evicted| P8[Node pressure disk memory]
  ST -->|Terminating forever| P9[Finalizers or node gone]
  ST -->|Completed| P10[Normal for Jobs]

First three commands, always

kubectl get pod web-abc -o wide                         # node, IP, restarts, age
kubectl describe pod web-abc                            # Events at the bottom: the most useful lines
kubectl logs web-abc --all-containers --previous        # logs of the crashed attempt (omit --previous if running)
kubectl get events --sort-by=.lastTimestamp -n shop | tail -20

Pending

The scheduler cannot place the pod. describe shows a line like 0/5 nodes are available: 3 Insufficient cpu, 2 node(s) had taint {...} that the pod didn't tolerate.

  • Insufficient cpu/memory: requests too large for any node, or the cluster is full. kubectl describe nodes | grep -A5 "Allocated resources"; scale nodes (Cluster Autoscaler) or lower requests.
  • Taints and tolerations / node selectors / affinity: the pod demands labels or tolerations no node has.
  • PVC not bound: kubectl get pvc; wrong StorageClass, or a zonal volume in a different zone from available nodes.
  • ResourceQuota exceeded: kubectl describe quota -n shop.

ImagePullBackOff

kubectl describe pod web-abc | grep -A3 -i "failed to pull"
kubectl get pod web-abc -o jsonpath='{.spec.containers[*].image}'
kubectl get secret regcred -n shop      # imagePullSecrets present in the same namespace?

Typos in the tag, a private registry without imagePullSecrets, expired ECR tokens on nodes without the correct IAM role, Docker Hub rate limits (toomanyrequests), or network egress blocked to the registry.

CrashLoopBackOff

The container starts, exits, and Kubernetes restarts it with increasing back-off.

kubectl logs web-abc --previous --tail=100
kubectl get pod web-abc -o jsonpath='{.status.containerStatuses[0].lastState}'    # exit code and reason
kubectl describe pod web-abc | grep -A8 "Last State"
Exit code / reason Meaning
1 or 2 Application error: read the log
126 / 127 Command not executable / not found (wrong command or image)
137 (OOMKilled) Killed for memory; raise the limit or fix the leak
139 Segmentation fault
143 SIGTERM (normal stop)

Also check configuration: missing environment variables, wrong database URL, permissions on mounted files (non-root user and read-only filesystem), and a liveness probe killing a slow-starting app (add a startup probe).

Running but not Ready / no traffic

kubectl describe pod web-abc | grep -A3 -i "readiness"
kubectl get endpointslices -l kubernetes.io/service-name=web
kubectl port-forward pod/web-abc 8080:8080 & curl -i localhost:8080/healthz
kubectl get svc web -o jsonpath='{.spec.selector}'; kubectl get pod web-abc --show-labels

Wrong probe path or port, app listening on 127.0.0.1 only, Service selector not matching pod labels, a NetworkPolicy blocking the kubelet or the ingress.

Debug inside a minimal container

kubectl exec -it web-abc -- sh                        # if the image has a shell
kubectl debug -it web-abc --image=busybox:1.35 --target=web            # ephemeral container sharing the process namespace
kubectl debug web-abc -it --copy-to=web-debug --container=web -- sh    # copy of the pod with a different command
kubectl debug node/ip-10-0-1-5.ap-south-1.compute.internal -it --image=ubuntu:22.04     # shell on a node

Use nslookup, curl, nc -zv from there to test DNS and connectivity exactly as the pod sees it. Delete debug copies afterwards.

Terminating that never ends

kubectl get pod web-abc -o jsonpath='{.metadata.finalizers}'
kubectl delete pod web-abc --grace-period=0 --force        # last resort; may leave processes if the node is alive

A pod on an unreachable node stays Terminating until the node returns or is removed. Finalizers waiting for a controller (storage, custom resources) need the controller fixed rather than patched away.

Node-level causes

kubectl get nodes
kubectl describe node worker-3 | sed -n '/Conditions/,/Addresses/p'      # MemoryPressure DiskPressure PIDPressure Ready
kubectl top nodes; kubectl top pods -A --sort-by=memory | head

NotReady nodes point to kubelet, runtime or network problems: check kubelet logs (journalctl -u kubelet), container runtime status (crictl ps), disk space and the CNI.

Habit that saves time

Record what you see (status, events, exit code) before changing anything, change one thing at a time, and capture the fix in a runbook or an alert annotation so the next on-call engineer starts one step ahead.