Scaling: HPA, VPA & Cluster Autoscaler
Three independent, complementary autoscaling mechanisms. HPA changes replica count based on metrics. VPA changes per-Pod CPU/memory allocation. Cluster Autoscaler changes node count. They operate at P
Three independent, complementary autoscaling mechanisms. HPA changes replica count based on metrics. VPA changes per-Pod CPU/memory allocation. Cluster Autoscaler changes node count. They operate at Pod count, Pod size, and node count layers respectively.
-
HPA queries the metrics pipeline and computes desired replica count as current/target ratio, then updates replicas.
-
HPA defaults to fast scale-up and conservative scale-down (stabilization window) to avoid flapping.
-
VPA modes: Off (recommendation only), Initial (sets resources at Pod creation), Auto (evicts/recreates with new values).
-
Cluster Autoscaler watches for Pending Pods with FailedScheduling/insufficient-resource reasons and provisions nodes.
-
HPA and Cluster Autoscaler form a natural pipeline: HPA adds replicas -> Pods Pending -> CA adds nodes.
-
Ensure the metrics pipeline is running (metrics-server for CPU/memory, or a custom-metrics adapter for Prometheus-based metrics) -- HPA has nothing to query without it.
-
Set resource requests on the target Deployment's containers -- HPA's CPU/memory percentage targets are calculated relative to requests, so a target is meaningless without them.
-
Create an HPA resource referencing the Deployment, a target metric (e.g. averageUtilization: 70 for CPU), and min/max replica bounds.
-
HPA polls the metrics pipeline on an interval, computes desiredReplicas = currentReplicas * (currentMetric / targetMetric), and updates the Deployment's replica count.
-
For per-Pod sizing instead of replica count, create a VerticalPodAutoscaler in Off mode first to see recommendations before ever switching to Auto (which evicts/recreates Pods with new resource values).
-
If Pods go Pending due to insufficient node capacity, Cluster Autoscaler (a separate component watching for FailedScheduling events) provisions new nodes to fit them.
-
An e-commerce API scaling replica count up via HPA ahead of and during a flash-sale traffic spike, then scaling back down afterward.
-
A batch-processing service using VPA in Auto mode to right-size memory requests automatically as workload characteristics change over weeks, without a human re-tuning manifests.
-
A cluster running Cluster Autoscaler on a cloud provider so node count grows automatically when HPA-driven replica growth can't fit on existing nodes, and shrinks back down during low-traffic periods to control cost.
-
A service scaled on a custom Prometheus metric (e.g. queue depth) rather than CPU, so replica count tracks actual backlog instead of a CPU proxy.
-
HPA and VPA deliberately not combined on the same CPU/memory metric for the same workload, since they'd fight each other -- VPA handles memory-based sizing while HPA scales on a separate custom metric.
-
Always set resource requests before attaching an HPA -- utilization-based scaling targets are computed against requests, so missing requests makes the whole HPA meaningless.
-
Set both minReplicas and maxReplicas deliberately based on real capacity and cost constraints, not arbitrary defaults.
-
Tune the HPA stabilization window (behavior.scaleDown.stabilizationWindowSeconds) to prevent flapping under bursty-but-brief load spikes.
-
Never run HPA (CPU/memory-based) and VPA (Auto mode, same metric) on the same workload simultaneously -- they'll repeatedly override each other's decisions.
-
Prefer a custom metric closer to real user impact (queue depth, request latency) over raw CPU utilization when CPU isn't actually the bottleneck.
-
Pre-provision some headroom (via minReplicas or Cluster Autoscaler scale-up buffer) for workloads where node-provisioning latency during a spike is unacceptable.
-
Attaching an HPA to a Deployment with no resource requests set -- HPA has nothing to compute a percentage against and either errors or behaves unpredictably.
-
Setting maxReplicas so low that HPA hits its ceiling during real traffic spikes, silently capping capacity exactly when it's needed most.
-
Running VPA in Auto mode on a workload also managed by HPA on the same metric -- the two controllers conflict, each interpreting the other's changes as new signal to react to.
-
Expecting Cluster Autoscaler to provision a node instantly -- cloud node provisioning takes real minutes, so relying on it for sub-minute traffic spikes leaves Pods Pending during the gap.
-
Forgetting that VPA's Auto mode evicts and recreates Pods to apply new resource values -- using it on a disruption-intolerant workload without checking eviction behavior first.
-
Not setting PodDisruptionBudgets, so Cluster Autoscaler's node scale-down can take out more replicas simultaneously than the application can tolerate.
-
HPA's default polling interval and stabilization window trade responsiveness for stability -- tightening them reacts faster to spikes but risks flapping; the defaults favor fast scale-up and conservative scale-down deliberately.
-
Custom-metrics-based HPA (via Prometheus adapter) adds a metrics-pipeline hop with its own latency -- for very fast-moving load, that lag between real demand and HPA's view of it matters.
-
Cluster Autoscaler node provisioning latency (often 1-5+ minutes depending on cloud provider and node image) is frequently the real bottleneck in scale-out response time, not HPA's own decision loop -- pair HPA with some standing headroom for spiky workloads.
-
VPA recommendations are based on historical usage windows -- a workload with genuinely bursty, unpredictable usage will get less useful VPA recommendations than a steady-state one.
-
Load-test HPA scaling behavior before relying on it for real production traffic spikes -- confirm actual scale-up latency (metrics lag + Pod startup time) against your real SLA needs.
-
Set PodDisruptionBudgets on any HPA/Cluster-Autoscaler-managed workload so scale-down/node-consolidation events don't remove too many replicas at once.
-
Start VPA in Off (recommendation-only) mode in production and observe its suggestions for a real traffic cycle before ever switching to Auto mode.
-
Monitor HPA's actual vs. desired replica count and Cluster Autoscaler's node-provisioning events as first-class signals -- a stuck HPA or a Cluster Autoscaler unable to provision fails silently otherwise.
-
Deploy metrics-server, set CPU requests on a Deployment, attach an HPA targeting 50% CPU utilization, then generate load and watch
kubectl get hpa -wscale replicas up and back down. -
Create a VerticalPodAutoscaler in Off mode for a Deployment and inspect
kubectl describe vparecommendations without letting it modify anything. -
Deliberately set an HPA's maxReplicas low, generate load past that ceiling, and observe replica count plateau despite ongoing high utilization.
-
On a cluster with Cluster Autoscaler enabled, scale a Deployment's replicas past current node capacity and watch new nodes appear via
kubectl get nodes -w.
-
HPA, VPA, and Cluster Autoscaler operate at three independent layers: Pod count, Pod size, and node count.
-
HPA requires resource requests for percentage-based CPU/memory scaling.
-
HPA defaults to fast scale-up and conservative scale-down (stabilization window).
-
HPA and Cluster Autoscaler form a natural pipeline -- HPA replicas can trigger CA node additions.
Want a visual for this concept?
Generate a diagram tailored to “Scaling: HPA, VPA & Cluster Autoscaler” — the AI picks whichever visual (flowchart, comparison, sequence, etc.) best fits.
Sign in to generate a visual →