Debugging a 502 Bad Gateway Spike During Kubernetes Rolling Updates
Scenario Prompt:
“Immediately following a production deployment rollout via Helm, the ingress controller and external AWS Application Load Balancer log an error spike with hundreds of HTTP 502 Bad Gateway responses over a 60-second window. Existing pods were being terminated while new pods were starting up. Once the rollout completed, error rates returned to zero. Walk me through the exact packet-level and lifecycle root cause, and how you eliminate these errors.”
Substantive Technical Concepts to Hit:
Kubernetes Asynchronous Endpoint Removal
When a pod is deleted, the Kubelet sends SIGTERM while the Endpoints controller asynchronously updates the Endpoints object and removes the IP from iptables/IPVS across nodes. Ingress proxies continue forwarding traffic to the pod for several seconds after it stops accepting connections unless mitigated.
PreStop Lifecycle Sleep Hook
Injecting a container preStop hook with a sleep (e.g. sleep 10 or sleep 15) pauses the container shutdown process, giving kube-proxy and ingress routing tables sufficient time to drain connections and remove the pod IP before the application receives SIGTERM.
Graceful Connection Draining (SIGTERM Handling)
Application runtimes must trap SIGTERM, stop accepting new incoming TCP connections, finish in-flight HTTP requests, and flush output buffers before exiting, preventing abrupt TCP RST packet transmission.
Keepalive Timeout Race Conditions (ALB vs Origin)
Reverse proxies (like AWS ALB or NGINX) reuse keepalive connections to upstream targets. If the backend application closes an idle connection right as the ALB forwards a new request, the ALB receives a TCP RST and issues an immediate 502 Bad Gateway. Upstream keepalive timeout must always exceed proxy idle timeout.
Container Readiness Probes
Ensuring new pods only register in the Kubernetes Service endpoints list once internal caches are primed and the application is actively ready to serve traffic, preventing cold pods from failing immediate requests.
- Is the backend application explicitly catching SIGTERM and waiting for in-flight requests to complete before closing sockets?
- Are the keepalive timeouts on the backend pods configured higher than the upstream load balancer idle timeout?
- Does the Pod specification include a preStop hook with an adequate delay to account for kube-proxy propagation across the cluster?