EKS Troubleshooting

An EKS problem can live in Kubernetes, in AWS, or in the seam between them. Most time is lost debugging the wrong layer: reading pod logs when a security group is closed, or inspecting IAM when a readiness probe is failing. Locate the layer first, then go deep.

The layers

┌────────────────────────────────────────────────────────────────────┐
│ 5. Application      crashes, bad config, failing probes            │
│ 4. Kubernetes       scheduling, RBAC, quotas, admission, DNS       │
│ 3. Add-ons          VPC CNI, CoreDNS, kube-proxy, CSI, LB controller│
│ 2. Nodes            kubelet, containerd, disk, memory, kernel      │
│ 1. AWS              IAM, VPC routing, security groups, quotas, ENIs│
│ 0. Control plane    API server, etcd — managed by AWS              │
└────────────────────────────────────────────────────────────────────┘

Ask three questions in order:

  1. What changed? A deployment, an add-on update, a node AMI, an IAM policy, a security group. Most incidents follow a change.
  2. What is the blast radius? One pod, one node, one zone, one namespace, or everything? The scope points at the layer: one node suggests layers 1–2, everything suggests an add-on or the network.
  3. Does it reproduce outside the application? A debug pod that cannot resolve DNS rules out the application at once.

First five minutes

# Is the cluster itself healthy?
aws eks describe-cluster --name my-cluster --query 'cluster.{status:status,version:version,health:health}'
kubectl get --raw='/readyz?verbose' | tail -3
 
# Nodes and system add-ons
kubectl get nodes -o wide
kubectl get pods -n kube-system -o wide
 
# What is Kubernetes complaining about, most recent last?
kubectl get events -A --sort-by=.lastTimestamp | tail -30
 
# The failing workload
kubectl describe pod <pod> -n <ns>          # read Events at the bottom first
kubectl logs <pod> -n <ns> --previous       # the crashed container, not the new one

kubectl describe and events answer the majority of questions. Read them before forming a theory. The general method is in Kubernetes troubleshooting and systematic debugging.

Where the evidence lives

EvidenceWhere
Pod and object state, eventskubectl describe, kubectl get events (events expire after an hour)
Application logskubectl logs; your log backend for anything older — pod logging
API server, audit, authenticator, schedulerControl plane logs in CloudWatch, if enabled
kubelet and containerdjournalctl -u kubelet / -u containerd on the node (journalctl)
VPC CNI/var/log/aws-routed-eni/ipamd.log and plugin.log on the node
AWS API errorsCloudTrail — filter on errorCode
Dropped network trafficVPC Flow Logs — look for REJECT
Add-on and node group healthaws eks describe-addon, aws eks describe-nodegroup (health.issues)
Cluster-level findingsEKS console → Cluster insights and Observability dashboard

Getting onto a node

Prefer Session Manager to SSH: no keys, no open port, and every session is logged.

aws ssm start-session --target i-0123456789abcdef0

When you cannot reach the node that way, a debug pod shares its namespaces:

kubectl debug node/ip-10-0-1-23.eu-west-1.compute.internal -it --image=public.ecr.aws/amazonlinux/amazonlinux:2023
chroot /host

For a container with no shell, attach an ephemeral container — kubectl debug. Bottlerocket nodes have no shell by default; use its admin container.

For anything going to AWS Support, collect a bundle on the node with the EKS log collector script from the awslabs/amazon-eks-ami repository; it gathers kubelet, containerd, CNI, iptables and kernel output in one archive.

Playbooks by symptom

SymptomGo to
Anything EKS-specific, as a lookup tableCommon EKS issues
Pod stuck PendingPod Pending
CrashLoopBackOffCrashLoopBackOff
ImagePullBackOffImage pull failures
Node NotReadyNode NotReady
Service not reachableService unreachable
DNS failuresDNS resolution
PVC stuckPVC stuck
Ingress returns 404 or 503Ingress 404
Pod IP or ENI problemsVPC CNI troubleshooting
Access denied to the clusterEKS access
Problems during or after an upgradeUpgrade process

Habits that shorten incidents

  • Enable control plane logging and a log backend before you need them. Evidence that was never collected cannot be recovered.
  • Keep add-ons current. A large share of “mysterious” issues are fixed bugs in the VPC CNI, CoreDNS or kube-proxy.
  • Alert on leading indicators: free IPs per subnet, node disk pressure, CoreDNS errors, API server 5xx, pending pods.
  • Rehearse. Run chaos experiments for node loss and zone loss so the first time is not in production.
  • Write the postmortem — incident management.

Across the wiki