HPA Not Scaling

HPA metrics server, custom metrics, stabilization window, scale-down cooldown, and resource request prerequisites.

Overview

Overview

The Horizontal Pod Autoscaler (HPA) scales a Deployment or StatefulSet by comparing observed metric values with target values. When it is configured but not scaling, the cause is usually missing metrics, missing resource requests, metrics below the threshold, or the stabilization window delaying the change.

Causes and checks

  • Metrics Server not installed or erroring — kubectl get hpa — TARGETS shows unknown/unknown when no data comes back
  • No resource requests — Pod spec — HPA computes CPU utilization as a percentage of requests, so without requests it has no denominator
  • Custom metrics not exposed — API services — HTTP requests per second or queue depth need the Prometheus Adapter or KEDA
  • Metric below the threshold — Current vs target — Nothing to scale
  • Stabilization window — HPA behavior — Scaling is delayed on purpose

The replica formula

desiredReplicas = ceil(currentReplicas * (currentMetricValue / desiredMetricValue))

For CPU, currentMetricValue is the average CPU utilization across all pods, as a percentage of requests.

> [!IMPORTANT] If pods have no CPU requests, HPA cannot compute utilization: it needs a denominator.

Scale-up and scale-down timing

  • Scale-up — Metric exceeds the target — 0 seconds, scales immediately — ScaleUpStabilization can be set to prevent rapid oscillation
  • Scale-down — Metric drops below the target — 300 seconds (5 minutes) — The metric must stay below the threshold for 5 minutes; limited by minReplicas

> [!TIP] The 5-minute scale-down window prevents rapid thrashing when load oscillates, so a slow scale-down is usually expected behavior.

Key concepts

Metrics Server
Cluster-wide aggregator of resource usage data. Required for CPU/memory HPA. kubectl top commands also use it. Install with Helm or kubectl apply -f metrics-server.yaml.
Resource requests prerequisite
HPA CPU/memory targets are percentages of the resource request. Without requests set, HPA cannot compute utilization and shows "unknown." Always set requests on pods using HPA.
Scale-down stabilization window
Default 300 seconds. Metric must stay below threshold for this long before scale-down occurs. Prevents thrashing. Set in spec.behavior.scaleDown.stabilizationWindowSeconds.
KEDA
Kubernetes Event-Driven Autoscaler. Scales based on external metrics: SQS queue depth, Kafka consumer lag, Redis list length. Can scale to zero (HPA cannot). More flexible than Prometheus Adapter.
HPA min/max replicas
HPA will not scale below minReplicas or above maxReplicas regardless of metric values. Ensure maxReplicas is high enough to handle peak load and minReplicas provides baseline availability.

When to use it

  • Diagnosing why an HPA shows TARGETS as unknown/unknown
  • Explaining why HPA is not scaling down even though CPU has been low for 10 minutes
  • Setting up HPA for a stateless service with meaningful resource requests
  • Configuring KEDA for queue-depth-based scaling instead of CPU

Interview questions

  • Your HPA is configured but the TARGETS column shows unknown/unknown. How do you fix it?

Sign up free to read the full topic

More Troubleshooting topics

Start free on Cariara · Coding problems · System design studio