Skip to main content

Scale out with the Horizontal Pod Autoscaler

Inspect 1.36

Every cluster created with Syself Autopilot runs the , so a Horizontal Pod Autoscaler that scales on CPU or memory works the moment you apply it, with no need to install additional tools. It watches live usage, compares it to a target you set, and moves the replica count until the two line up.

How it decides#

The math is a ratio. If your pods average 80% CPU against a 50% target, the HPA figures it needs roughly 80/50 (that is, 1.6) times the replicas it has now, and it adds them. When load drops, it works the same ratio in reverse.

yaml
		apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web
spec:
  scaleTargetRef: # the workload whose replica count the HPA owns
    apiVersion: apps/v1
    kind: Deployment
    name: web
  minReplicas: 2 # floor: 2+ so a node drain never leaves you at zero
  maxReplicas: 10
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 60 # target is a % of the CPU request, not the node
	
Important

A CPU or memory target is a percentage of the request, not of the node. If a container has no CPU request, "60% of CPU" has no denominator and the HPA simply cannot scale it. before you use resource-based HPAs.

Min, max, and stabilization#

minReplicas and maxReplicas set the range the HPA moves within. Between them sits stabilization, which keeps the replica count from flapping: the HPA scales up fast, but by default waits 5 minutes of sustained low load before scaling down, so a short drop in usage does not shed capacity you will want back a minute later. Tune behavior.scaleUp and behavior.scaleDown when the defaults do not fit your traffic shape.

Your HPA during a node roll#

minReplicas: 1 is a common mistake on this platform. Nodes here can get drained and replaced constantly. Every Kubernetes upgrade rolls them out, and self-healing replaces any node that goes unhealthy. When a node drains, its pods are evicted with up to the to reschedule elsewhere. A single-replica workload has no second copy to carry traffic across that gap, so it can sit at zero running pods mid-drain even though the HPA is behaving exactly as configured. Keep minReplicas at 2 or higher for anything that has to stay reachable.

Beyond CPU and memory#

CPU and memory are not the only signals an autoscaling/v2 HPA can read. Point it at a custom metric from your own application, or an external one like queue depth: install an adapter that publishes the value to the Kubernetes metrics API, then reference it under metrics the same way you would CPU. One limit stays fixed, though: the HPA only changes pod count, never node count. When it scales past what the current nodes hold, pair it with the .

Verify#

kubectl get hpa web shows current usage against your target under TARGETS: 35%/60% means it is reading metrics and has headroom. If you see <unknown>/60%, the HPA cannot read usage at all, almost always a missing CPU request or metrics-server not reaching the pod. Fix that first; a blind HPA will not scale.

Then prove the important case: cordon and drain the node running your workload by hand, and watch it. If minReplicas is 2 or more, traffic never notices. If it is 1, you will see the gap the next real upgrade would have shown you in production.