4.3 Autoscaling Workloads & Clusters (HPA, VPA, Cluster Autoscaler, KEDA)

Key Takeaways

  • The Horizontal Pod Autoscaler changes the replica count of a Deployment or StatefulSet based on observed metrics, and requires resource requests to be set to compute CPU utilisation.
  • metrics-server supplies the resource metrics the HPA reads; without it, HPA reports unknown metrics and never scales.
  • The Vertical Pod Autoscaler adjusts CPU and memory requests rather than replica count, and traditionally must evict a Pod to apply new values.
  • The Cluster Autoscaler adds worker nodes when Pods are unschedulable and removes underutilised nodes, operating at the infrastructure layer rather than the workload layer.
  • KEDA extends the HPA with event-driven scalers for queue depth, stream lag, and cron schedules, and is the standard way to scale a Kubernetes Deployment to zero.
Last updated: August 2026

4.3 Autoscaling Workloads & Clusters (HPA, VPA, Cluster Autoscaler, KEDA)

Quick Answer: Kubernetes autoscales at four distinct layers. The Horizontal Pod Autoscaler (HPA) adds or removes replicas. The Vertical Pod Autoscaler (VPA) raises or lowers a Pod's CPU and memory requests. The Cluster Autoscaler (CA) adds or removes worker nodes. KEDA extends the HPA to external event sources — queue depth, stream lag, cron — and is what lets a Deployment scale all the way to zero.

Elasticity is one of the defining properties in the CNCF cloud native definition, and KCNA reliably tests whether you can name the right autoscaler for a stated symptom. The discriminator is always the same: what is being changed — replicas, request sizes, or machines?


1. The Four Layers at a Glance

            ┌──────────────────────────────────────────────┐
  EVENTS    │  KEDA — scales on queue depth, lag, cron,     │
            │  and to/from zero; drives an HPA underneath   │
            └──────────────────────┬───────────────────────┘
                                   ▼
            ┌──────────────────────────────────────────────┐
  REPLICAS  │  HPA — more/fewer Pods (scale out / in)      │
            └──────────────────────┬───────────────────────┘
                                   ▼
            ┌──────────────────────────────────────────────┐
  POD SIZE  │  VPA — bigger/smaller requests (scale up/down)│
            └──────────────────────┬───────────────────────┘
                                   ▼
            ┌──────────────────────────────────────────────┐
  NODES     │  Cluster Autoscaler / Karpenter — more/fewer  │
            │  machines when Pods cannot be scheduled       │
            └──────────────────────────────────────────────┘

2. Horizontal Pod Autoscaler

The HPA is a control-loop controller that periodically (about every 15 seconds) reads metrics and updates the replicas field of a scale target.

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web
  minReplicas: 3
  maxReplicas: 30
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70

The Scaling Formula

desiredReplicas = ceil( currentReplicas × ( currentMetric / targetMetric ) )

With 4 replicas averaging 90% CPU against a 70% target: ceil(4 × 90/70) = ceil(5.14) = 6 replicas.

Two Prerequisites Candidates Forget

  1. metrics-server must be installed. It is not part of a default cluster. It aggregates kubelet resource statistics and serves the metrics.k8s.io API that both kubectl top and the HPA consume. Without it, the HPA reports <unknown> and never acts.
  2. The Pods must declare CPU/memory requests. "70% utilisation" is meaningless without a denominator — utilisation is measured as a percentage of the request. A Pod with no CPU request cannot be scaled on CPU utilisation.

Metric Types

TypeSourceExample
Resourcemetrics-serverCPU or memory utilisation
PodsCustom metrics APIAverage requests-per-second per Pod
ObjectCustom metrics APIRequests-per-second on an Ingress
ExternalExternal metrics APIDepth of a cloud message queue

Damping Behaviour

Uncontrolled scaling oscillates. The HPA applies a stabilisation window — 300 seconds for scale-down by default, 0 for scale-up — so it reacts fast to load but retreats slowly. behavior.scaleDown and behavior.scaleUp policies let you tune both the window and the maximum rate of change.


3. Vertical Pod Autoscaler

The VPA answers a different question: are the requests on this workload right at all? It observes real consumption and recommends — or applies — new requests values.

Its three modes:

ModeBehaviour
OffProduce recommendations only. The safest and most common production use: a right-sizing report.
InitialApply recommendations to newly created Pods only.
Auto / RecreateActively update running Pods — historically by evicting and recreating them, since requests were immutable on a running Pod.

That eviction behaviour is the VPA's defining limitation and a favourite exam point. It is also why running the HPA and the VPA on the same CPU/memory metric conflicts: one adds replicas while the other resizes and restarts them, and they fight. The supported combination is HPA on CPU with VPA restricted to memory, or VPA in Off mode used purely for recommendations.

Kubernetes has been moving toward in-place Pod resizing so that requests can be changed without recreating the Pod. Until that is universally available, treat "VPA evicts Pods to resize them" as the correct exam answer.


4. Cluster Autoscaler

The HPA and VPA both assume there is somewhere to put the Pods. The Cluster Autoscaler supplies that assumption by talking to the cloud provider's node group or auto-scaling group API.

  • Scale up when one or more Pods are Pending because no node can satisfy them. The trigger is unschedulable Pods, not high CPU on existing nodes — this distinction is tested.
  • Scale down when a node has been underutilised for a sustained period (about 10 minutes by default) and everything on it can be rescheduled elsewhere. The node is cordoned, drained, and released.

A node will not be removed if it hosts Pods without a controller, Pods with restrictive PodDisruptionBudgets, Pods using local storage, or Pods carrying the cluster-autoscaler.kubernetes.io/safe-to-evict: "false" annotation.

Karpenter is a newer alternative that provisions right-sized instances directly from pending Pod requirements rather than scaling predefined node groups.


5. KEDA — Event-Driven Autoscaling

KEDA (Kubernetes Event-Driven Autoscaling) is a CNCF graduated project that fills the HPA's biggest gaps: external event sources and scale-to-zero.

A queue consumer has no meaningful CPU load while it waits, so CPU-based HPA cannot scale it. KEDA installs a ScaledObject CRD, polls the event source directly through one of its 60-plus scalers (Kafka, RabbitMQ, AWS SQS, Azure Service Bus, Redis, Prometheus, PostgreSQL, cron), and translates that signal into an HPA it manages on your behalf.

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: order-processor
spec:
  scaleTargetRef:
    name: order-processor
  minReplicaCount: 0        # scale to zero when the queue is empty
  maxReplicaCount: 50
  triggers:
  - type: kafka
    metadata:
      topic: orders
      lagThreshold: "100"

The minReplicaCount: 0 line is the headline capability: a plain HPA cannot go below 1, so scale-to-zero on Kubernetes means KEDA or Knative.


6. Diagnostic Table

SymptomCorrect autoscaler
Latency rises at peak; CPU pinned at 95%HPA on CPU
Pods are OOMKilled; requests were guessedVPA recommendation, then fix the requests
New Pods sit Pending with Insufficient cpuCluster Autoscaler
Kafka lag grows while consumer CPU stays flatKEDA with a Kafka scaler
A nightly batch service should cost nothing when idleKEDA cron scaler, or Knative
kubectl top pods returns "Metrics API not available"Install metrics-server
Test Your Knowledge

An HPA targeting 70% CPU utilisation reports <unknown> for the current metric and never scales. What is the most likely cause?

A
B
C
D
Test Your Knowledge

What event causes the Cluster Autoscaler to add a node to the cluster?

A
B
C
D
Test Your Knowledge

A team needs a Kafka consumer Deployment to run zero Pods when the topic is empty and to scale up as consumer lag grows. Which component provides this?

A
B
C
D