On this page
  1. What are the three Kubernetes autoscalers?
  2. How does the Horizontal Pod Autoscaler decide?
  3. How do I write an HPA manifest?
  4. Why does my HPA never scale?
  5. When is autoscaling the wrong tool?
  6. Where AI coding assistants get this wrong
  7. Checklist
  8. FAQ
    1. What is the difference between HPA and VPA?
    2. Do I need a metrics server for autoscaling?
    3. Does autoscaling reduce my cloud bill?
  9. Related topics
  10. Sources
concept

Kubernetes Autoscaling Explained: HPA vs VPA vs Cluster Autoscaler

Kubernetes has three autoscalers that answer three different questions. Learn which one scales replicas, which resizes pods, which adds nodes, and when autoscaling is the wrong fix.

Quick answer

  • The Horizontal Pod Autoscaler (HPA) changes replica count, the Vertical Pod Autoscaler (VPA) changes a pod’s CPU and memory requests, and the cluster autoscaler changes the number of nodes.
  • Only one of them adds capacity: HPA and VPA redistribute what the cluster already has, so on a single node they mostly move the bottleneck around.
  • HPA works by comparing observed usage against requests, so it is only as correct as the requests you set.
  • Without the metrics server installed, an HPA reports unknown metrics and silently never scales.
  • The cluster autoscaler needs a cloud node pool it can grow; on k3s and other self-hosted clusters, adding capacity is a decision you make, not a controller.

What are the three Kubernetes autoscalers?

Kubernetes ships three separate autoscaling mechanisms, and they are constantly confused for each other because all three are described as ‘scaling’. The Horizontal Pod Autoscaler adjusts how many copies of a workload run, based on a metric such as CPU utilization. The Vertical Pod Autoscaler adjusts how much CPU and memory a single pod requests, either as a recommendation or by restarting the pod with new values. The cluster autoscaler adjusts how many nodes exist, by asking a cloud provider’s node pool to add or remove machines.

The distinction that matters is capacity. HPA makes more pods, but each pod still needs somewhere to run; if the nodes are full, extra replicas sit Pending. VPA makes a pod bigger, which can make it unschedulable on a node with no room. Only the cluster autoscaler adds resources. That is why autoscaling is not a substitute for sizing: it is a way of matching your stated capacity to demand, and it needs spare capacity to work with.

How does the Horizontal Pod Autoscaler decide?

Every HPA cycle, the controller reads the current metric for the workload’s pods and compares it to your target. The arithmetic is roughly desired replicas equals the current replica count multiplied by current usage divided by target usage, rounded up. With a 50% CPU target and pods averaging 100% of their requested CPU, the controller doubles the replica count. If the average is below target, it scales in, subject to a stabilization window that prevents flapping.

The important detail is that utilization is measured against requests, not against the node’s capacity. A pod with a 100m CPU request using 100m is at 100% utilization, and one with a 1 CPU request using 100m is at 10% — even though both use exactly the same amount of CPU. Wrong requests therefore produce wrong scaling decisions in both directions: requests set too high make the cluster look idle while it is saturated, and requests set too low cause the HPA to add replicas it does not need.

How do I write an HPA manifest?

An HPA is a small object that points at a workload and declares a target. The autoscaling/v2 API is where behavior tuning lives, including the stabilization window and per-direction scaling policies.

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api
  minReplicas: 2
  maxReplicas: 10
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300

Why does my HPA never scale?

The most common cause is a missing metrics server. The HPA controller reads metrics from the metrics API, and a cluster without the metrics server returns nothing, so the HPA reports unknown values in its status and takes no action. Run kubectl top pods — if that fails, nothing the HPA does will work. Many managed platforms and k3s install the metrics server for you; a hand-built cluster usually does not.

The second cause is missing resource requests. Utilization is a percentage of requests, so a container without a CPU request has nothing to divide by and the HPA cannot compute a value. The third is a workload that is not CPU-bound: an app waiting on a database or an external API sits at low CPU while it is genuinely overloaded, and CPU-based autoscaling will never react. Those workloads need a custom or external metric, or they need the actual bottleneck fixed.

When is autoscaling the wrong tool?

Autoscaling is the wrong tool when there is nowhere to scale to. A single-node cluster has a fixed ceiling; adding pods past it produces Pending pods and slower responses, not more throughput. It is also wrong for stateful workloads such as a database: you cannot horizontally scale a single Postgres primary by adding replicas, and a VPA restarting your database to adjust its requests is an outage. And it is wrong when the answer is simply that the app is inefficient — autoscaling a leaky service multiplies the leak.

The honest sequence is: set resource requests from measured usage, fix the obvious inefficiency, confirm the workload can run in more than one replica, and only then add an HPA. If the workload does not scale horizontally at all, the VPA’s recommendation mode is a better first step than an HPA, because it tells you what the pod actually needs.

Where this bites vibecoders

Asked to make an app ‘handle more traffic’, an assistant will add an HPA in the same response as the Deployment, because it is the recognizable pattern for scaling. What it will not check is whether a metrics server exists, whether the container declares CPU requests for the HPA to divide by, whether the app can run two replicas without corrupting state, or whether the cluster is a single node that has no room for the replicas it will ask for. The result is an autoscaler that reports unknown metrics forever, or one that adds pods which sit Pending while the app stays slow — both of which look like the cluster is broken rather than the manifest being wrong.

Where AI coding assistants get this wrong

  • Adding an HPA to a Deployment that declares no CPU requests, so the metric can never be computed.
  • Assuming a metrics server is present and never checking with kubectl top.
  • Autoscaling a stateful workload such as a database, or a Deployment that holds its state on a local volume.
  • Setting minReplicas equal to maxReplicas, producing an autoscaler that cannot move.
  • Leaving the CPU target at the default 80% without measuring what the app can actually sustain per replica.
  • Adding an HPA and cluster autoscaler to a single-node k3s cluster where no new nodes can appear.

Checklist

  • Confirm the metrics server works with kubectl top pods.
  • Set measured CPU and memory requests before writing any HPA.
  • Choose a target utilization the app can sustain per replica, not a round number.
  • Confirm the workload is safe to run at more than one replica.
  • Set minReplicas above one for anything that must stay available.
  • Tune the scale-down stabilization window so it does not flap under spiky load.
  • Know your ceiling: node count times node size, or the autoscaler’s maximum.

FAQ

What is the difference between HPA and VPA?

The HPA changes how many replicas of a workload run; the VPA changes how much CPU and memory each replica requests. They address different bottlenecks: HPA for a workload that scales out, VPA for one that needs to be sized correctly. Running both on the same workload based on CPU is possible but confusing, and most teams pick one.

Do I need a metrics server for autoscaling?

For CPU and memory based autoscaling, yes. The HPA reads its values from the metrics API, which the metrics server provides. Without it the HPA reports unknown metrics and never acts. Managed platforms and k3s usually include it; a cluster you built by hand often does not.

Does autoscaling reduce my cloud bill?

It can, by matching capacity to demand, and it can also increase it by adding replicas and nodes faster than a human would. Scale-in is usually slower than scale-out by design, so a spiky workload tends to hold capacity it is not using. Autoscaling manages responsiveness first and cost second.

Sources

Share: