CKA — Troubleshoot Pods
CKA Exam Domain
| Domain | Weight |
|---|---|
| Troubleshooting | 30% |
Pod troubleshooting is the bread and butter of the CKA exam. Almost every troubleshooting question starts with a Pod that isn’t behaving correctly. You need to identify the status, find the root cause, and fix it — fast.
Pod Troubleshooting Flow
Every Pod issue follows the same debugging flow. Memorize this:
kubectl get pods → Check STATUS → kubectl describe pod → kubectl logs → kubectl exec
- See the problem —
kubectl get podsshows the current status - Get details —
kubectl describe pod <pod>shows events and configuration - Read logs —
kubectl logs <pod>shows application output - Get inside —
kubectl exec -it <pod> -- /bin/shfor interactive debugging
Exam Tip: Start with
kubectl get pods -o wideto get the Pod status, node placement, and IP address all at once. This saves time in the exam.
CrashLoopBackOff
What It Means
CrashLoopBackOff means your container starts, crashes, and Kubernetes restarts it with an exponentially increasing backoff delay (10s, 20s, 40s, up to 5 minutes).
NAME READY STATUS RESTARTS AGE
my-app 0/1 CrashLoopBackOff 5 (2m ago) 8m
Common Causes
- Wrong command or arguments — The container’s
commandorargsfield references a binary or script that doesn’t exist - Missing configuration — The app expects environment variables, ConfigMaps, or Secrets that aren’t present
- Application error — The code itself crashes on startup (null pointer, missing dependency, port conflict)
- Liveness probe failure — The liveness probe keeps killing the container because it can’t respond in time
Debugging Steps
# Step 1: Check the logs of the current crash
kubectl logs my-app
# Step 2: Check logs from the PREVIOUS crash (crucial for CrashLoopBackOff!)
kubectl logs my-app --previous
# Step 3: Describe the Pod to see events and config
kubectl describe pod my-app
# Step 4: For multi-container Pods, specify the container
kubectl logs my-app -c sidecar-container
Example Fix
# BROKEN — wrong command
spec:
containers:
- name: app
image: nginx
command: ["/bin/start-app"] # doesn't exist in nginx image
# FIXED — remove the wrong command, let the image's default CMD run
spec:
containers:
- name: app
image: nginx
# command removed — uses default nginx entrypoint
ImagePullBackOff & ErrImagePull
What It Means
Kubernetes can’t pull the container image. ErrImagePull is the initial failure; ImagePullBackOff means it’s retrying with backoff.
NAME READY STATUS RESTARTS AGE
my-app 0/1 ImagePullBackOff 0 3m
Common Causes
- Wrong image name — Typo in the image name (
ngingxinstead ofnginx) - Wrong tag — The specified tag doesn’t exist (
nginx:1.99.0) - Private registry — The registry requires authentication but no
imagePullSecretsis configured - Network issues — The node can’t reach the container registry
Debugging Steps
# Always start with describe — the Events section tells you exactly what's wrong
kubectl describe pod my-app
Look at the Events section at the bottom:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 1m default-scheduler Successfully assigned default/my-app to node01
Normal Pulling 1m kubelet Pulling image "ngingx:latest"
Warning Failed 1m kubelet Failed to pull image "ngingx:latest": rpc error: ...
Warning Failed 1m kubelet Error: ErrImagePull
Normal BackOff 30s kubelet Back-off pulling image "ngingx:latest"
Warning Failed 30s kubelet Error: ImagePullBackOff
Fix: Wrong Image Name
kubectl edit pod my-app
# Fix the image name from "ngingx" to "nginx"
Or delete and recreate with the correct image.
Fix: Private Registry
# Create the imagePullSecret
kubectl create secret docker-registry regcred \
--docker-server=registry.example.com \
--docker-username=user \
--docker-password=pass
# Reference it in the Pod spec
spec:
imagePullSecrets:
- name: regcred
containers:
- name: app
image: registry.example.com/my-app:v1
Pending Pods
What It Means
The Pod has been accepted by the cluster but can’t be scheduled to a node.
NAME READY STATUS RESTARTS AGE
my-app 0/1 Pending 0 5m
Common Causes
- Insufficient resources — CPU/memory requests exceed what’s available on any node
- No matching node —
nodeSelector, node affinity, or taints prevent scheduling - PVC not bound — The Pod references a PersistentVolumeClaim that isn’t bound
Debugging Steps
kubectl describe pod my-app
Check the Events section for FailedScheduling:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 1m default-scheduler 0/3 nodes are available:
1 Insufficient cpu, 2 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: }
Fix: Resource Issue
# Check what resources the node has available
kubectl describe node <node-name> | grep -A 5 "Allocated resources"
# Option 1: Reduce the Pod's resource requests
# Option 2: Add more nodes to the cluster
Fix: Taint/Toleration Issue
# Check taints on nodes
kubectl describe node <node-name> | grep Taints
# Add toleration to the Pod, or remove the taint from the node
kubectl taint nodes <node-name> key=value:NoSchedule-
Fix: PVC Issue
# Check the PVC status
kubectl get pvc
# If the PVC is Pending, check if a matching PV exists
kubectl get pv
OOMKilled
What It Means
The container exceeded its memory limit and was killed by the Linux OOM (Out of Memory) killer.
NAME READY STATUS RESTARTS AGE
my-app 0/1 OOMKilled 3 (1m ago) 5m
Debugging Steps
kubectl describe pod my-app
Look for the Last State section:
Last State: Terminated
Reason: OOMKilled
Exit Code: 137
Fix
# Increase the memory limit
spec:
containers:
- name: app
image: my-app:v1
resources:
requests:
memory: "128Mi"
limits:
memory: "512Mi" # increase this if the app genuinely needs more
Exam Tip: Exit code 137 = OOMKilled (128 + signal 9 SIGKILL). Exit code 143 = graceful termination (128 + signal 15 SIGTERM). Know these codes!
Pod Status Reference
| Status | Meaning |
|---|---|
| Running | Pod is running normally, all containers are up |
| Pending | Pod is accepted but not scheduled (resource/scheduling issue) |
| Succeeded | All containers completed successfully (common for Jobs) |
| Failed | All containers terminated, at least one with failure |
| CrashLoopBackOff | Container keeps crashing, restarts with exponential backoff |
| ImagePullBackOff | Can’t pull the container image, retrying with backoff |
| ErrImagePull | Initial failure to pull the container image |
| ContainerCreating | Image pulled, container being set up (may indicate volume/network issue if stuck) |
| Terminating | Pod is being deleted (may hang if finalizers or preStop hooks are slow) |
| Init:Error | An init container failed |
| Init:CrashLoopBackOff | An init container keeps crashing |
Essential Debugging Commands
# Get all Pods with details
kubectl get pods -o wide
kubectl get pods -A -o wide # all namespaces
# Describe a Pod — events, config, conditions
kubectl describe pod <pod>
kubectl describe pod <pod> -n <namespace>
# Logs — application output
kubectl logs <pod>
kubectl logs <pod> --previous # previous crashed container
kubectl logs <pod> -c <container> # specific container
kubectl logs <pod> --tail=50 # last 50 lines
kubectl logs <pod> -f # follow/stream
# Execute into a container
kubectl exec -it <pod> -- /bin/sh
kubectl exec -it <pod> -c <container> -- /bin/sh
# Events — cluster-wide debugging
kubectl get events --sort-by=.metadata.creationTimestamp
kubectl get events --field-selector involvedObject.name=<pod>
Practice Questions
Q1. A Pod named web-app in the default namespace is in CrashLoopBackOff. Diagnose and fix it.
Show Answer
# Step 1: Check the Pod status
kubectl get pod web-app
# Step 2: Check the logs (and previous logs)
kubectl logs web-app
kubectl logs web-app --previous
# Step 3: Describe the Pod for events and config
kubectl describe pod web-app
# Common fix: If it's a wrong command, edit the Pod spec
# You may need to delete and recreate since Pod specs are mostly immutable
kubectl get pod web-app -o yaml > web-app.yaml
# Edit web-app.yaml to fix the issue
kubectl delete pod web-app
kubectl apply -f web-app.yaml
The key is reading the logs — they almost always tell you exactly what’s wrong.
Q2. A Pod is stuck in ImagePullBackOff. The image is my-registry.io/app:v2. What do you check?
Show Answer
# Step 1: Describe the Pod to see the exact error
kubectl describe pod <pod-name>
# Look at Events — it will say something like:
# "Failed to pull image: unauthorized" → needs imagePullSecrets
# "Failed to pull image: not found" → wrong image name/tag
# Step 2: If it needs authentication
kubectl create secret docker-registry regcred \
--docker-server=my-registry.io \
--docker-username=<user> \
--docker-password=<pass>
# Step 3: Add imagePullSecrets to the Pod spec or patch the deployment
kubectl patch deployment <deploy> -p '{"spec":{"template":{"spec":{"imagePullSecrets":[{"name":"regcred"}]}}}}'
Q3. A Pod named data-processor has been Pending for 10 minutes. There are 3 worker nodes in the cluster. Find out why and fix it.
Show Answer
# Step 1: Check why it's pending
kubectl describe pod data-processor
# Look for FailedScheduling event. Common reasons:
# "Insufficient cpu" — requests too high
# "node(s) had untolerated taint" — needs toleration
# "node(s) didn't match Pod's node affinity/selector" — wrong label
# Step 2: Check nodes
kubectl describe nodes | grep -A 5 "Allocated resources"
kubectl get nodes --show-labels
# Step 3: Fix based on root cause
# For resource issue: reduce requests or add nodes
# For taint: add toleration or remove taint
# For nodeSelector: fix label or update selector
Q4. A Deployment’s Pods are showing OOMKilled with exit code 137. The current memory limit is 64Mi. Fix it.
Show Answer
# Step 1: Verify the OOMKilled status
kubectl describe pod <pod-name>
# Look for Last State: Terminated, Reason: OOMKilled
# Step 2: Increase the memory limit in the Deployment
kubectl edit deployment <deployment-name>
# Change spec.containers[].resources.limits.memory to a higher value, e.g., "256Mi"
# Or use kubectl set:
kubectl set resources deployment <deployment-name> --limits=memory=256Mi
# Step 3: Verify the new Pods are running
kubectl get pods -w
Q5. A multi-container Pod named logger has two containers: app and sidecar. The app container is running but the sidecar is in CrashLoopBackOff. Get the logs for the crashing container.
Show Answer
# Step 1: Check which container is failing
kubectl get pod logger
# Output shows READY 1/2 — one of two containers is not ready
# Step 2: Get logs for the specific container
kubectl logs logger -c sidecar
kubectl logs logger -c sidecar --previous
# Step 3: Describe the Pod to see container-specific events
kubectl describe pod logger
# Look at the "sidecar" container section for State and Last State
# Step 4: Fix based on what the logs reveal
# Export, edit, delete, and recreate if needed
kubectl get pod logger -o yaml > logger.yaml
# Fix the sidecar container spec
kubectl delete pod logger
kubectl apply -f logger.yaml
What’s Next
Pod issues are the most common troubleshooting scenario, but sometimes the problem isn’t the Pod — it’s the node. Next, we’ll learn how to diagnose and fix node-level issues.