Kubernetes autoscaling adds or removes computing power for your apps as traffic goes up and down. The goal is simple. Your apps always have enough capacity to stay fast, and you stop paying for servers that sit idle. A cluster that scales itself also handles a sudden traffic spike without anyone resizing it by hand.
When demand changes, you have two basic options. You can run more or fewer copies of an app, which is horizontal scaling, or give each copy more or less CPU and memory, which is vertical scaling. Manual changes come late and need someone watching, so an autoscaler makes them for you. Autoscalers have limits too. Each one reacts a little after demand changes, and each one works well only when every app states how much CPU and memory it needs.
Four techniques cover the parts of a cluster you may need to scale:
- Horizontal Pod Autoscaler (HPA) changes how many copies of an app run. Each running copy is called a pod.
- Vertical Pod Autoscaler (VPA) changes how much CPU and memory each pod gets.
- Cluster Autoscaler changes how many servers, called nodes, the cluster has.
- KEDA adds pods when outside events arrive, such as new jobs in a queue, and can remove every pod when there is no work.
This guide explains how each technique works, compares all four in one table, and gives you a two-question selector for choosing between them. It then covers sample configuration files, cost savings, common fixes, and a step-by-step rollout for your own cluster.
Try it yourself: every cluster on Rackspace Spot includes a managed Cluster Autoscaler at no extra cost, so nodes join and leave on their own as load changes. A working cluster starts at $7.20 a month, which undercuts what most other providers charge for a comparable managed cluster.
Understanding Kubernetes autoscaling fundamentals
What is Kubernetes autoscaling?
Kubernetes autoscaling is software that resizes your cluster for you. Without it, someone has to notice a slowdown and run kubectl scale by hand. An autoscaler checks a number such as CPU use every 10 to 30 seconds, compares it with your target, and adds or removes capacity when the two drift apart.
Core components enabling Kubernetes autoscaling
Every autoscaler relies on the same four parts of Kubernetes:
- Metrics Server checks how much CPU and memory each pod uses every 15 seconds.
- The API server is the cluster's central record. It stores each autoscaler's settings and the pod count it asks for.
- Controllers, such as a Deployment, read that pod count and start or stop pods to match it.
- The scheduler picks a node for each new pod. If no node has room, the pod waits in a Pending state.
Key metrics that drive autoscaling decisions
CPU use is the most common trigger. Kubernetes measures it against the pod's CPU request, which is the amount of CPU the pod asks for. A pod that requests 500m, or half a CPU, and uses 400m runs at 80%. Memory can trigger scaling too, but it is a weaker signal, because memory use often stays high after traffic drops.
Kubernetes counts some cached memory as in use, even though the operating system cannot always free it. As a result, an HPA that scales on memory can keep extra pods running after the busy period ends. If a container sets no CPU request, the HPA has nothing to measure against and does not scale it.
Autoscalers can also scale on two other kinds of numbers:
- Custom metrics come from inside the cluster, such as how many requests each pod handles per second.
- External metrics come from outside the cluster, such as the number of messages waiting in a RabbitMQ queue.
The four pillars of Kubernetes autoscaling
The table below compares all four autoscalers side by side:
Kubernetes autoscaling techniques compared
| Technique | What it scales | Main trigger | Best use case | Scale to zero | Key limitation |
|---|---|---|---|---|---|
| HPA | Pod replicas | CPU, memory, custom metrics | Stateless web apps and APIs | Beta in v1.37, not on CPU or memory | Lags sudden spikes |
| VPA | Pod CPU and memory | Past CPU and memory use | Steady or single-instance workloads | No | Can restart pods |
| Cluster Autoscaler | Nodes | Waiting pods, idle nodes | Any cluster with variable demand | Nodes only, where the provider allows | New nodes take minutes |
| KEDA | Pod replicas and Jobs | Queues, streams, schedules | Bursty or mostly idle event workloads | Yes, by default | One more tool to install and run |
Which autoscaling technique to use when
Select one problem and one environment, and the recommended starting point appears below with the reason.
Find the right starting point
Choose the situation that best describes your workload.
1. What problem are you trying to solve?
2. Where does the cluster run?
Recommended starting point
Select one option in each list to see your starting point.
Most live clusters use two autoscalers, one for pods and one for nodes.
Horizontal Pod Autoscaler (HPA)
The Horizontal Pod Autoscaler adds or removes pods to keep a number, such as CPU use, close to a target you set. Every 15 seconds, it runs three steps:
- Observe: check the current CPU use, or another chosen number, for each pod.
- Compare: divide the average by the target to see how far off it is.
- Act: set
desiredReplicas = ceil(currentReplicas × currentValue / targetValue).
For example, four pods target 50% CPU but run at 80%. The HPA multiplies 4 by 80/50, rounds 6.4 up, and scales to seven pods. It ignores changes within 10% of the target, so small swings never trigger scaling.
Scale-up starts within one or two 15-second checks, while scale-down waits five minutes so a short dip keeps its pods. Each new pod also needs a node with free space. On Rackspace Spot, you can set one node pool to autoscale, so the cluster adds nodes when pods cannot be scheduled and removes them once they sit unused.
HPA configuration deep dive
This Kubernetes autoscaling YAML example targets a Deployment named web:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: web
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web
minReplicas: 2
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
behavior:
scaleDown:
policies:
- type: Percent
value: 50
periodSeconds: 60You tune four fields most often:
minReplicassets the lowest pod count. With two pods, the app stays up even while one node shuts down for maintenance.averageUtilizationsets the CPU target. Apps that must respond fast, such as APIs, usually aim for 50 to 60%. Background jobs can run at 80%.behavior.scaleDown.policiesremoves at most half the pods each minute, so the HPA does not cut pods it needs again a few minutes later.tolerancechanges the 10% range the HPA ignores, with separate values for scaling up and down. It is stable from Kubernetes v1.37.
Vertical Pod Autoscaler (VPA)
Some apps cannot simply run more copies, such as a database that runs as a single instance. The Vertical Pod Autoscaler helps these apps by giving each pod more or less CPU and memory, based on how much it used in the past. Its update mode decides how it applies each change:
Offsuggests new sizes and changes nothing.Initialapplies new sizes only when a pod starts.Recreaterestarts a pod at the new size when its current size is far off.Autobehaves like Recreate and is deprecated.InPlaceOrRecreate, generally available since VPA 1.6.0, resizes a pod while it keeps running and restarts it only if that fails.
Restarts are the main downside of VPA. A restarted pod drops open connections and loses data it held in memory. Before you turn on Recreate, set a PodDisruptionBudget, which limits how many pods can restart at the same time.
VPA configuration and tuning
Start in recommendation-only mode:
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: db
spec:
targetRef:
apiVersion: apps/v1
kind: StatefulSet
name: db
updatePolicy:
updateMode: "Off"
resourcePolicy:
containerPolicies:
- containerName: "*"
minAllowed: {cpu: 100m, memory: 256Mi}
maxAllowed: {cpu: 2, memory: 4Gi}minAllowed and maxAllowed set a lower and upper limit, so one unusual week cannot shrink a pod too far or grow it bigger than a node. Run kubectl describe vpa db after a week to read the suggested sizes.
Do not let VPA and the HPA both act on CPU for the same app. If VPA gives each pod more CPU, each pod's usage percentage falls, and the HPA removes pods the app still needs. To use both, have the HPA scale on a different number, such as requests per second.
Cluster Autoscaler
Pod autoscalers only work when the cluster has room for new pods. The Cluster Autoscaler adds nodes when it runs out. Every 10 seconds, it looks for pods stuck in Pending because no node has space. It then works out which node group could fit them and adds a node to that group. A node group is a set of identical servers that grow and shrink together.
Removing nodes works the other way. If the pods on a node ask for less than half of its capacity for 10 minutes, and they can move to other nodes, the autoscaler moves them and shuts the node down. It goes by what pods ask for, which can differ from what they actually use.
Karpenter is an open-source alternative that skips node groups. It reads what the waiting pods need and starts a server of the right size, often in under a minute.
Cluster Autoscaler configuration and behavior
Four flags control most of its behavior:
| Flag | Default | Effect |
|---|---|---|
--scale-down-unneeded-time | 10m | How long a node stays underused before removal |
--scale-down-delay-after-add | 10m | How long to wait after adding a node before removing any |
--scale-down-utilization-threshold | 0.5 | Below this share of requested capacity, a node counts as underused |
--max-node-provision-time | 15m | How long to wait for a new node before trying another group |
KEDA: Event-driven and scale-to-zero autoscaling
CPU shows that a pod is busy. It cannot show 40,000 messages waiting for pods that do not exist yet. KEDA, an open-source project, scales on events like these. Version 2.21 includes 80 scalers, which are ready-made connectors for sources such as Apache Kafka, RabbitMQ, Prometheus, and time-based schedules (Cron).
KEDA works alongside the HPA in three stages:
- Activation: every 30 seconds, KEDA checks the event source. When work appears, it starts the first pod.
- Scaling: KEDA creates an HPA behind the scenes and passes it the event count. The HPA then adds any pods beyond the first.
- Cooldown: after five minutes with no events, KEDA scales the app back to zero pods.
A ScaledObject is the KEDA setting that links an app to its event source:
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: orders-worker
spec:
scaleTargetRef:
name: orders-worker
minReplicaCount: 0
maxReplicaCount: 50
triggers:
- type: rabbitmq
metadata:
queueName: orders
mode: QueueLength
value: "20"
authenticationRef:
name: rabbitmq-authKEDA targets 20 messages per replica, so 400 waiting messages produce 20 workers, and an empty queue produces none.
The HPA can also scale to zero in Kubernetes v1.37 as a beta feature, but never on CPU or memory. KEDA scales to zero on any supported version and can start a one-off Job for each batch of events.
Autoscaling strategies, policies, and best practices
Designing effective autoscaling strategies
Pick the combination that fits each kind of app:
- Stateless services, such as web front ends that keep no data between requests, pair the HPA or KEDA with the Cluster Autoscaler.
- Single-instance services, such as a database, pair VPA with the Cluster Autoscaler.
- Event-driven workers run KEDA from zero, and the Cluster Autoscaler removes the nodes they leave empty.
Base each target on the response time you promise users, often written into a service level agreement (SLA). Run a load test to find the CPU level where responses get too slow, then set the HPA target 15 points lower. If responses slow down at 75% CPU, for example, target 60%.
For predictable peaks, such as a 9 a.m. login rush, use KEDA's Cron scaler to add pods before the rush begins.
Resource management for optimal autoscaling
Every autoscaler in this guide depends on resource requests, the CPU and memory each container says it needs. The HPA compares actual use against them, VPA changes them, and the Cluster Autoscaler adds them up to decide whether a node is full. If the requests are wrong, all three make wrong decisions.
A common mistake is asking for too much. Pods then look less busy than they are, so the HPA scales late, and nodes fill up with reserved capacity that nothing uses. Run VPA in Off mode to see what pods really use, then set requests from its suggestions. Our guide to Kubernetes resource optimization covers request sizing in depth.
Cost optimization through autoscaling
Autoscaling saves money when it removes nodes, because nodes are what you pay for. Three settings lower the bill:
- Lower floors: drop
minReplicasand node group minimums in test environments outside working hours. - Faster scale-down: shorten
--scale-down-unneeded-timeon clusters that run batch jobs, so idle nodes go away sooner. - Cheaper capacity: run work that can restart safely on spot nodes. They cost less because the provider can take them back.
Combining the Cluster Autoscaler with spot nodes saves money twice. The autoscaler removes nodes you do not need, and each node it keeps costs less. On Rackspace Spot, for example, you autoscale a spot node pool by setting minimum and maximum node counts on a bid.
Track cost per request instead of total spend. Total spend rises whenever traffic grows, even when autoscaling works well.
Autoscaling best practices
Confirm each item before you rely on an autoscaler in production:
- Every container sets CPU and memory requests.
- You load-tested your targets in a test environment.
- Each namespace has a ResourceQuota, so one team cannot consume the cluster.
- HPA and VPA never act on the same metric for one workload.
- PodDisruptionBudgets limit how many pods of each app can restart at once.
- Autoscaling settings live in version control, such as Git, with a note explaining each target.
Monitoring, troubleshooting, and autoscaling limitations
Monitoring Kubernetes autoscaling in production
Start with the status each autoscaler reports:
kubectl describe hpa web
kubectl describe vpa db
kubectl -n kube-system logs deploy/cluster-autoscaler
kubectl get events --field-selector reason=TriggeredScaleUpTo spot trends over time, chart pod counts, node counts, and CPU use in a tool such as Prometheus with Grafana. Set alerts for three warning signs:
- An HPA stuck at
maxReplicasfor 15 minutes, which means it wants more pods than you allow - Pods stuck in Pending for five minutes
- Failed attempts by the Cluster Autoscaler to add nodes
Troubleshooting common autoscaling issues
Match the symptom to its fix:
| Symptom | Likely cause | Fix |
|---|---|---|
HPA targets show <unknown> | Metrics Server down, or pods lack CPU requests | Check kubectl top pods, add requests |
| Scaling lags a spike | Slow pod startup or node provisioning | Raise minReplicas, shorten startup |
| Pods restart every few hours | VPA Recreate evicting on new recommendations | Narrow bounds or use InPlaceOrRecreate |
| Pods stay Pending, no new nodes | Node group at maximum or cloud quota reached | Read autoscaler logs, raise the limit |
| Replica count swings | HPA and VPA both acting on CPU | Move the HPA to an external metric |
| Nodes never scale down | Local storage, unmanaged pods, or strict PodDisruptionBudgets | Add safe-to-evict annotations where safe |
Known autoscaling limitations
Some limits remain no matter how you configure things:
- Metrics delay: Metrics Server reads usage every 15 seconds, and the HPA checks every 15 seconds, so up to 30 seconds can pass before the HPA asks for a new pod.
- Indirect signals: CPU and memory show how hard a pod works, which can differ from how many users are waiting. A pod stuck waiting on a slow database uses little CPU, so it looks idle while requests pile up.
- Local storage: by default, the Cluster Autoscaler keeps any node running a pod that stores data on that node's own disk, so clusters with many such pods shrink slowly.
- Bursty traffic: a spike that ends faster than a new pod can start is over before the extra capacity arrives.
Implementation guide for Kubernetes autoscaling
Planning your autoscaling implementation
Before you change anything, record a week of normal CPU use, memory use, request rate, and queue length for each app. Run each app through the selector, then write down how fast it must respond and how much it may cost.
Step-by-step autoscaling configuration
This Kubernetes autoscaling tutorial sets things up in order, because each step relies on the one before it:
- Install Metrics Server: apply its
components.yamlfrom the latest release, then confirmkubectl top nodesreturns data. - Add the HPA: apply the
webexample from this guide and check that its targets show percentages. - Add VPA for memory-intensive workloads: install VPA, apply the
dbmanifest in Off mode, and review recommendations after a week. - Enable the Cluster Autoscaler: turn it on for each node pool through your provider's console or command-line tool, and set a minimum and maximum node count.
- Validate with load: send test traffic with a load-testing tool such as k6, then watch
kubectl get hpa web --watchand the node count.
Scaling autoscaling across large and complex clusters
When many teams share one cluster, give autoscaling the same rules and reviews as any other setting:
- Templates: put tested HPA and VPA settings in Helm charts, which are reusable app packages, so every team starts from the same defaults.
- GitOps: store the settings in Git and apply them with Argo CD or Flux, so someone reviews every change.
- Policy enforcement: use Kyverno or OPA Gatekeeper to reject pods without resource requests.
Frequently asked questions
What is autoscaling in Kubernetes?
Kubernetes autoscaling adds or removes capacity automatically as demand changes. The HPA changes how many pods run, VPA changes each pod's CPU and memory, the Cluster Autoscaler adds and removes nodes, and KEDA scales apps on outside events, even down to zero.
How do you scale pods in Kubernetes?
Run kubectl scale deployment web --replicas=5 for a one-time change. For automatic scaling, create a HorizontalPodAutoscaler with kubectl autoscale or a YAML manifest. The HPA then adjusts the replica count every 15 seconds against your target.
What are the different types of Kubernetes autoscaling?
Four types cover most clusters: the Horizontal Pod Autoscaler for replicas, the Vertical Pod Autoscaler for per-pod resources, the Cluster Autoscaler for nodes, and KEDA for event-driven scaling. Karpenter is a faster alternative to the Cluster Autoscaler.
Can HPA scale to zero?
Yes, with limits. Kubernetes v1.37 enables minReplicas: 0 by default as a beta feature, but only for HPAs that scale on object or external metrics. CPU and memory cannot trigger it. KEDA scales to zero on any supported version.
Do managed Kubernetes services support autoscaling?
Yes. The HPA and VPA run on any standard Kubernetes cluster, managed or not. For nodes, most managed services offer a built-in Cluster Autoscaler that you switch on per node pool. Rackspace Spot includes one in every cluster at no extra cost.
Choosing your Kubernetes autoscaling stack
Each autoscaler covers one part of the cluster, but nodes are what you pay for. Autoscaling cuts how many nodes you run, and the price of each node sets how low the bill can go.
Rackspace Spot prices nodes through an open-market auction. You bid for servers, bids start at $0.001 an hour, and prices rise only when more people bid for the same capacity. The managed control plane, the part of Kubernetes that runs the cluster itself, costs nothing extra, and a working cluster starts at $7.20 a month.
Its built-in autoscaler is the same Cluster Autoscaler covered above, run for you, and one bid per cluster can autoscale at a time. A spot node can be taken back when someone outbids you, so spot capacity suits work that can restart safely, such as queue workers, batch jobs, and build and test runners.
Pick your pair from the selector, apply the manifests in this guide, and get started with Rackspace Spot to watch them scale on real nodes.