Horizontal Pod Autoscaler
More pods when busy, fewer when quiet.
So far, you chose the number of replicas yourself. But traffic changes through the day. Too few pods, and users wait. Too many, and you pay for idle machines. The horizontal pod autoscaler adjusts the number of pods for you, based on what it measures. Let's see it in action.

- Traffic changes all day
- You pick a target, not a number
- Kubernetes adds and removes pods
The autoscaling loop
The autoscaler is another control loop. Every fifteen seconds, it reads the average C P U use of the pods, from the metrics server. It compares it to your target, for example, fifty percent of the requested C P U. If the pods are busier than the target, it computes how many pods would bring the average back down, and scales up. If they are quieter, it scales down, but slowly, to avoid flapping. So the replica count follows the load.
- Measureaverage CPU of the pods
- Comparewith your target, 50%
- Computehow many pods are needed
- Scalechange the replica count
An autoscaler in YAML
Here is the autoscaler file. It points at its target, the deployment called php. Min replicas is one, and max replicas is six, so it can never go beyond those limits. And under metrics, we choose C P U, with an average utilisation of fifty percent. Utilisation is measured against the pod's request, which is why every autoscaled pod must have a C P U request.
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: php
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php
minReplicas: 1
maxReplicas: 6
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50Watching it scale
Let's watch. The app uses an image that does some heavy maths for every request. First, there is one pod, and the autoscaler shows, a low percentage against the fifty percent target. Now we start a load generator, a pod that sends requests as fast as it can. After a couple of minutes, the usage climbs above the target, and the autoscaler raises the replica count, to four pods. More pods share the work, and the average falls back toward the target. When the load stops, it will scale back down, after a five minute calm period.
kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE php Deployment/php cpu: 1%/50% 1 6 1 111s kubectl run load --image=busybox:1.36 --restart=Never -- /bin/sh -c "while true; do wget -q -O- http://php > /dev/null; done" pod/load created kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE php Deployment/php cpu: 90%/50% 1 6 4 4m21s kubectl get pods -l app=php NAME READY STATUS RESTARTS AGE php-f858fbfcc-4vsbl 1/1 Running 0 95s php-f858fbfcc-5pbdt 1/1 Running 0 95s php-f858fbfcc-ct8bw 1/1 Running 0 95s php-f858fbfcc-w8gdt 1/1 Running 0 4m21s
File used: app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: php
spec:
replicas: 1
selector:
matchLabels:
app: php
template:
metadata:
labels:
app: php
spec:
containers:
- name: php
image: registry.k8s.io/hpa-example
ports:
- containerPort: 80
resources:
requests:
cpu: 100m
limits:
cpu: 200m
---
apiVersion: v1
kind: Service
metadata:
name: php
spec:
selector:
app: php
ports:
- port: 80File used: hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: php
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php
minReplicas: 1
maxReplicas: 6
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50Summary
Good. The horizontal pod autoscaler follows load, adding and removing pods, between a minimum and a maximum. It needs C P U requests, and the metrics server. Next, two more kinds of autoscaling, one that resizes pods, and one that adds whole machines.
Key takeaways- HPA: scale the number of pods
- Target a utilisation, set min and max
- Needs requests and metrics-server