Amazon EKS — Troubleshooting Hands-On Lab
In this lab you’ll intentionally break things and fix them — the best way to build troubleshooting muscle memory.
Prerequisites:
- Running EKS cluster
kubectlandawsCLI configured- A test namespace
Step 1 — Create a Test Namespace
kubectl create namespace troubleshooting-lab
Step 2 — Debug ImagePullBackOff
Deploy a pod with a wrong image name:
# broken-image.yaml
apiVersion: v1
kind: Pod
metadata:
name: broken-image
namespace: troubleshooting-lab
spec:
containers:
- name: app
image: nginx:does-not-exist-12345
ports:
- containerPort: 80
kubectl apply -f broken-image.yaml
# Watch the status
kubectl get pod broken-image -n troubleshooting-lab -w
# STATUS: ImagePullBackOff
# Diagnose
kubectl describe pod broken-image -n troubleshooting-lab | grep -A5 Events
# Fix — update the image
kubectl set image pod/broken-image app=nginx:latest -n troubleshooting-lab
# Verify
kubectl get pod broken-image -n troubleshooting-lab
# STATUS: Running
Step 3 — Debug CrashLoopBackOff
Deploy a pod that crashes immediately:
# crashing-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: crashing-pod
namespace: troubleshooting-lab
spec:
containers:
- name: app
image: busybox:latest
command: ["sh", "-c", "echo 'starting'; exit 1"]
kubectl apply -f crashing-pod.yaml
# Watch
kubectl get pod crashing-pod -n troubleshooting-lab -w
# STATUS: CrashLoopBackOff
# Check logs
kubectl logs crashing-pod -n troubleshooting-lab
# Output: starting
# Check exit code
kubectl describe pod crashing-pod -n troubleshooting-lab | grep -A5 "Last State"
# Exit Code: 1
# Fix — replace with a working command
kubectl delete pod crashing-pod -n troubleshooting-lab
# fixed-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: crashing-pod
namespace: troubleshooting-lab
spec:
containers:
- name: app
image: busybox:latest
command: ["sh", "-c", "echo 'running'; sleep 3600"]
kubectl apply -f fixed-pod.yaml
kubectl get pod crashing-pod -n troubleshooting-lab
# STATUS: Running
Step 4 — Debug Pending Pod (Resource Starvation)
Deploy a pod requesting impossible resources:
# greedy-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: greedy-pod
namespace: troubleshooting-lab
spec:
containers:
- name: app
image: nginx:latest
resources:
requests:
cpu: "100"
memory: "1000Gi"
kubectl apply -f greedy-pod.yaml
# Watch
kubectl get pod greedy-pod -n troubleshooting-lab
# STATUS: Pending
# Diagnose
kubectl describe pod greedy-pod -n troubleshooting-lab | grep -A5 Events
# 0/X nodes are available: Insufficient cpu, Insufficient memory
# Fix — reduce to reasonable values
kubectl delete pod greedy-pod -n troubleshooting-lab
# reasonable-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: greedy-pod
namespace: troubleshooting-lab
spec:
containers:
- name: app
image: nginx:latest
resources:
requests:
cpu: "100m"
memory: "128Mi"
kubectl apply -f reasonable-pod.yaml
kubectl get pod greedy-pod -n troubleshooting-lab
# STATUS: Running
Step 5 — Debug DNS Resolution
# Deploy a debug pod
kubectl run dns-debug --image=busybox:latest --restart=Never -n troubleshooting-lab -- sleep 3600
# Test DNS resolution
kubectl exec dns-debug -n troubleshooting-lab -- nslookup kubernetes.default
# Should resolve to cluster IP
# Test external DNS
kubectl exec dns-debug -n troubleshooting-lab -- nslookup google.com
# Should resolve
# Check CoreDNS
kubectl get pods -n kube-system -l k8s-app=kube-dns
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=20
Step 6 — Debug Service Connectivity
# Create a service with wrong selector
kubectl create deployment web --image=nginx:latest -n troubleshooting-lab
kubectl expose deployment web --port=80 --target-port=80 -n troubleshooting-lab
# Verify endpoints exist
kubectl get endpoints web -n troubleshooting-lab
# Should show pod IPs
# Now create a broken service
kubectl apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
name: web-broken
namespace: troubleshooting-lab
spec:
selector:
app: wrong-label
ports:
- port: 80
targetPort: 80
EOF
# Check endpoints — should be empty
kubectl get endpoints web-broken -n troubleshooting-lab
# ENDPOINTS: <none>
# Diagnose
kubectl get pods -n troubleshooting-lab --show-labels
# Find the correct label
# Fix the selector
kubectl patch svc web-broken -n troubleshooting-lab -p '{"spec":{"selector":{"app":"web"}}}'
# Verify endpoints now exist
kubectl get endpoints web-broken -n troubleshooting-lab
Step 7 — Use Ephemeral Debug Containers
# Attach a debug container to a running pod
kubectl debug -it crashing-pod -n troubleshooting-lab --image=busybox:latest --target=app
# Inside the debug container you can:
# - Inspect the filesystem
# - Check environment variables
# - Test network connectivity
# - View process info
Cleanup
kubectl delete namespace troubleshooting-lab
Key Takeaways
| Skill | Commands |
|---|---|
| Check pod status | kubectl describe pod, kubectl logs --previous |
| Check events | kubectl get events --sort-by=.lastTimestamp |
| Debug networking | kubectl exec -- nslookup, kubectl get endpoints |
| Debug node issues | SSM session + journalctl -u kubelet |
| Quick debug pod | kubectl run netshoot --image=nicolaka/netshoot -it --rm |