HPA Horizontal Scaling

A fixed replica count is rarely optimal for production applications. During quiet periods, extra Pods consume CPU, memory, and node capacity without adding value. During traffic spikes, too few replicas can increase latency, trigger timeouts, or cause requests to fail.

The Horizontal Pod Autoscaler (HPA) balances these concerns by adjusting the number of replicas for a Kubernetes workload according to observed demand. It is a built-in Kubernetes API resource in the autoscaling API group and supports targets such as Deployments, StatefulSets, and ReplicaSets.

Importantly, the HPA controller does not create or delete Pods directly. Instead, it updates the target workload’s replicas field through its scale subresource. The workload controller then reconciles that value. This design also explains why an HPA cannot target a DaemonSet: DaemonSets do not expose the required scaling interface.

How the Scaling Decision Works

By default, the HPA controller runs its synchronization loop approximately every 15 seconds. During each cycle, it retrieves current metrics, compares them with configured targets, calculates a recommended replica count, and updates the workload when the result warrants a change.

For a single utilization-based metric, the basic calculation is:

desiredReplicas = ceil(currentReplicas × currentMetricValue / desiredMetricValue)

Suppose a Deployment has four replicas, average CPU utilization is 80%, and the target is 50%:

ceil(4 × 0.80 / 0.50) = ceil(6.4) = 7

The HPA would therefore recommend seven replicas, subject to the configured minimum, maximum, stabilization windows, and scaling policies.

To prevent small metric fluctuations from causing constant adjustments, Kubernetes applies a default tolerance of 10%. A recommendation that remains within roughly 10% of the current replica count is normally treated as acceptable.

The final decision is constrained by:

  • minReplicas, which prevents the workload from shrinking below a safe baseline.
  • maxReplicas, which limits the impact of a faulty metric or unexpected traffic surge.
  • behavior, which controls how quickly the workload may scale up or down.
  • The target workload’s current state, including any changes already in progress.

Choosing the Right Metrics

HPA can calculate recommendations from several metric categories.

Resource metrics

Resource metrics measure utilization of resources such as CPU or memory. CPU utilization is usually expressed as a percentage of the Pod’s configured CPU request rather than its absolute consumption.

For example, a Pod with a 500m CPU request that consumes 400m CPU has approximately 80% CPU utilization. Defining requests accurately is therefore essential: without them, CPU-based HPA calculations may be misleading or incomplete.

The Metrics Server provides resource metrics through the Kubernetes Metrics API and must be installed in the cluster for standard CPU and memory utilization metrics to work.

Pods metrics

Pods metrics describe a custom measurement associated with individual Pods. Examples might include the number of active connections, pending jobs, or requests currently being processed. An application or monitoring system must expose these measurements, usually through an adapter that translates them into the Metrics API format.

Object metrics

Object metrics describe a related object in the same namespace. For example, an HPA could use a queue-depth metric reported for a messaging object. These metrics generally require an external metrics adapter.

External metrics

External metrics come from systems outside the workload but still relevant to its scaling decision. Examples include cloud monitoring metrics, third-party API latency, or the depth of an externally managed message queue.

Prometheus Adapter and similar components can expose custom or external metrics in a form that HPA can consume. When adapters or telemetry pipelines are unavailable, scaling decisions may be delayed, skipped, or based on incomplete information.

Defining an HPA

The following autoscaling/v2 configuration scales the web-app Deployment between two and ten replicas based on average CPU utilization:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web-app-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web-app
  minReplicas: 2
  maxReplicas: 10
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 50
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 0
      policies:
        - type: Percent
          value: 50
          periodSeconds: 60
        - type: Pods
          value: 4
          periodSeconds: 60
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
        - type: Percent
          value: 10
          periodSeconds: 60

This configuration permits relatively fast growth: every minute, the HPA may add either 50% of the current replica count or four Pods, whichever applicable limit is higher. Scale-down behavior is intentionally more conservative, allowing at most a 10% reduction per minute and retaining a five-minute stabilization window.

After applying the manifest, inspect the autoscaler with:

kubectl get hpa web-app-hpa
kubectl describe hpa web-app-hpa

The describe output is especially useful for troubleshooting. It can reveal the current metric values, the target values, the computed replica recommendation, scaling conditions, and recent events such as failed metric requests or adjustments rejected by a policy.

Controlling Scaling Behavior

Traffic rarely changes in a perfectly smooth pattern. Without additional controls, a brief surge can trigger excessive expansion, while a temporary dip can cause the workload to shed capacity too quickly. The behavior field addresses these problems with stabilization windows and rate policies.

A stabilization window stores recent scaling recommendations and selects a safer value:

  • During scale-up, the lowest recent recommendation is considered.
  • During scale-down, the highest recent recommendation is considered.

This asymmetry allows capacity to grow quickly while giving demand more time to recover before replicas are removed. Kubernetes defaults to a scale-down stabilization window of 300 seconds and no scale-up stabilization window unless the HPA specifies otherwise.

Policies can limit changes by either:

  • Pods, such as adding no more than four replicas in a period.
  • Percent, such as adding no more than 50% of the current replica count.
  • periodSeconds, which defines the window over which the policy applies.

These controls