Skip to main content

Load balancer health checks

12 min read

Pod lifecycle overview · Checklist and references

ALB/NLB Health Check and Probe Integration​

When using AWS Load Balancer Controller, synchronize ALB/NLB health checks with Kubernetes Readiness Probes to enable zero-downtime deployments.

ALB Target Group Health Checks vs. Readiness Probes​

Table 1. ALB and NLB health checks compared with Kubernetes Readiness Probes

AspectALB Health CheckNLB Health CheckKubernetes Readiness Probe
Executed byAWS Load BalancerAWS Load Balancerkubelet
Check targetIP:Port in the Target GroupIP:Port in the Target GroupPod container
Action on failureRemove from targets (block traffic)Remove from targets (block traffic)Remove from Service Endpoints
Default interval30 seconds30 seconds10 seconds
Timeout5 secondsProtocol-dependent (10 seconds for TCP, 6 seconds for HTTP/HTTPS)1 second

The ALB and NLB interval/timeout values are the Elastic Load Balancing Target Group API defaults; see the ALB and NLB health check documentation for the exact values. Target groups created by the AWS Load Balancer Controller can override these values through annotations, so they may differ from the ELB API defaults.

Health Check Timing Synchronization Strategy​

During a rolling update, operations proceed in the following order:

Figure 1. Pod creation and termination timing with load balancer health checks during a rolling update

Expand the diagram to read labels and follow connections.
Diagram

Recommended configuration:

apiVersion: v1
kind: Service
metadata:
name: myapp
annotations:
# ALB health check configuration
alb.ingress.kubernetes.io/healthcheck-path: /ready
alb.ingress.kubernetes.io/healthcheck-interval-seconds: "10"
alb.ingress.kubernetes.io/healthcheck-timeout-seconds: "5"
alb.ingress.kubernetes.io/healthy-threshold-count: "2"
alb.ingress.kubernetes.io/unhealthy-threshold-count: "2"
spec:
type: NodePort
ports:
- port: 80
targetPort: 8080
selector:
app: myapp
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: app
image: myapp:v1
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /ready # Same path as ALB
port: 8080
periodSeconds: 5 # Shorter interval than ALB
failureThreshold: 2
successThreshold: 1
terminationGracePeriodSeconds: 60

Pod Readiness Gates (Contributing to Zero-Downtime Deployments)​

AWS Load Balancer Controller v2.5+ supports Pod Readiness Gates, delaying the transition to the Ready state until the Pod is registered as an ALB/NLB target and passes health checks. This feature contributes to zero-downtime deployments but does not by itself guarantee them. The following prerequisites must also hold for it to take effect: the Namespace must have the automatic-injection label applied, the LBC version must support readiness gates, the ALB/NLB health check path and thresholds must be configured correctly, and the terminating side must drain existing connections through preStop and connection draining.

Enabling the feature:

# Enable automatic injection by adding a label to the Namespace
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
elbv2.k8s.aws/pod-readiness-gate-inject: enabled

Verify operation:

# Check Pod Readiness Gates
kubectl get pod myapp-xyz -o yaml | grep -A 10 readinessGates

# Example output:
# readinessGates:
# - conditionType: target-health.alb.ingress.k8s.aws/my-target-group-hash

# Check Pod Conditions
kubectl get pod myapp-xyz -o jsonpath='{.status.conditions}' | jq

Benefits:

  • During rolling updates, the old Pod is retained until it is removed from the targets
  • The new Pod receives traffic only after passing ALB health checks
  • When the prerequisites are met together, it greatly reduces traffic loss and contributes to zero-downtime deployments
Details

For more information about Pod Readiness Gates, see the "Pod Readiness Gates" section of the EKS High Availability Architecture Guide.

Gateway API Health Check Integration (ALB Controller v2.14+)​

AWS Load Balancer Controller v2.14+ integrates with the Kubernetes Gateway API, providing more advanced per-route health check mappings than Ingress. L7 routes (HTTPRoute/GRPCRoute) are served by an ALB on v2.14.0 and later, and L4 routes (TCPRoute/UDPRoute/TLSRoute) by an NLB on v2.13.3 and later.

Check before production use

Using the LBC and Gateway API together is not yet suggested for production workloads (per the LBC v2.14 Gateway documentation). It also requires prerequisites first: install the standard Gateway API CRDs (plus the experimental CRDs if needed) and the LBC Gateway-specific CRDs, and specify the --feature-gates=ALBGatewayAPI=true (L7) or NLBGatewayAPI=true (L4) flag in the LBC deployment. By default the LBC does not reconcile Gateway API resources.

Gateway API vs. Ingress Health Check Comparison​

Table 2. Health check capabilities of Ingress compared with Gateway API

AspectIngressGateway API
Health check configuration locationService/Ingress annotationTargetGroupConfiguration CRD
Per-route health checksLimited (annotation-based)Native support (per HTTPRoute/GRPCRoute)
L4/L7 protocol supportHTTP/HTTPS onlySupports TCP/UDP/TLS/HTTP/GRPC
Multi-tenant role separationSingle Ingress objectSeparate Gateway (infrastructure) and Route (application)
Weighted canary deploymentsSupported via weighted forward-action annotationsNative HTTPRoute support

Gateway API Architecture and Health Checks​

Figure 2. Gateway API components and TargetGroupConfiguration application structure

Expand the diagram to read labels and follow connections.
Diagram

L7 Health Checks: HTTPRoute/GRPCRoute with ALB​

TargetGroupConfiguration CRD example:

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: prod-gateway
namespace: production
spec:
gatewayClassName: alb
listeners:
- name: http
protocol: HTTP
port: 80
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api-v1-route
namespace: production
spec:
parentRefs:
- name: prod-gateway
hostnames:
- api.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /api/v1
backendRefs:
- name: api-v1-service
port: 8080
---
# TargetGroupConfiguration (AWS Load Balancer Controller v2.14+)
apiVersion: gateway.k8s.aws/v1beta1
kind: TargetGroupConfiguration
metadata:
name: api-v1-healthcheck
namespace: production
spec:
targetReference:
name: api-v1-service
defaultConfiguration:
targetType: ip
routeConfigurations:
- routeIdentifier:
kind: HTTPRoute
namespace: production
name: api-v1-route
targetGroupProps:
healthCheckConfig:
healthCheckProtocol: HTTP
healthCheckPath: /api/v1/healthz # Per-route health checks
healthCheckPort: "8080"
healthCheckInterval: 10
healthCheckTimeout: 5
healthyThresholdCount: 2
unhealthyThresholdCount: 2
matcher:
httpCode: "200-299"

GRPCRoute health check example:

apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
name: grpc-service-route
namespace: production
spec:
parentRefs:
- name: prod-gateway
hostnames:
- grpc.example.com
rules:
- matches:
- method:
service: myservice.v1.MyService
backendRefs:
- name: grpc-backend
port: 9090
---
apiVersion: gateway.k8s.aws/v1beta1
kind: TargetGroupConfiguration
metadata:
name: grpc-healthcheck
namespace: production
spec:
targetReference:
name: grpc-backend
defaultConfiguration:
targetType: ip
protocolVersion: GRPC
routeConfigurations:
- routeIdentifier:
kind: GRPCRoute
namespace: production
name: grpc-service-route
targetGroupProps:
healthCheckConfig:
healthCheckProtocol: HTTP # gRPC health checks use HTTP/2
healthCheckPath: /grpc.health.v1.Health/Check
healthCheckPort: "9090"
healthCheckInterval: 10
healthCheckTimeout: 5
healthyThresholdCount: 2
unhealthyThresholdCount: 2
matcher:
grpcCode: "0" # gRPC OK status

L4 Health Checks: TCPRoute/UDPRoute with NLB​

apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
metadata:
name: tcp-service-route
namespace: production
spec:
parentRefs:
- name: nlb-gateway
sectionName: tcp-listener
rules:
- backendRefs:
- name: tcp-backend
port: 5432
---
apiVersion: gateway.k8s.aws/v1beta1
kind: TargetGroupConfiguration
metadata:
name: tcp-healthcheck
namespace: production
spec:
targetReference:
name: tcp-backend
defaultConfiguration:
targetType: ip
routeConfigurations:
- routeIdentifier:
kind: TCPRoute
namespace: production
name: tcp-service-route
targetGroupProps:
healthCheckConfig:
healthCheckProtocol: TCP # Check TCP connectivity only
healthCheckPort: "5432"
healthCheckInterval: 30
healthCheckTimeout: 10
healthyThresholdCount: 3
unhealthyThresholdCount: 3

Gateway API Pod Readiness Gates​

Gateway API supports Pod Readiness Gates in the same way as Ingress:

apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
elbv2.k8s.aws/pod-readiness-gate-inject: enabled

Verify operation:

# Check Gateway status
kubectl get gateway prod-gateway -n production

# Check HTTPRoute status
kubectl get httproute api-v1-route -n production -o yaml

# Check Pod Readiness Gates
# The condition type the LBC injects is of the form target-health.elbv2.k8s.aws/<hash>, with a
# per-target-group suffix, so a fixed string cannot match it; grep the condition list for that prefix.
kubectl get pod -n production -l app=api-v1 -o yaml | grep -A 5 "target-health.elbv2.k8s.aws"

Health Check Transition Checklist for Migrating from Ingress to Gateway API​

Table 3. Step-by-step health check verification items when migrating from Ingress to Gateway API

StepIngressGateway APIVerification
1. Health check path mappingAnnotation-basedTargetGroupConfiguration CRDSeparate policies for each route
2. Protocol configurationHTTP/HTTPS onlyHTTP/HTTPS/GRPC/TCP/UDPVerify protocol type
3. Pod Readiness GatesNamespace labelNamespace label (same)Ensure zero-downtime deployments
4. Health check timingService annotationTargetGroupConfigurationValidate interval/timeout
5. Multi-route health checksSingle route onlyIndependent configuration per routeValidate each route

Migration example (Ingress → Gateway API):

# Before (Ingress)
apiVersion: v1
kind: Service
metadata:
name: myapp
annotations:
alb.ingress.kubernetes.io/healthcheck-path: /healthz
alb.ingress.kubernetes.io/healthcheck-interval-seconds: "10"
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress
spec:
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myapp
port:
number: 8080
# After (Gateway API)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: myapp-route
spec:
parentRefs:
- name: prod-gateway
hostnames:
- api.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: myapp
port: 8080
---
apiVersion: gateway.k8s.aws/v1beta1
kind: TargetGroupConfiguration
metadata:
name: myapp-healthcheck
spec:
targetReference:
name: myapp
defaultConfiguration:
targetType: ip
routeConfigurations:
- routeIdentifier:
kind: HTTPRoute
name: myapp-route
targetGroupProps:
healthCheckConfig:
healthCheckProtocol: HTTP
healthCheckPath: /healthz
healthCheckPort: "8080"
healthCheckInterval: 10
healthCheckTimeout: 5
healthyThresholdCount: 2
unhealthyThresholdCount: 2
Gateway API Migration Strategy
  • Phased migration: Ingress and Gateway API can run simultaneously on the same ALB (separate listeners)
  • Canary deployment: Transition safely using weighted traffic splitting in HTTPRoute
  • Rollback plan: Retain Ingress objects for a period after migration is complete