Amazon EKS — Pod & Workload Failures

3 minute read

Pods fail for many reasons — image pull errors, application crashes, insufficient resources, or scheduling constraints. Each failure mode has specific symptoms and fixes.


ImagePullBackOff

Symptom: Pod stuck in ImagePullBackOff or ErrImagePull.

kubectl describe pod <pod-name> -n <namespace>
# Look for Events section
Cause Error Message Fix
Wrong image name repository does not exist Fix image path in deployment
ECR auth expired no basic auth credentials Verify node IAM role has ECR permissions
Cross-account ECR denied: User Add ECR repository policy or imagePullSecret
Private repo no secret unauthorized: authentication required Create imagePullSecret
Image tag doesn’t exist manifest unknown Verify tag exists in ECR

Fix — ECR Permissions on Node IAM Role

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ecr:BatchCheckLayerAvailability",
        "ecr:BatchGetImage",
        "ecr:GetDownloadUrlForLayer",
        "ecr:GetAuthorizationToken"
      ],
      "Resource": "*"
    }
  ]
}

Fix — Cross-Account imagePullSecret

kubectl create secret docker-registry ecr-cross-account \
  --docker-server=987654321098.dkr.ecr.us-east-1.amazonaws.com \
  --docker-username=AWS \
  --docker-password=$(aws ecr get-login-password --region us-east-1) \
  -n production

CrashLoopBackOff

Symptom: Pod starts, crashes, restarts repeatedly with increasing backoff.

# Check current state
kubectl get pod <pod-name> -n <namespace>

# Check logs from current (crashing) container
kubectl logs <pod-name> -n <namespace>

# Check logs from previous crash
kubectl logs <pod-name> -n <namespace> --previous

# Check container exit code
kubectl describe pod <pod-name> -n <namespace> | grep -A5 "Last State"
Exit Code Meaning Common Cause
0 Success (but pod shouldn’t exit) App exits immediately; wrong CMD/entrypoint
1 Application error Config missing, dependency unavailable
137 OOMKilled (SIGKILL) Memory limit too low
139 Segfault Application bug
143 SIGTERM (graceful) Liveness probe failing

Fix — OOMKilled (Exit 137)

# Confirm OOMKill
kubectl describe pod <pod-name> | grep -A3 "Reason: OOMKilled"

Increase memory limit:

resources:
  requests:
    memory: 512Mi
  limits:
    memory: 512Mi    # Increase this

Fix — Application Crash (Exit 1)

# Debug interactively
kubectl run debug --image=<same-image> --restart=Never -it -- /bin/sh

# Check environment variables
kubectl exec <pod-name> -- env

# Check if config exists
kubectl describe configmap <config-name>
kubectl describe secret <secret-name>

Pending Pods

Symptom: Pod stuck in Pending indefinitely.

kubectl describe pod <pod-name> | grep -A10 Events
Event Message Cause Fix
Insufficient cpu Not enough CPU on any node Add nodes or reduce requests
Insufficient memory Not enough memory on any node Add nodes or reduce requests
0/3 nodes are available: 3 node(s) had taint Taint / toleration mismatch Add toleration or remove taint
0/3 nodes are available: 3 node(s) didn't match Node affinity mismatch Fix affinity rules or label nodes
persistentvolumeclaim not found PVC doesn’t exist or is pending Check PVC status

Fix — No Resources Available

# Check node capacity
kubectl describe nodes | grep -A5 "Allocated resources"

# Check if Cluster Autoscaler or Karpenter is running
kubectl get pods -n kube-system | grep -E "autoscaler|karpenter"

Fix — Taint Mismatch

# List node taints
kubectl get nodes -o custom-columns='NAME:.metadata.name,TAINTS:.spec.taints[*].key'

# Add toleration to pod spec

Fargate Pod Scheduling Failures

Fargate pods fail if no Fargate Profile matches:

# Check Fargate profiles
aws eks list-fargate-profiles --cluster-name my-cluster

# Check if namespace and labels match a profile
aws eks describe-fargate-profile \
  --cluster-name my-cluster \
  --fargate-profile-name <profile-name> \
  --query 'fargateProfile.selectors'

Common issues:

  • Pod namespace doesn’t match any Fargate Profile selector
  • Pod labels don’t match profile selectors
  • Fargate Profile has 0 selectors

Debugging Commands Cheat Sheet

# Pod status overview
kubectl get pods -n <namespace> -o wide

# Detailed pod info
kubectl describe pod <pod-name> -n <namespace>

# Container logs
kubectl logs <pod-name> -n <namespace> -c <container>

# Previous logs (after crash)
kubectl logs <pod-name> -n <namespace> --previous

# Exec into running container
kubectl exec -it <pod-name> -n <namespace> -- /bin/sh

# Ephemeral debug container
kubectl debug -it <pod-name> --image=busybox:latest --target=<container>

# Events sorted by time
kubectl get events -n <namespace> --sort-by=.lastTimestamp

Updated: