Kubernetes autoscaling with the Horizontal Pod Autoscaler
Scale on CPU, memory, or custom Prometheus metrics, and tune stabilization windows so the HorizontalPodAutoscaler won't flap under spiky, bursty load.
The Horizontal Pod Autoscaler adds and removes replicas to match load. The manifest itself is short; the parts teams get wrong are needing metrics-server installed, setting CPU requests so utilization math works, picking a metric that actually reflects user pain, and tuning behavior so replica counts do not yo-yo under spiky traffic.
HPA v2 supports Resource metrics (CPU, memory), custom metrics from Prometheus or other adapters, and external metrics like queue depth. CPU-target autoscaling is the starting point — but for a queue worker you scale on backlog, not processor idle time. The Kubernetes administration track covers requests, limits, and scheduling before you layer autoscaling on top.
Without CPU requests, utilization is undefined and HPA never scales.
Without requests on the Deployment, CPU utilization is undefined and HPA sits at minReplicas forever.
Prerequisites: metrics-server and requests
HPA reads current utilization from the metrics API. If kubectl top pods fails, HPA has nothing to scale on. Every container in the target Deployment needs a CPU request — utilization is measured as usage divided by request, not limit. A container with no request reports as 0% and the autoscaler never fires.
kubectl top pods -n prod -l app=apiNAME CPU(cores) MEMORY(bytes)api-7d4k2 245m 128Mikubectl get deployment api -n prod -o jsonpath="{.spec.template.spec.containers[0].resources.requests.cpu}"250m <- HPA divides usage by thisThe basic CPU autoscaler
Target 70% average CPU utilization across pods. Set minReplicas high enough to survive a single-node loss and maxReplicas low enough to stay within your cloud budget and downstream connection limits. Leave headroom above minReplicas so the scaler has room to react before users notice latency.
apiVersion: autoscaling/v2kind: HorizontalPodAutoscalermetadata:name: apinamespace: prodspec:scaleTargetRef:apiVersion: apps/v1kind: Deploymentname: apiminReplicas: 3maxReplicas: 20metrics:- type: Resourceresource:name: cputarget:type: UtilizationaverageUtilization: 70
kubectl get hpa api -n prod -wNAME TARGETS MINPODS MAXPODS REPLICASapi 42%/70% 3 20 3api 88%/70% 3 20 6 (scaled up under load)Scale on a custom metric when CPU lies
CPU utilization stays flat when your bottleneck is I/O wait, thread pool exhaustion, or downstream latency. Install the Prometheus Adapter (or your cloud provider's equivalent), expose a metric like http_requests_per_second, and reference it in the HPA metrics array with type: Pods and averageValue. The scaler now reacts to traffic, not processor heat.
metrics:- type: Podspods:metric:name: http_requests_per_secondtarget:type: AverageValueaverageValue: "500"
Stop the flapping with behavior policies
By default HPA scales up fast and down immediately — fine for steady load, painful for bursty traffic. A scale-down stabilization window waits before removing replicas, and a percent-based policy caps how many pods disappear per minute. Scale-up can stay aggressive; scale-down should be conservative so a brief lull does not halve your capacity right before the next spike.
behavior:scaleDown:stabilizationWindowSeconds: 300policies:- type: Percentvalue: 50periodSeconds: 60scaleUp:stabilizationWindowSeconds: 0policies:- type: Percentvalue: 100periodSeconds: 60
Where this goes next
HPA scales pods horizontally. Vertical Pod Autoscaler right-sizes requests over time. Cluster Autoscaler adds nodes when pending pods cannot fit. Together they are the three autoscalers — each solves a different bottleneck. The Kubernetes administration path covers all three with production tuning patterns.
Go deeper in a courseKubernetes administrationAutoscaling, scheduling, and running workloads at scale.View course