iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

HPA / Autoscaling

HorizontalPodAutoscaler watches a metric (CPU, memory, or a custom one) and scales a Deployments replica count up or down. Configure it with sensible min/max bounds, a target metric, and the stabilisation windows that prevent flapping. Get this right and your stack absorbs load without paging anyone.

CPU + custom metric HPA with sensible bounds

EXAMPLE
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: shop-api
  namespace: shop
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: shop-api

  # 1) Bounds — protect against runaway scaling AND keep a minimum capacity
  minReplicas: 3
  maxReplicas: 50

  # 2) Metrics
  metrics:
    # CPU at 60% target lets new traffic land without queueing
    - type: Resource
      resource:
        name: cpu
        target: { type: Utilization, averageUtilization: 60 }

    # Memory if your app is memory-bound (rarely the right primary signal)
    - type: Resource
      resource:
        name: memory
        target: { type: Utilization, averageUtilization: 75 }

    # Custom metric (from Prometheus Adapter etc.)
    - type: Pods
      pods:
        metric: { name: 'requests_per_second' }
        target: { type: AverageValue, averageValue: '200' }

  # 3) Behaviour — flap protection
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 30
      policies:
        - { type: Percent, value: 100, periodSeconds: 30 }   # double or less per 30s
        - { type: Pods,    value: 4,   periodSeconds: 30 }   # OR +4 pods per 30s
      selectPolicy: Max
    scaleDown:
      stabilizationWindowSeconds: 300                        # wait 5m before shrinking
      policies:
        - { type: Percent, value: 10, periodSeconds: 60 }    # at most -10%/min
      selectPolicy: Min                                       # the gentler of the two

---
# 4) Required: resource requests on the Deployment
# Without 'requests', the autoscaler has nothing to compute utilisation against.
# spec:
#   template:
#     spec:
#       containers:
#         - name: api
#           resources:
#             requests: { cpu: '100m', memory: '256Mi' }
#             limits:   { cpu: '500m', memory: '512Mi' }

---
# 5) Metrics server must be running on the cluster
# kubectl get apiservice v1beta1.metrics.k8s.io
# If missing, install:
#   kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

---
# 6) For CUSTOM metrics, install Prometheus Adapter (or KEDA for event-driven scaling)
# https://github.com/kubernetes-sigs/prometheus-adapter

# 7) Operate the HPA
# kubectl get hpa -n shop
# kubectl describe hpa shop-api -n shop
# kubectl get hpa shop-api -n shop -w

# 8) Inspect why it is NOT scaling
# kubectl describe hpa shop-api -n shop  -> 'ScalingActive' condition
# Check: metrics-server running, resource requests set, target metric reachable

# 9) Decision tree for the target metric
# - Stateless HTTP API:           CPU @ 50-70%
# - Long-poll / WS heavy:         in-flight connections (custom metric)
# - Worker pulling from a queue:  queue depth via KEDA
# - Memory-bound (JVM, Python):   memory at 60-75%
# - Latency target?               consider custom metric + percent of SLA budget

# 10) Common pitfalls
# - Forgetting resources.requests -> HPA cannot compute utilisation
# - minReplicas=1 in prod         -> a single pod restart causes hard outage
# - maxReplicas too low           -> caps capacity below incident peak
# - stabilizationWindowSeconds=0  -> oscillates around the target every 15s
# - HPA fighting Cluster Autoscaler -> pods pending, no node added -> right-size requests

Why it matters

Pair HPA with `minReplicas >= 3` + a 300-second scaleDown stabilisation window. Three replicas survive a single node loss; the 5-minute downscale window prevents the post-spike "we shrank to 5 pods then traffic returned" oscillation that drives PagerDuty in the 3am hour.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
kind: HorizontalPodAutoscaler
spec: { minReplicas: 2, maxReplicas: 10, targetCPUUtilizationPercentage: 70, scaleTargetRef: { kind: Deployment, name: api } }
Try it Yourself »

Discussion

Loading…