Horizontal Pod Autoscaling
The idea in one sentence
Section titled “The idea in one sentence”A HorizontalPodAutoscaler watches a metric against a target and adjusts a Deployment’s replicas between a minimum and maximum to keep that metric near the target — nothing more.
Two hard prerequisites before HPA does anything
Section titled “Two hard prerequisites before HPA does anything”The HorizontalPodAutoscaler (autoscaling/v2) sounds simple, but it silently does nothing at all unless two things are true first.
- The workload’s Pods must have resource
requestsset. By default HPA scales on CPU or memory utilization, and utilization is calculated as a percentage of what a Pod requested — no requests means there is no denominator to compute a percentage from. metrics-server(or a custom/external metrics adapter) must be installed in the cluster. HPA does not measure anything itself; it reads metrics that something else collected and exposed through the metrics API. No metrics source, no scaling decision, ever.
apiVersion: apps/v1kind: Deploymentmetadata: name: web-appspec: replicas: 3 selector: matchLabels: app: web-app template: metadata: labels: app: web-app spec: containers: - name: web-app image: web-app:3.2.0 resources: requests: cpu: "250m" memory: "256Mi"# metrics-server has to actually be running before HPA can read any utilizationkubectl get deployment metrics-server -n kube-systemDefining the HorizontalPodAutoscaler
Section titled “Defining the HorizontalPodAutoscaler”With requests in place and metrics-server running, the HPA object itself just names a target and a metric:
apiVersion: autoscaling/v2kind: HorizontalPodAutoscalermetadata: name: web-appspec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: web-app minReplicas: 3 maxReplicas: 20 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 60kubectl get hpa web-appkubectl describe hpa web-appThis says: keep average CPU utilization across all web-app Pods near 60% of their requested CPU, scaling the Deployment anywhere between 3 and 20 replicas to hold that line. HPA also supports scaling on custom, non-resource metrics — queue depth, requests-per-second, and similar — through the custom.metrics.k8s.io and external.metrics.k8s.io APIs, for teams whose bottleneck is not CPU or memory at all.
What HPA does not do
Section titled “What HPA does not do”It is worth being precise about the boundary here, because two other autoscalers sound similar but do completely different jobs:
- HorizontalPodAutoscaler changes how many replicas a Deployment or StatefulSet has. That is the entire job.
- VerticalPodAutoscaler (VPA) changes the
requests/limitsof the Pods that already exist, resizing them instead of adding more of them. - Cluster Autoscaler changes how many Nodes the cluster has, adding or removing machines underneath everything else (the next lesson covers this).
flowchart LR pods["Deployment Pods"] --> ms["metrics-server"] ms --> hpa["HorizontalPodAutoscaler controller"] hpa -->|"raise or lower"| replicas["Deployment.spec.replicas"]