During a production incident, triage follows a strict hierarchy: Host Node → Networking/DNS → Control Plane → Container Runtime → Application Code. Never debug application logs until you confirm the infrastructure substrate is healthy.
Exit code 137 means SIGKILL was dispatched. The critical question: Was it a container-level OOM (exceeded resources.limits.memory) or a node-level OOM (host kernel killed processes due to node exhaustion)?
# Check if container was OOMKilled
kubectl get pods -n prod -o jsonpath='{range .items[*]}{.metadata.name}{" "}{.status.containerStatuses[*].lastState.terminated.reason}{" "}{.status.containerStatuses[*].lastState.terminated.exitCode}{"
"}{end}' | grep OOMKilled
# Check node dmesg for kernel kill events
kubectl debug node/<node-name> -it --image=busybox -- chroot /host dmesg -T | grep -i -E "oom[-_]killer|killed process"
The Fix: Differentiate RSS memory from Page Cache. If JVM or Node.js heap is configured higher than container memory limits, tune heap flags (-XX:MaxRAMPercentage=75.0).
When a pod exits with 143, it received SIGTERM but failed to shutdown gracefully within terminationGracePeriodSeconds (default: 30s), forcing kubelet to send SIGKILL.
# Inspect pod shutdown duration events
kubectl get events -n prod --field-selector reason=Killing --sort-by='.metadata.creationTimestamp'
The Fix: Implement a preStop hook with a sleep (e.g. sleep 10) to allow Kubernetes endpoints and kube-proxy iptables to remove the pod IP before the application stops accepting traffic, and increase terminationGracePeriodSeconds: 60.
The most destructive configuration mistake in Kubernetes: configuring a liveness probe to check downstream dependencies (PostgreSQL database or Redis). If the database slows down, all pods fail their liveness probe simultaneously, kubelet restarts all containers in a stampede, destroying connection pools and taking down the entire system.
The Rule: Liveness probes must only verify if the container process is deadlocked internally (shallow /healthz check returning HTTP 200). Use readiness probes for dependency checks so traffic is temporarily detached without restarting the process.
When external or inter-pod requests experience sudden 5.00-second latency spikes, it is almost always the Linux netfilter conntrack UDP race condition between IPv4 (A) and IPv6 (AAAA) DNS queries.
# Check conntrack insertion drops
sudo conntrack -S
# Verify CoreDNS response metrics
kubectl top pods -n kube-system -l k8s-app=kube-dns
The Fix: Deploy NodeLocal DNSCache daemonset on every node to serve DNS over local TCP loops, eliminating conntrack UDP races entirely.
Pods remain stuck in ContainerCreating or FailedCreatePodSandBox with error: "failed to assign an IP address to container".
# Check aws-node daemonset IP pool status
kubectl get pods -n kube-system -l k8s-app=aws-node
kubectl describe daemonset aws-node -n kube-system | grep -A 8 "Environment:"
The Fix: Enable Prefix Delegation on the AWS VPC CNI. Set ENABLE_PREFIX_DELEGATION=true and configure WARM_PREFIX_TARGET=1, expanding node IP capacity from ~30 IPs to over 250 IPs per instance.
df -ih. Millions of orphaned container logs or build cache artifacts fill the inode table even when disk space is 80% free.kubectl logs -n karpenter -l app.kubernetes.io/name=karpenter for InsufficientInstanceCapacity or missing subnet tags.Whether you're planning a complex cloud migration, optimizing Kubernetes reliability, or designing autonomous AI workflows, I'm always open to discussing architecture and technical challenges with engineering teams.
Connect with Naveed on LinkedIn →Exit code 137 indicates the container was killed by SIGKILL (signal 9 + 128 = 137), almost always triggered by the Linux kernel Out-Of-Memory (OOM) killer when container memory exceeds limits. Exit code 143 indicates SIGTERM (signal 15 + 128 = 143), meaning Kubernetes gracefully requested termination (e.g. node drain, rolling update, or failing liveness probe) but the app did not exit before terminationGracePeriodSeconds expired.
The notorious 5-second DNS delay is caused by a race condition in Linux netfilter conntrack during simultaneous UDP lookups (A and AAAA records) over the same source port. This causes conntrack insert collisions and packet drops. The fix is deploying NodeLocal DNSCache or setting single-request-reopen in the pod dnsConfig.
AWS VPC CNI IP exhaustion happens when pod churn exhausts the available secondary IPv4 addresses on worker node ENIs. Resolve it by configuring WARM_IP_TARGET and MINIMUM_IP_TARGET in the aws-node daemonset, or enabling prefix delegation (ENABLE_PREFIX_DELEGATION=true) which allocates /28 IPv4 prefixes (16 IPs per slot) instead of individual IPs.