What Is Horizontal Pod Autoscaling?
Horizontal Pod Autoscaling (HPA) automatically adjusts the number of Pod replicas in a Deployment, StatefulSet, or ReplicaSet based on observed metrics such as CPU utilization, memory usage, or custom application metrics. Instead of manually running kubectl scale when traffic spikes, the HPA controller runs a continuous control loop that compares current metric values against a target and changes the replica count to close the gap. This is the primary mechanism Kubernetes offers for reacting to changing load without operator intervention.
Cricket analogy: Like a captain who rotates bowlers based on the scoreboard rate, adding an extra fielder near the boundary only when the required run rate climbs above ten an over, HPA adds Pods only when the measured load actually crosses the target threshold.
How the HPA Controller Works
The HPA controller, part of kube-controller-manager, polls the metrics.k8s.io API (served by the Metrics Server) every sync period, default 15 seconds, to fetch current resource usage for the Pods matched by the target's selector. It computes the desired replica count using the formula desiredReplicas = ceil(currentReplicas * (currentMetricValue / desiredMetricValue)), then updates the .spec.replicas field on the target resource. Because it only edits the replicas field, HPA composes cleanly with a Deployment's own rollout logic; the Deployment controller still owns rolling updates while HPA only owns the count.
Cricket analogy: It is like a team management group recalculating squad size for the next match based on last match's over-rate efficiency divided by the target rate, rounding up to the nearest whole player rather than fielding a fraction of one.
Custom and External Metrics
Beyond CPU and memory, HPA can scale on custom metrics exposed through the custom.metrics.k8s.io API, such as requests-per-second reported by an Ingress controller, or external metrics like queue depth in an SQS queue reported through external.metrics.k8s.io, typically via an adapter like the Prometheus Adapter or KEDA. This lets teams scale a checkout service based on actual queue backlog rather than a proxy signal like CPU, which can lag behind real demand for I/O-bound workloads.
Cricket analogy: It is like a selector who scales the squad not on a generic fitness score but on a specific custom metric such as strike rate against left-arm spin in the last five innings, a signal much closer to what actually matters for the upcoming series.
Metrics Server only provides CPU and memory and is not a general monitoring solution; it does not store historical data. For custom or external metrics you need an adapter (Prometheus Adapter, Datadog Cluster Agent, or KEDA) that implements the custom.metrics.k8s.io or external.metrics.k8s.io API on top of your real monitoring backend.
Scaling Behavior and Stabilization Windows
The autoscaling/v2 API exposes a .spec.behavior block that lets you tune scale-up and scale-down independently: policies control the maximum rate of change (e.g., no more than 4 Pods or 100% every 60 seconds), and a stabilizationWindowSeconds value prevents flapping by looking back over a window and picking the highest (for scale-up) or lowest (for scale-down) recommended replica count seen in that window. The default stabilization window is 0 seconds for scale-up and 300 seconds for scale-down, meaning Kubernetes reacts to load increases quickly but is deliberately conservative about removing capacity, since a premature scale-down under a brief lull followed by a spike causes latency and even dropped requests.
Cricket analogy: It is like a captain who brings on an extra fielder the moment the required rate spikes but waits a full over of consistently low run rate before removing that fielder again, avoiding the flapping of moving players in and out ball by ball.
HPA cannot scale a Deployment that has no resource requests defined on its Pods when using CPU or memory metrics, because utilization is calculated as a percentage of the request. Always set requests before attaching an HPA, or the controller will be unable to compute a target and scaling will silently fail.
- HPA adjusts replica count based on metrics; it does not resize individual Pods (that is VPA's job).
- The controller polls metrics every sync period (default 15s) and applies desiredReplicas = ceil(currentReplicas * currentMetric / targetMetric).
- CPU/memory-based scaling requires resource requests to be set on the Pod spec, since utilization is a percentage of the request.
- Custom and external metrics need an adapter (Prometheus Adapter, KEDA) implementing the relevant metrics API.
- The behavior block tunes scale-up/scale-down rate limits and stabilization windows independently.
- Default stabilization is 0s for scale-up and 300s for scale-down to avoid flapping.
- HPA composes with Deployments by only editing .spec.replicas, leaving rollout mechanics untouched.
Practice what you learned
1. What does the HPA controller actually modify on the target workload?
2. Why must Pods have CPU resource requests set for CPU-based HPA to work?
3. What is the default stabilization window for scale-down in autoscaling/v2?
4. Which API must be implemented to allow HPA to scale on a queue-depth metric from an external system like SQS?
5. What formula does HPA use to compute the desired replica count for a single metric?
Was this page helpful?
You May Also Like
Vertical Pod Autoscaling
Understand how VPA right-sizes container CPU and memory requests automatically based on observed usage history.
Cluster Autoscaling
Learn how the Cluster Autoscaler adds and removes worker nodes so Pod-level autoscalers always have capacity to grow into.
Resource Requests and Limits
Understand how Kubernetes uses requests for scheduling and limits for runtime enforcement, and how both determine a Pod's QoS class.