intermediate~4h

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 -w scale replicas up and back down.

  • Create a VerticalPodAutoscaler in Off mode for a Deployment and inspect kubectl describe vpa recommendations 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 →

Practice quiz

Next Step

Continue to Scheduling: Affinity, Taints & Topology Spread← Back to all Kubernetes chapters