Cluster Autoscaler in Kubernetes

Cluster Autoscaler in Kubernetes

A plain-English, production-minded guide to how Kubernetes adds and removes servers on its own, why it sometimes refuses to, and how to run it without nasty surprises.

Picture a pizza shop on a quiet Tuesday afternoon. Two cooks, two ovens, plenty of space. Then a big cricket match ends, and within ten minutes two hundred orders pour in. If the owner has to phone a staffing agency, wait for new cooks to arrive, and only then switch on more ovens, half the customers will walk away hungry. On the other side, if the owner keeps twenty cooks standing around every quiet afternoon, the shop slowly goes broke.

A Kubernetes cluster lives with this exact problem every single day. Traffic jumps, a batch job starts, a marketing email goes out, and suddenly the servers have no room left. A few hours later the rush is over, half the servers sit idle, and the cloud bill keeps ticking anyway. The Cluster Autoscaler is the part of the Kubernetes ecosystem that handles this calmly and automatically. It adds servers when pods have nowhere to run, and it removes servers when they are no longer needed. This guide explains how it thinks, how it works inside, and how to run it in production.

1Why Clusters Must Grow and Shrink

Before learning any tool, it helps to feel the problem it solves.

Every application needs computers to run on. In Kubernetes, those computers are called nodes. If you buy too few nodes, your application slows down or stops working when many users arrive. If you buy too many, you pay for computers that do nothing. Cloud providers bill you for every running virtual machine, usually by the second, so an idle machine is simply money leaving your account.

Traffic is rarely flat. A food-delivery app is busy at lunch and dinner. A ticket-booking site explodes when a popular concert goes on sale. A payroll system works hard on the last day of the month. A fixed-size cluster has to be sized for the busiest moment, which means it is wasteful for the other twenty-three hours of the day. The smarter plan is a cluster that breathes: it grows when work arrives and shrinks when work leaves.

Three different things can scale

Kubernetes has more than one autoscaler, and beginners often mix them up. Each one answers a different question.

  • How many copies of my app should run? The Horizontal Pod Autoscaler (HPA) answers this by adding or removing pods.
  • How big should each copy be? The Vertical Pod Autoscaler (VPA) answers this by adjusting the CPU and memory each pod asks for.
  • How many servers do I need to hold all those copies? The Cluster Autoscaler answers this by adding or removing nodes.
flowchart TB
  A["Traffic grows"] --> B["HPA creates more pods"]
  B --> C["Scheduler tries to place the pods"]
  C --> D{"Is there room on existing nodes?"}
  D -->|"Yes"| E["Pods start running"]
  D -->|"No"| F["Pods wait in Pending state"]
  F --> G["Cluster Autoscaler adds nodes"]
  G --> E
    
Figure 1: The autoscalers work as a chain. Pod scaling happens first, node scaling follows.
Everyday Analogy

Think of a hotel. The guests are pods and the rooms are nodes. A travel agency (the HPA) decides how many guests to send. When guests arrive and every room is taken, the hotel manager (the Cluster Autoscaler) opens another floor. When whole floors sit empty for a long time, the manager closes them to save electricity. The manager never decides how many guests come. The manager only makes sure there are enough rooms.

10 sec
default time between looks at the cluster
10 min
default wait before an idle node is removed
3 layers
pod count, pod size and node count
i
Remember

The Cluster Autoscaler does not watch your website traffic or your CPU graphs. It watches one thing above all: pods that cannot find a place to run.

2Core Concepts From Zero

A handful of words carry almost the whole story. Learn them once and everything else becomes easy.

Concept

Node

One computer, real or virtual, that runs your containers. In the cloud it is usually a virtual machine such as an EC2 instance.

Concept

Pod

The smallest unit Kubernetes runs. It wraps one or more containers that always live together on the same node.

Concept

Resource Request

The amount of CPU and memory a pod promises it needs. Kubernetes reserves this amount on a node for the pod.

Concept

Resource Limit

The maximum a pod is allowed to use. Going over the memory limit gets the container killed.

Concept

Scheduler

The Kubernetes component that picks which node each new pod will run on, based on requests and rules.

Concept

Pending Pod

A pod that has been created but not placed on any node yet. If the scheduler says no node fits, it is called unschedulable.

Concept

Allocatable

The part of a node that pods can actually use. Some CPU and memory is always kept back for the operating system and Kubernetes itself.

Concept

Node Group

A set of identical nodes managed together, such as an AWS Auto Scaling group. The autoscaler changes the size of these groups.

Requests are the currency of autoscaling

This is the single most important idea in the whole article. The scheduler does not look at how busy a node really is. It looks at the requests written in pod definitions and adds them up. If a node has 4 CPUs available and four pods each request 1 CPU, the node is full in the eyes of the scheduler, even if those pods are actually sitting idle and using almost nothing.

The Cluster Autoscaler uses the very same arithmetic. It makes its decisions from requests, not from live usage. That is why a cluster can look half empty on a monitoring dashboard and still be unable to take one more pod. It is also why pods without any requests confuse the autoscaler badly, a problem we return to later.

Everyday Analogy

A cinema sells seats, not bodies. If you reserve three seats for your family but only two people come, the third seat stays empty, yet nobody else can sit there. Requests are seat reservations. The scheduler counts reservations, not who actually sat down.

Rules that narrow the choices

Pods can carry extra rules. A node selector says “only run me on nodes with this label”. A taint on a node says “keep out unless you carry my matching toleration”. Affinity and topology spread rules say things like “keep my replicas in different zones”. These rules matter a lot, because the autoscaler can only add a node that would truly accept the waiting pod. A node of the wrong kind, however large, does not help.

!
Watch Out

High CPU usage on a node does not trigger scale-up, and low usage does not by itself trigger scale-down. Requests and pending pods drive everything.

3What Cluster Autoscaler Is, and Is Not

A short history, a clear definition, and a list of common misunderstandings.

The Cluster Autoscaler, often shortened to CA, is an open-source program that lives in the Kubernetes autoscaler repository and is maintained by the Kubernetes SIG Autoscaling community. It has been part of the ecosystem since the mid-2010s, which makes it one of the most battle-tested pieces of the platform. It runs as an ordinary pod inside your cluster, talks to the Kubernetes API on one side and to your cloud provider on the other, and changes the number of nodes in your node groups.

Its job can be said in two sentences. If some pods cannot be scheduled because no node has enough free room, and a new node from one of your groups would fix that, add the node. If some nodes have been mostly unused for a while and their pods could happily live elsewhere, remove those nodes.

The Cluster Autoscaler does not predict the future. It reacts to pods that are waiting.

How it differs from its neighbours

ToolWhat it changesWhat triggers itSpeed
Horizontal Pod AutoscalerNumber of pod copiesMetrics such as CPU or custom valuesSeconds to a minute
Vertical Pod AutoscalerCPU and memory requests of podsObserved usage over timeSlow, often needs pod restarts
Cluster AutoscalerNumber of nodes in existing node groupsPending pods and underused nodesMinutes, limited by VM boot time
KarpenterNodes launched directly, any fitting typePending pods and consolidation checksOften faster, avoids group indirection

Three popular misunderstandings

  • “It scales my pods.” No. It never changes how many pods a Deployment has. That is the HPA’s job.
  • “It reacts to CPU spikes.” No. It reacts to pods that cannot be scheduled, which is a scheduling event, not a usage event.
  • “It makes my nodes bigger.” No. It only adds or removes whole nodes using templates you already defined in node groups.
i
Good to Know

Managed offerings hide some of this work. Google Kubernetes Engine has autoscaling built into its managed control plane. On Amazon EKS and Azure AKS you can either run the open-source autoscaler yourself or use the provider’s newer alternatives.

4Architecture and Components

One small program, several clear responsibilities.

The autoscaler is a single binary running one main loop. It does not need a database. It reads the world from the Kubernetes API, makes decisions in memory, and writes its orders to the cloud provider. Here is the big picture.

flowchart LR
  U["Users and CI systems"] --> API["Kubernetes API server"]
  API --> SCH["kube-scheduler"]
  SCH -->|"cannot place pod"| PEND["Pending pods"]
  CA["Cluster Autoscaler"] -->|"reads pods and nodes"| API
  PEND --> CA
  CA -->|"asks to change size"| CP["Cloud provider API"]
  CP --> NG1["Node group A"]
  CP --> NG2["Node group B"]
  NG1 --> N1["New nodes"]
  N1 -->|"register and become Ready"| API
  CA -->|"writes health and status"| CM["Status ConfigMap in kube-system"]
    
Figure 2: The autoscaler sits between the Kubernetes API and the cloud provider.

The moving parts inside

Component

Main Loop

Wakes up every ten seconds by default, refreshes its view of the cluster, and decides whether to scale up, scale down, or do nothing.

Component

Cluster State Registry

Remembers which nodes are healthy, which groups are growing, and which groups recently failed so they can be avoided for a while.

Component

Cloud Provider Interface

A plug-in layer with one implementation per cloud. It knows how to read group sizes and change them.

Component

Scheduling Simulator

Reuses the real scheduler’s logic to ask a pretend question: if this node existed, would this pod fit on it?

Component

Estimator

Works out how many new nodes are needed by packing the waiting pods into imaginary nodes, like fitting boxes into trucks.

Component

Expander

The tie-breaker. When several node groups could help, it picks one using a chosen strategy.

Component

Scale-Down Planner

Tracks which nodes look unneeded, for how long, and whether their pods can move safely.

Component

Actuator

Carries out the plan: taints nodes, evicts pods, and finally tells the cloud to delete the machine.

Where it runs

On a self-managed cluster or on Amazon EKS, the autoscaler normally runs as a Deployment in the kube-system namespace on one of your worker nodes. You may run more than one replica, but only one is active at a time because they elect a leader. On Google Kubernetes Engine, the autoscaler is part of the managed control plane, so you configure it but never see its pod.

Everyday Analogy

Imagine a building manager with a clipboard. Every ten seconds the manager walks the halls, counts who is waiting outside without a room, checks which rooms are nearly empty, and phones the cleaning agency to open or close floors. The scheduling simulator is the manager’s floor plan, used to test “would these guests fit if I opened that wing?” before spending any money.

5How Scale-Up Works Internally

From a pod stuck in Pending to a fresh node, step by step.

Scale-up begins when the scheduler gives up on a pod. The scheduler writes a condition on the pod saying it is unschedulable, and that is the signal the autoscaler waits for. On its next scan it collects all such pods. Pods that are brand new may be ignored for a moment so the scheduler gets a fair chance first.

flowchart TD
  A["Scan every 10 seconds"] --> B{"Any unschedulable pods?"}
  B -->|"No"| C["Check scale-down instead"]
  B -->|"Yes"| D["Build a template node for each group"]
  D --> E["Simulate: would the pending pods fit?"]
  E --> F{"Does any group work?"}
  F -->|"No"| G["Record a NotTriggerScaleUp event"]
  F -->|"Yes"| H["Expander picks one group"]
  H --> I["Increase the group size"]
  I --> J["Wait for nodes to register"]
  J --> K["Scheduler places the pending pods"]
    
Figure 3: The scale-up decision path.
1

Collect the stuck pods

The autoscaler lists pods that the scheduler marked unschedulable and filters out ones that could never be fixed by adding nodes.

2

Imagine a new node from each group

For every node group it builds a template: the CPU, memory, labels and taints a new node of that group would have.

3

Test the fit

Using the scheduler’s own rules, it checks which waiting pods would fit on each template node.

4

Count the nodes needed

The estimator packs pods into imaginary nodes to find how many are required, never going past the group’s maximum size.

5

Choose a winner

If several groups qualify, the expander strategy decides which one to grow.

6

Order the nodes

The cloud provider layer raises the desired size of the chosen group. The cloud then boots the machines.

Template nodes, in simple words

The autoscaler cannot ask a node that does not exist yet how big it will be, so it guesses from a template. If the group already has a running node, that node is copied as the model. If the group is empty, the autoscaler asks the cloud provider or reads tags on the group. System pods that run on every node, called DaemonSets, are subtracted from the template, because they will take their share of each new machine before your pods get any.

When the cloud says no

Sometimes a group is asked to grow but nodes never appear: the cloud has no capacity of that machine type, a quota is exhausted, or the machine boots but never joins the cluster. The autoscaler waits up to a limit, fifteen minutes by default, then gives up on that attempt and places the group in a temporary backoff. During backoff it tries other groups instead. Repeated failures lengthen the backoff, so a broken group is not hammered over and over.

Everyday Analogy

You need a taxi big enough for six friends. You phone several taxi companies and ask whether their vans fit six people with luggage. Only some can. You pick one, and if the van never turns up, you wait a while, then call a different company and stop calling the first for a bit. That is template matching, expansion and backoff in one story.

!
Watch Out

If a single pod asks for more CPU or memory than the largest node type in any group, no amount of waiting will help. The pod will stay Pending forever and the autoscaler will log that no group can fit it.

6How Scale-Down Works Internally

Removing a server is much more delicate than adding one, so the autoscaler is deliberately cautious.

Adding a node is almost risk-free. Removing a node can hurt running users if done carelessly. For that reason scale-down has many safety checks and long waiting times. A node is removed only when every check says it is safe.

flowchart TD
  A["Compute utilization of every node"] --> B{"Below the threshold, 50 percent by default?"}
  B -->|"No"| Z["Keep the node"]
  B -->|"Yes"| C["Mark the node as unneeded"]
  C --> D{"Unneeded for 10 minutes?"}
  D -->|"No"| C
  D -->|"Yes"| E{"Can all its pods fit elsewhere?"}
  E -->|"No"| Z
  E -->|"Yes"| F["Taint the node and evict its pods"]
  F --> G["Delete the machine from the node group"]
    
Figure 4: The scale-down decision path.

How utilization is measured

For each node the autoscaler adds up the requests of all pods on it and divides by the node’s allocatable amount, once for CPU and once for memory. The larger of the two ratios is the node’s utilization. Take a node with 4 CPUs allocatable where pods request 1.2 CPUs in total: that is 30 percent. If memory is at 45 percent, the node’s utilization is 45 percent. Both are under the default threshold of 50 percent, so the node becomes a candidate.

Safety checks before removal

Being under the threshold is only the first gate. The autoscaler then simulates moving every pod to other nodes. The node is spared if any of these is true:

  • A pod is not owned by a controller such as a Deployment, so nothing would recreate it after eviction.
  • A pod uses local storage that would be lost, unless it is marked as safe to evict.
  • A pod carries the annotation cluster-autoscaler.kubernetes.io/safe-to-evict set to false.
  • Evicting a pod would break a PodDisruptionBudget, a promise that a minimum number of replicas stay up.
  • A pod has strict placement rules and no other node in the cluster would accept it.
  • The node would drop the group below its minimum size, or the node is annotated to disable scale-down.

The graceful goodbye

When a node passes all checks, the autoscaler first adds a taint so that no new pods land on it. Then it asks Kubernetes to evict each pod politely through the Eviction API, which respects disruption budgets and the pod’s shutdown grace period. Only when the node is empty does it tell the cloud provider to delete the machine and shrink the group.

Everyday Analogy

A supermarket has ten checkout lanes. Closing one lane is sensible only if its queue has been short for a good while and its customers can easily join other lanes. The manager would never close a lane while someone is halfway through paying. The waiting time, the “can they move?” check and the polite hand-over are all part of the same caution.

i
Tip

After a scale-up, the autoscaler also waits ten minutes by default before it considers any scale-down. This stops the cluster from adding a node and deleting it again in a nervous loop.

7Data Flow and Lifecycle of a Node

Follow one burst of traffic from the first new pod to the last deleted machine.

Now let us put the pieces together. Here is the life of a node, told as a conversation between the components.

sequenceDiagram
  participant D as Deployment
  participant S as Scheduler
  participant C as Cluster Autoscaler
  participant P as Cloud Provider
  participant K as New Node
  D->>S: Create 8 new pods
  S->>S: Only 2 pods fit on existing nodes
  S-->>C: 6 pods marked Unschedulable
  C->>C: Simulate and choose a node group
  C->>P: Raise desired size by 2
  P->>K: Boot two virtual machines
  K->>S: Nodes join and become Ready
  S->>K: Place the pending pods
  Note over C,K: Later, when load drops, scale-down reverses this
    
Figure 5: One scale-up from request to running pods.

A worked example with real numbers

Suppose a cluster has three nodes, each with 4 CPUs available to pods, so 12 CPUs in total. Existing pods request 10 CPUs, leaving 2 CPUs free. Each pod of a web service requests 1 CPU. A flash sale begins, and the HPA raises the web service by 8 pods.

  • Two of the new pods fit into the free 2 CPUs. Six pods stay Pending.
  • Each new node can hold four such pods, so six pods need two nodes (6 divided by 4 is 1.5, rounded up to 2).
  • The autoscaler asks the node group to grow by two.
0s

HPA creates the pods

Eight new pods appear. The scheduler places two and marks six unschedulable within a few seconds.

~10s

Autoscaler notices

On its next scan it sees six Pending pods, simulates, and orders two nodes.

1-3m

Machines boot

The cloud starts the virtual machines, the operating system boots, and the kubelet registers with the cluster.

+30s

Pods start

The scheduler places the waiting pods on the new nodes. Container images are pulled and the pods become Ready.

Night

Load falls, scale-down starts

The HPA removes pods. The two extra nodes drop under half utilization, stay unneeded for ten minutes, get drained, and are deleted.

The exact times depend on your cloud, instance type and image size, so treat them as rough guides. The important lesson is that a new node is never instant. From the first Pending pod to a running pod often takes several minutes, and that delay shapes many design choices later in this guide.

i
Good to Know

The autoscaler keeps a status record in a ConfigMap named cluster-autoscaler-status inside kube-system. It lists the health of the cluster and the scale-up and scale-down state of each node group, which makes it the first place to look when behaviour seems odd.

8Expanders and Tuning Knobs

Two sets of dials control almost all of the autoscaler’s personality.

Expanders: choosing which group to grow

When more than one node group could host the waiting pods, the expander breaks the tie. You pick the strategy with a command-line flag. You can even chain several, for example priority first and least-waste as a tie-breaker.

ExpanderHow it choosesGood for
randomPicks any qualifying group (the default)Simple clusters with similar groups
most-podsPicks the group that lets the most pending pods be scheduledMixed workloads with node selectors
least-wastePicks the group leaving the least idle CPU and memory after scalingCost-conscious clusters with different sizes
priorityFollows a ranked list you write in a ConfigMapPreferring cheap spot groups before on-demand ones
pricePicks the cheapest option using provider pricingOnly available with some providers
grpcAsks an external service of your own to decideCustom business rules

The settings that matter most

The defaults below come from the open-source project. Managed services may change them, so always check your provider’s documentation.

SettingDefaultWhat it controls
scan-interval10 secondsHow often the main loop runs
scale-down-utilization-threshold0.5Utilization below which a node is a removal candidate
scale-down-unneeded-time10 minutesHow long a node must stay unneeded before removal
scale-down-delay-after-add10 minutesPause on scale-down after any scale-up
scale-down-delay-after-failure3 minutesPause after a failed scale-down
max-node-provision-time15 minutesHow long to wait for a new node before giving up
max-graceful-termination-sec600 secondsLongest wait for pods to finish during a drain
balance-similar-node-groupsfalseKeep similar groups, such as one per zone, evenly sized
expanderrandomStrategy for choosing a group to grow

Each node group also has its own minimum and maximum size. These two numbers are your safety rails: the minimum guarantees a baseline of capacity, and the maximum caps the bill. You can also set cluster-wide limits on total cores, total memory and total node count.

Everyday Analogy

Think of a thermostat. The scan interval is how often it checks the room. The thresholds and waiting times are how patient it is before it switches the heater on or off. Set it too twitchy and the heater clicks on and off all day. Set it too lazy and the room freezes before anything happens.

i
Tip

Change one setting at a time and watch the cluster for a few days. Autoscaler behaviour is a conversation between your workloads, your cloud and these dials, so small changes can have surprising effects.

9Working With HPA, VPA and Spare Capacity

The autoscalers are teammates. Used together they are strong, used carelessly they fight.

HPA and Cluster Autoscaler

This is the classic pair. The HPA reacts to load by creating pods. When those pods cannot be placed, the Cluster Autoscaler provides nodes. Both are needed: HPA alone runs out of room, and Cluster Autoscaler alone has nothing to react to. The HPA relies on a metrics source such as the Kubernetes Metrics Server to read usage. Event-driven tools like KEDA can feed the HPA from queues and other signals, which suits background workers.

VPA and Cluster Autoscaler

The VPA changes the requests of pods, usually by restarting them. Better-sized requests give the autoscaler a more truthful picture, which is a real benefit. The warning is to avoid letting VPA and HPA act on the same CPU or memory signal for the same workload, because they will pull in opposite directions.

The waiting problem and the headroom trick

Remember that a new node takes minutes to arrive. During a sudden spike, users may wait that long. A popular fix is overprovisioning, also called headroom. You run a small Deployment of dummy “pause” pods that do nothing but reserve CPU and memory. These pods get a very low priority, lower than every real workload.

flowchart LR
  PP["Low priority pause pods hold spare room"] --> NEW["A real pod arrives"]
  NEW -->|"preempts a pause pod"| RUN["Real pod starts in seconds"]
  NEW --> EV["Evicted pause pod becomes Pending"]
  EV --> CA["Cluster Autoscaler adds a node in the background"]
  CA --> PP
    
Figure 6: Pause pods turn node start-up delay into invisible background work.

When a real pod arrives and the cluster is otherwise full, Kubernetes evicts a pause pod instantly to make space. The real pod starts in seconds. The evicted pause pod becomes Pending, which triggers the autoscaler to add a node, quietly rebuilding the spare room. You pay for a little unused capacity and receive fast reaction in return.

!
Watch Out

The autoscaler ignores pods whose priority is below a cutoff, which is minus ten by default. Give your pause pods a priority such as minus one, not minus one thousand, or they will never cause nodes to be added.

Everyday Analogy

A restaurant keeps a few tables with a “reserved” card on them. When a real party walks in, the card is removed and they sit down at once, while a waiter quietly sets up a new reserved table in the back room. The customers never notice the work.

10Cloud Provider Behavior

The idea is the same everywhere. The plumbing underneath differs.

CloudNode group is calledNotes
AWS (EKS)Auto Scaling group, often via managed node groupsGroups are found by tags or by name; you run the autoscaler yourself
Google Cloud (GKE)Managed instance group inside a node poolBuilt in; offers profiles such as balanced and optimize-utilization
Microsoft Azure (AKS)Virtual machine scale set inside a node poolEnabled per node pool with min and max counts

Amazon Web Services details

On AWS, the autoscaler can discover groups automatically by looking for two tags on each Auto Scaling group: one marking it as enabled and one carrying your cluster name. Alternatively you list groups by name with their minimum and maximum sizes. Several lessons come up again and again.

  • Do not fight it. Do not attach the Auto Scaling group’s own scaling policies, and do not change desired capacity by hand, while the Cluster Autoscaler is in charge. Two controllers managing one number leads to chaos.
  • Match the version. Use an autoscaler release whose minor version matches your Kubernetes minor version, because it embeds scheduler logic from that release.
  • Similar instance types. If one group mixes instance types, choose types with the same CPU and memory. The autoscaler builds its template from one type, so a wildly different type makes its predictions wrong.
  • Zones and storage. Disks such as EBS volumes live in a single zone. If pods use them, create one node group per zone and enable balancing between similar groups, so a pod needing a zone can always get a node there.
  • Scaling from zero. A group may rest at zero nodes. To do this, the autoscaler needs to know what a node would look like, so you add tags for labels and taints on the group.

Google Cloud and Azure in short

On GKE you simply switch autoscaling on for a node pool and set its limits. The service hides the controller and offers profiles that trade speed against cost: one favours availability, the other removes underused nodes more eagerly. GKE Autopilot goes one step further and removes node management from you altogether. On AKS you enable the autoscaler per node pool with minimum and maximum counts, and a profile object holds the fine-tuning settings.

i
Good to Know

Quotas matter. If your account is limited to a certain number of machines of a type, the autoscaler can ask for more and the cloud will simply refuse. Always check quotas before a launch event, not during it.

11Advantages, Disadvantages and Trade-offs

No tool is perfect. Knowing the costs helps you choose wisely.

Advantages

  • Cuts waste by removing idle nodes automatically.
  • Prevents Pending pods caused by lack of room.
  • Mature, widely used and well documented.
  • Works across many clouds with the same concepts.
  • Respects pod disruption budgets and scheduling rules.
  • Supports scale-from-zero for batch and GPU pools.

Disadvantages

  • Reactive, so users may wait minutes during sudden spikes.
  • Depends on node groups you must design and maintain.
  • Bad requests produce bad decisions.
  • Scale-down is slow and often blocked by small details.
  • Cannot choose a brand new instance type on its own.
  • Version matching and tuning need ongoing care.

Cluster Autoscaler or Karpenter?

Karpenter is a newer approach, reached its 1.0 release in 2024, and is now developed within the Kubernetes SIG Autoscaling community with a mature AWS implementation. Instead of growing fixed node groups, it looks at the waiting pods and launches machines of whatever suitable type fits them best, then regularly consolidates workloads onto fewer nodes. Neither is simply better.

QuestionCluster AutoscalerKarpenter
How are nodes organised?Pre-defined node groupsRules describing allowed machine shapes
Instance choiceFixed per groupPicked per batch of pods
Clouds supportedMany providersStrongest on AWS, growing elsewhere
Operational styleFamiliar, predictable, simple to reason aboutFlexible, more automatic, newer concepts to learn
Best fitStable fleets, multi-cloud teams, teams wanting well-known behaviourDiverse or spiky workloads that benefit from fast, right-sized nodes
i
Tip

Do not migrate just because something is newer. If your current autoscaling is quiet, cheap and boring, that is a good sign. Consider a change when node-group sprawl or slow reaction is genuinely hurting you.

12Security

The autoscaler can create and destroy servers. That is real power, so treat it carefully.

If an attacker or a bug controlled the autoscaler, they could launch hundreds of machines and run up a large bill, or delete nodes and cause an outage. Security here is mostly about giving it only the permissions it needs and keeping it healthy.

Cloud permissions

The autoscaler needs permission to read group information and to change group sizes or terminate instances inside those groups. Grant only those actions. Where the cloud supports it, restrict the write actions to groups carrying your cluster’s tag, so that a mistake in one cluster cannot touch another. Use short-lived workload identity, such as IAM roles for service accounts on AWS or workload identity on Google Cloud, rather than long-lived keys stored in a secret.

Kubernetes permissions

Inside the cluster, the autoscaler uses a service account with a role that allows it to read pods, nodes and related objects, evict pods, and update its own status ConfigMap and leader-election lease. Review the standard manifest and remove anything you do not use. Run it in kube-system with a high priority class so it is never the first pod to be pushed out under pressure.

Protecting the bill and the fleet

  • Always set maximums. A node group maximum and a cluster-wide node limit are your cost firewall.
  • Keep it off nodes it manages. Run the autoscaler on a small, stable node group it does not shrink, so it cannot delete the machine it lives on.
  • Harden nodes the usual way. Patched images, restricted network rules and minimal permissions on the node role still apply to every machine it creates.
  • Watch for abuse. A user who can create unlimited large pods can cause large scale-ups. Use namespace resource quotas and limit ranges to put a ceiling on what any team can request.
Everyday Analogy

Give the building manager a company credit card with a spending limit and a list of approved suppliers, not an unlimited card. If the card is ever lost, the damage stays small.

!
Watch Out

Resource quotas are not only about fairness. In an autoscaled cluster they are also a safety net against runaway cost.

13Monitoring, Logging and Metrics

You cannot trust what you cannot see. The autoscaler gives you three windows into its mind.

Window one: events

Kubernetes events are short notes attached to pods and nodes. The autoscaler writes a note named TriggeredScaleUp on pods that caused a scale-up, and NotTriggerScaleUp on pods it could not help, with a reason such as “no node group fits” or “max size reached”. It also records scale-down events on nodes. Reading the events of a Pending pod is usually the fastest way to learn why it is stuck.

Window two: logs and the status ConfigMap

The autoscaler logs each loop’s key decisions. Raising log verbosity shows the simulation details and which blockers kept a node alive, but it is noisy, so use it for investigations rather than all the time. The status ConfigMap in kube-system shows cluster health, per-group sizes, and whether a group is in backoff.

Window three: metrics

The autoscaler exposes Prometheus metrics, by default on port 8085. These are the ones worth putting on a dashboard.

MetricWhat it tells you
cluster_autoscaler_unschedulable_pods_countHow many pods are waiting right now
cluster_autoscaler_nodes_countNode totals by state, such as ready or unready
cluster_autoscaler_scaled_up_nodes_totalHow many nodes were added over time
cluster_autoscaler_scaled_down_nodes_totalHow many nodes were removed, with reasons
cluster_autoscaler_failed_scale_ups_totalScale-ups that never produced nodes
cluster_autoscaler_function_duration_secondsHow long each part of the loop takes
cluster_autoscaler_errors_totalErrors by type
cluster_autoscaler_last_activityWhen each step last ran, useful for spotting a stuck loop

What to alert on

  • Pending pods stay above zero for longer than your tolerance, for example fifteen minutes.
  • Failed scale-ups keep climbing, which hints at quota or capacity trouble.
  • The last-activity time stops advancing, meaning the loop may be hung or unhealthy.
  • Node count nears the cluster maximum, so you are warned before the ceiling blocks growth.
  • Average requested-to-allocatable ratio stays very low for days, hinting at inflated requests or a wasteful minimum size.
Everyday Analogy

Events are the manager’s sticky notes on each door, logs are the daily diary, and metrics are the wall chart showing trends. When a guest complains, you read the sticky note. When you want to know whether this week was worse than last week, you read the chart.

14Design Patterns and Anti-Patterns

Habits that make autoscaling smooth, and habits that quietly break it.

Patterns that work

Pattern

Workload-Shaped Node Groups

Keep separate groups for general apps, memory-heavy jobs, GPU work and system add-ons. Taints and selectors steer pods to the right group.

Pattern

Spot First, On-Demand Fallback

Use the priority expander to try cheaper interruptible machines first and fall back to regular ones if they are unavailable.

Pattern

One Group Per Zone

With zone-bound storage, create a group in each zone and enable balancing so capacity grows evenly and pods always find a home.

Pattern

Headroom With Pause Pods

Reserve a thin layer of spare room with low-priority placeholder pods so spikes meet capacity that is already warm.

Pattern

Scale-to-Zero Batch Pools

Let costly pools for nightly jobs or GPU training rest at zero nodes and wake only when work is queued.

Pattern

Disruption Budgets Everywhere

Give every important workload a sensible PodDisruptionBudget so drains are safe, yet not so strict that they are blocked.

Anti-patterns to avoid

ANTI-PATTERN 01Avoid
The habit

Deploying pods with no CPU or memory requests.

Why it hurts

The scheduler treats such pods as free, so it crams many onto one node. The autoscaler then sees nodes that look empty and tries to remove them, and never sees a need to add more. The result is crowded, unstable nodes.

Better approach

Require requests on every workload using a LimitRange or policy, and review them using real usage data.

ANTI-PATTERN 02Avoid
The habit

Changing group sizes by hand, or attaching cloud scaling policies, while the autoscaler manages the same group.

Why it hurts

Two controllers fight over one number. Nodes appear and vanish unpredictably and the autoscaler’s view of the world becomes wrong.

Better approach

Change minimum and maximum sizes instead, and let the autoscaler own the actual count.

ANTI-PATTERN 03Avoid
The habit

Setting a PodDisruptionBudget that allows zero disruptions, or running single-replica workloads that must never move.

Why it hurts

The node holding such a pod can never be drained. It stays forever, and your savings from scale-down shrink away.

Better approach

Run at least two replicas, allow at least one disruption, and spread them across nodes.

ANTI-PATTERN 04Avoid
The habit

Inflating requests “to be safe”, for example asking for four CPUs when two are used.

Why it hurts

The cluster fills up on paper long before it fills up in reality. The autoscaler faithfully buys machines to match the inflated numbers, and you pay for the padding.

Better approach

Right-size requests from measured usage, perhaps with VPA recommendations, and keep a modest safety margin.

ANTI-PATTERN 05Avoid
The habit

One enormous node group mixing machine types of very different sizes.

Why it hurts

The autoscaler builds its prediction from one type. If the cloud delivers a smaller one, pods still do not fit and the cycle repeats.

Better approach

Keep each group to instance types with matching CPU and memory.

15Best Practices and Common Mistakes

A checklist you can follow, then a troubleshooting path for the day something goes wrong.

Best practices

  • Write honest requests. Everything else depends on them.
  • Set sensible minimums and maximums. A minimum for a baseline, a maximum for cost safety.
  • Match versions. Upgrade the autoscaler together with Kubernetes, one minor version at a time.
  • Run it highly available. Two replicas with leader election and a critical priority class.
  • Use graceful shutdown. Give pods realistic grace periods and a preStop hook so drains do not drop requests.
  • Test scaling before you need it. Create a controlled load and watch pods, nodes and timings end to end.
  • Review quotas and limits quarterly. Cloud quotas, subnet IP space and node limits all cap how far you can grow.
i
Tip

Check that your subnets have enough free IP addresses. On some clouds every pod takes an IP, and a cluster can stop growing because the network ran out of addresses, not because of the autoscaler.

Common mistakes

  • Expecting instant reaction and skipping headroom for traffic spikes.
  • Leaving bare pods, or pods using local disk, on nodes you hoped would shrink.
  • Forgetting that DaemonSets and system pods can block scale-down on small clusters.
  • Setting a minimum size too high and then wondering why the bill never drops.
  • Ignoring the events on Pending pods, which usually explain the problem outright.

Troubleshooting: pods are Pending and no node appears

1

Read the pod events

Look for NotTriggerScaleUp and its reason. It often names the exact blocker, such as a selector no group satisfies.

2

Compare request and node size

Confirm the pod fits on the largest machine type in any group. If not, add a bigger group or shrink the request.

3

Check group limits

See whether the matching group is already at its maximum, or the cluster hit its total node or core limit.

4

Inspect the status ConfigMap

A group in backoff, or a cluster marked unhealthy, will pause scale-up until it recovers.

5

Look at the cloud side

Check quotas, machine availability in the zone, launch template errors, and whether new machines joined the cluster at all.

6

Verify permissions

Errors in the autoscaler logs about access denied usually mean its cloud role is missing an action.

Troubleshooting: idle nodes never go away

Work in the opposite direction. Check the node’s utilization against the threshold, look for blocking pods (bare pods, local storage, strict budgets, the do-not-evict annotation), confirm the group is above its minimum, and make sure no recent scale-up is still inside its cooling-off delay. The autoscaler’s logs usually say which pod blocked the node.

!
Watch Out

If more than a set share of nodes in the cluster are unhealthy, the autoscaler deliberately pauses itself, because acting on a broken picture could make things worse. Fix the unhealthy nodes first.

16Real-World and Industry Examples

How large teams think about node autoscaling, plus a few typical scenarios.

Google Kubernetes Engine

Google ships the autoscaler as a built-in feature of its managed Kubernetes service. Customers enable it per node pool and choose between profiles that favour availability or aggressive cost saving. It is a clear example of the same ideas in this article, hidden behind a settings page.

Airbnb

Airbnb has published engineering writing on how it scales its Kubernetes clusters dynamically to match demand, describing the work of adapting node scaling to its own workload mix. The lesson for smaller teams is that real fleets usually need extra tuning on top of the defaults.

Zalando

The European fashion retailer Zalando has openly shared its approach to running a very large number of Kubernetes clusters on AWS, where node autoscaling is a core building block. Their public material shows the value of treating cluster setup and autoscaling configuration as repeatable, automated infrastructure.

Typical scenario: a retail sale

An online store expects a big sale at noon. The team adds headroom pods an hour before, raises the node group maximum, checks quotas, and lets the HPA and autoscaler handle the climb. After the sale they lower the headroom and let scale-down trim the extra nodes overnight.

Typical scenario: nightly data jobs

A data team runs heavy processing from midnight to four in the morning. A dedicated, tainted node group sits at zero during the day. When the jobs are submitted, pods go Pending, nodes appear, the work runs, and the group returns to zero. The company pays for those machines only while the jobs run.

Typical scenario: machine learning on GPUs

GPU machines are expensive. A GPU node group with scale-from-zero and a short unneeded time avoids paying for idle accelerators. Taints keep ordinary pods away, so the costly nodes serve only the training and inference pods that need them.

17Getting Resource Requests Right

Every autoscaling problem eventually leads back to one humble field in the pod definition.

We have said many times that the autoscaler works from requests. This chapter explains how to choose good ones, because a team that gets this right will see the rest of the system behave almost by itself. A team that gets it wrong will fight strange symptoms for months.

Too low, too high, and just right

If a request is too low, the scheduler believes the pod is tiny. It places many such pods on one node. When they all become busy at once, the node runs out of real CPU or memory. CPU shortage makes everything slow. Memory shortage is worse, because the kernel starts killing containers. The autoscaler never saw a problem, since on paper the node was never full.

If a request is too high, the opposite happens. The cluster looks full while the machines are actually quiet. The autoscaler buys more nodes to satisfy the paper demand, and the bill grows with no benefit to users. This waste is invisible unless you compare requested amounts with measured usage.

A healthy request sits a little above the typical busy usage of the pod, with room for normal spikes. Many teams aim for the request to cover the usual high point of the day, not the rarest peak of the year.

Everyday Analogy

Booking a table at a restaurant works the same way. Tell them you are coming with two friends when you really bring ten, and the table is too small and everyone is squeezed. Book a banquet hall for two people, and the restaurant turns away paying guests while your hall sits empty. An honest booking helps the whole restaurant plan its evening.

Quality of Service classes

Kubernetes sorts pods into three classes based on how requests and limits are set. These classes decide who is protected and who is sacrificed when a node runs short of memory.

ClassHow you get itWhat it means
GuaranteedRequests equal limits for CPU and memory in every containerMost protected, last to be killed under pressure
BurstableAt least one request set, but not equal to limitsMiddle ground, common for ordinary services
BestEffortNo requests and no limits at allFirst to be killed, and invisible to the autoscaler’s maths

For autoscaling, the key point is that BestEffort pods look free. They do not make a node look fuller, so they never contribute to scale-up and they quietly crowd nodes that the autoscaler believes are empty.

Guardrails you can put in place

  • LimitRange. A namespace rule that gives default requests and limits to pods that forget to set them, and can also reject absurd values.
  • ResourceQuota. A namespace rule that caps the total CPU, memory and pod count a team may request, protecting both fairness and the cloud bill.
  • Admission policies. Cluster-wide checks that block deployments without requests at all.
  • VPA in recommendation mode. The Vertical Pod Autoscaler can watch real usage and publish suggested requests without changing anything. Engineers then review and apply the suggestions on a schedule.

A worked example

A team runs 40 copies of a checkout service. Each pod requests 2 CPUs, yet measured usage shows a busy-hour average of 0.7 CPUs and a peak of 1.1. The team lowers the request to 1.25 CPUs, which still gives comfortable room above the peak. The total reserved CPU falls from 80 to 50. On nodes with 8 usable CPUs each, that is the difference between ten nodes and about six or seven. The autoscaler does the rest by removing the nodes that are no longer needed, and the saving arrives without a single change to the application code.

i
Tip

Review requests after every big release, not only once a year. Applications grow heavier over time, and last year’s numbers quietly stop being true.

!
Watch Out

Memory requests deserve extra care. CPU can be shared and slowed down, but memory cannot. A pod that exceeds its memory limit is stopped, so never trim memory requests as aggressively as CPU.

18Spot Instances and Interruptions

Cheap machines that the cloud may take back at short notice, and how to use them safely.

Cloud providers sell spare machines at a deep discount, often a large fraction below the regular price. On Amazon these are Spot Instances, and on other clouds they have similar names. The catch is that the provider can reclaim them when it needs the capacity back. On AWS the warning is usually about two minutes. For stateless, replicated workloads this trade is excellent, and the Cluster Autoscaler is a natural partner for it.

Which workloads suit spot machines

  • Good fit: stateless web replicas with several copies, queue workers, batch processing that can retry, build and test jobs, and development environments.
  • Poor fit: a single-replica database, long jobs that cannot save progress, and anything where a two-minute warning is not enough to finish cleanly.

The recommended shape

Most teams build two kinds of node groups: a spot group for flexible work and an on-demand group as the dependable base. The priority expander is then told to try the spot group first and fall back to on-demand when spot capacity is not available. Pods that must be safe carry a node selector or affinity that points only to on-demand nodes.

flowchart TD
  A["Pending pods need nodes"] --> B["Priority expander reads its ranked list"]
  B --> C{"Is the spot group able to grow?"}
  C -->|"Yes"| D["Add spot nodes"]
  C -->|"No or in backoff"| E["Add on-demand nodes"]
  D --> F["Pods run at lower cost"]
  E --> G["Pods run at normal cost"]
  F --> H{"Provider reclaims a spot node?"}
  H -->|"Yes"| I["Node drains and pods return to Pending"]
  I --> A
    
Figure 7: Spot first, on-demand as a safety net, and a loop that repairs itself after interruptions.

Making spot capacity dependable

Spot reliability depends mostly on variety. If a group uses only one machine type, a shortage of that type hurts you completely. If it can use many types of similar size, the provider usually finds some capacity somewhere. On AWS, a mixed instances policy with several equal-sized types and a capacity-aware allocation strategy lowers the chance of interruption. Remember the earlier rule: the types in one group should have matching CPU and memory so the autoscaler’s template stays truthful.

It also helps to run a small helper that listens for the provider’s interruption notice and starts a graceful drain at once, rather than waiting until the machine disappears. On AWS this job is done by the Node Termination Handler, and similar tools exist elsewhere.

Protect the service itself

  • Keep at least two replicas of every service and spread them across nodes and zones, so one interruption cannot take everything down.
  • Use PodDisruptionBudgets so that a burst of reclaimed nodes cannot remove too many replicas at once.
  • Make shutdown fast and tidy, so the pod finishes its work inside the warning window.
  • Keep a floor of on-demand capacity big enough to carry the minimum acceptable traffic.
Everyday Analogy

Think of renting a car versus borrowing a neighbour’s spare. The neighbour’s car is almost free, but they may ask for it back at short notice. You would happily use it for grocery runs, yet you would not use it to drive to an important job interview. Keep a rented car on standby for the trips that cannot fail.

i
Good to Know

Large engineering teams commonly report that their cheapest and most flexible capacity comes from interruptible machines, as long as the software is built to expect them. The design effort is in the application, not in the autoscaler.

19Zones, Topology and Storage

Spreading across data centres makes a service sturdier, and also makes autoscaling a little more interesting.

A cloud region is split into several availability zones, which are separate buildings or groups of buildings with their own power and networking. Running copies of your application in more than one zone means a failure in one building does not stop the service. Kubernetes lets you ask for this with topology spread constraints. They say things such as “keep the number of replicas in each zone roughly equal”.

How spreading affects scale-up

Imagine a service that must keep an even number of pods in each of three zones, and the zone called A has no room left. Adding capacity in zone B does not satisfy the rule. The pod still waits, because the autoscaler must create a node in the right zone. This is why one node group per zone is so popular. The autoscaler can see exactly which group serves which zone and can grow the correct one.

When you do run one group per zone, turn on balancing between similar groups. The autoscaler then treats groups with matching machine shapes and labels as a family and grows them evenly, instead of filling one zone while the others stay small. A few labels naturally differ between zones, such as the zone name itself, so there is a setting that tells the autoscaler which labels to ignore when it decides that two groups are similar.

Rule

Spread Constraint

Keeps replicas evenly divided across zones or nodes. A strict version refuses to schedule when the spread would break, which can create Pending pods.

Rule

Anti-Affinity

Tells Kubernetes not to place two copies of the same app on one node. Useful, but each copy then needs its own node.

Rule

Node Affinity

Restricts pods to nodes with certain labels, such as a machine family or a zone.

Rule

Taints and Tolerations

Reserve special nodes for special pods, such as GPU machines for machine learning.

Storage is tied to a zone

Block disks on most clouds live inside one zone. A pod that uses such a disk can only run in that zone. If the pod is evicted and no node has room in that zone, it will stay Pending even though other zones have plenty of space. The autoscaler must add a node in the right zone, and this works well only when you have separate groups per zone.

A second helpful setting is the volume binding mode called wait for first consumer. With it, Kubernetes delays creating the disk until the pod has been placed, and then creates the disk in the same zone as the chosen node. This avoids the awkward situation where a disk is created in a zone first and the pod cannot find a node there.

Everyday Analogy

Suppose a school wants equal numbers of children in each of three classrooms. When the first classroom is full, it is no help to add chairs in the second. The school needs a new chair in the first. Likewise, a child who keeps books in a locker in classroom one must sit in classroom one. Where something is stored decides where it can sit.

Strict rules have a cost

The more rules you add, the fewer places a pod can go, and the harder it is for the autoscaler to find a node that helps. Treat strict anti-affinity and strict spread rules as precious tools. For many services, a softer preference expresses the same wish without risking a stuck pod. A common compromise is to make zone spreading strict for the services that truly need it, and preferred for everything else.

!
Watch Out

If a zone loses a lot of capacity, strict spread rules can leave pods Pending in the healthy zones as well, because they would break the balance. Plan for this by allowing a reasonable skew, not a perfect one.

20Upgrades and Day-Two Operations

Launching autoscaling is the easy day. Keeping it healthy for years is the real work.

Engineers sometimes call the first deployment day one, and everything after it day two. Day two is where small habits decide whether the system is boring and reliable or a constant source of surprises.

Upgrading Kubernetes with the autoscaler in place

A cluster upgrade usually follows a clear order. The control plane moves first, then the worker nodes, then the add-ons. The Cluster Autoscaler is an add-on that must be moved to the matching version, because it embeds the scheduler’s logic for that Kubernetes release. A mismatch can cause strange mistakes in its simulations, such as believing a pod fits when the real scheduler disagrees.

  • Read the release notes of both Kubernetes and the autoscaler for removed or changed settings.
  • Test the new combination in a staging cluster that has similar node groups and similar workloads.
  • Upgrade one minor version at a time, never skipping.
  • Pause or watch scale-down during the rollout, so nodes are not removed while the cluster is mid-change.

Rotating node images

Nodes should be replaced regularly with fresh, patched machine images. When a node group gets a new image, old nodes are drained and replaced. During this process the autoscaler sees pods being evicted and Pending for a short time, and it may add temporary nodes. This is normal. Good disruption budgets and enough spare capacity make the rotation smooth. Some teams set a maximum node lifetime so that no machine lives forever and surprises never pile up.

A simple runbook

1

Before a big event

Check quotas, raise group maximums if needed, add headroom pods, and confirm alerts are on. Do this days in advance, not minutes.

2

During the event

Watch Pending pod counts, node counts and failed scale-ups. Know who can raise limits quickly.

3

After the event

Remove extra headroom, restore normal limits, and let scale-down trim nodes. Check that the bill falls as expected.

4

Every month

Review idle capacity, blocked scale-downs, and requests against real usage. Small trims add up.

5

Every quarter

Rehearse a failure: a zone loss, a quota hit, a stuck node group. Practice makes the real thing dull.

Changing settings safely

Treat the autoscaler’s configuration like application code. Keep it in version control, review changes, roll them out in staging first, and record why each value was chosen. When behaviour changes after an edit, you will be glad to know exactly what was edited and when. Tune one thing at a time and give each change a few days of normal traffic before judging it.

Startup delays and node readiness

A node is not useful the moment it appears. It needs to start the kubelet, join the cluster, run its networking and storage helpers, and often wait for system add-ons. Some teams apply a startup taint that keeps application pods away until every helper reports ready. The autoscaler has an option to ignore such known startup taints when it builds its template node, so it does not wrongly decide that the new node can never accept pods. Without this, you can see the autoscaler add more nodes than needed because it keeps thinking the earlier ones are unusable.

Everyday Analogy

A new restaurant waiter on the first minute of the shift is not yet ready. They still need an apron, a notepad and the menu. A good manager does not send customers to them until they are ready, and also does not assume the waiter is missing just because they are not serving yet.

21Cost Thinking and Capacity Planning

Autoscaling saves money only if the pieces around it are chosen with cost in mind.

The Cluster Autoscaler keeps your node count close to what your pods need. It does not, by itself, decide whether those pods are efficient or whether the machines are the best value. Cost comes from several layers, and each layer has its own lever.

The layers of cost

LayerTypical leverWho owns it
Application efficiencyFaster code, less memory, right-sized requestsApplication teams
Pod countHPA targets and minimum replicasApplication and platform teams
Node countCluster Autoscaler settings and blockersPlatform team
Machine choiceInstance family, size, spot versus on-demandPlatform team
CommitmentDiscount plans for a steady baselineFinance and platform teams

Large nodes or small nodes?

This is one of the most debated design choices. Both extremes have a price.

Bigger nodes

  • System add-ons on each node take a smaller share.
  • Large pods fit more easily.
  • Fewer machines to patch and watch.
  • Less wasted space from fragmentation of leftover capacity, in some mixes.

Smaller nodes

  • Finer steps when scaling up and down, so less over-buying.
  • A single failure affects fewer pods.
  • Easier to drain, because fewer pods sit on each one.
  • More overhead from per-node helper pods and more IP addresses used.

Many teams settle on a middle size and keep one or two special groups for unusually large or small needs. A useful guide is to pick a node size that can hold at least several of your biggest typical pods, so that rounding errors do not leave much space unusable.

Fragmentation, the hidden waste

Imagine nodes with 8 CPUs where most pods ask for 3 CPUs. Two pods fit per node and use 6 CPUs, leaving 2 CPUs that nothing can use. A quarter of every node is wasted, and the autoscaler cannot fix it, because it simply obeys the requests. Changing the request to 2.5 CPUs would allow three pods per node and use 7.5 CPUs. Small changes in pod size can alter the packing a lot, so it pays to look at the shape of your pods against the shape of your nodes.

Stable base, flexible top

Cloud providers offer discounts for committing to a steady amount of usage over a year or longer. The autoscaler makes this planning easier. Look at the lowest level your cluster reaches in a normal week. That floor is a good amount to cover with commitments. Everything above it moves up and down with traffic, and is best served by on-demand or spot capacity that you pay for only while it exists.

Pod density limits

Kubernetes allows a default of about one hundred and ten pods per node, and some clouds set a lower limit based on how many network addresses a machine can carry. A node may be nearly empty in CPU terms yet full by pod count. When pods are small and many, check this limit, since the autoscaler will add nodes for pod count too, and the machine size you picked may be wasteful in that case.

i
Tip

Track one simple number over time: total requested CPU divided by total allocatable CPU across the cluster. If it hovers near fifty to seventy percent in a busy period, you have healthy headroom. If it is near ninety, spikes will wait for new nodes. If it is near twenty, you are likely paying for air.

22Large Clusters and Tricky Edge Cases

What changes when clusters grow big, and the quirks that surprise even experienced engineers.

Scale and speed

Kubernetes itself is designed for clusters of up to a few thousand nodes. In big clusters the autoscaler’s main loop has more to examine each time, and the simulation work grows with the number of pods and node groups. Its function-duration metric shows if loops are taking too long. A loop that takes longer than the scan interval means decisions arrive late. Remedies include fewer and larger node groups, avoiding needlessly complex scheduling rules, and giving the autoscaler enough CPU and memory of its own. Many organisations also prefer several medium clusters over one huge one, which limits the blast radius of any problem.

Parallel work

Removing empty nodes can happen in bulk, up to a configurable number at once, which keeps large clean-ups from being slow. Removing nodes that still hold pods is more careful and usually proceeds more gently. Recent releases have also improved how quickly the autoscaler can handle many node groups growing at the same time. Check the release notes of the version you run, since this area improves steadily.

Edge cases worth knowing

Edge Case

Pods That Fit Nowhere

A pod larger than any template node never triggers a useful scale-up. Fix the request or add a larger group.

Edge Case

Preemption

High-priority pods can push out lower ones. The pushed-out pods then wait, and may cause scale-up in turn.

Edge Case

Daemon Pods

Helper pods on every node reduce usable space. If they grow, every template node shrinks and fewer pods fit.

Edge Case

Unready Nodes

Nodes stuck in a not-ready state count against the autoscaler’s health checks and are cleaned up only after a waiting period.

Edge Case

Ghost Capacity

Machines that exist in the cloud but never joined the cluster are tracked and removed after a timeout, to avoid paying for them.

Edge Case

Expendable Pods

Pods below the priority cutoff never cause scale-up. This is perfect for placeholders and a trap for anything important.

When things look healthy but are not

One of the trickiest situations is when the autoscaler reports no problem while users complain. This can happen when pods are scheduled fine but are starved of real resources because their requests are too low, or when a service reaches a limit that autoscaling does not see, such as a database connection limit, a network quota or a rate limit on a third-party service. The autoscaler solves the compute problem only. Always trace a slow user request along its full path before blaming capacity.

The human side

Autoscaling is not a replacement for load testing or capacity thinking. It is a safety net and a cost saver. The best-run teams combine it with regular tests, clear ownership of settings, and short written notes explaining the reasons behind each unusual value in their configuration. When a person new to the team reads those notes a year later, the system still makes sense.

Everyday Analogy

An automatic door opens for people who walk toward it, but it cannot tell you whether the corridor behind it is wide enough for the whole crowd. Autoscaling opens the door of capacity. You still need to plan the corridor.

ANTI-PATTERN 06Avoid
The habit

Treating autoscaling as a reason to skip load testing and capacity planning.

Why it hurts

Hidden limits such as quotas, address space, databases and downstream services are discovered during a real incident rather than a rehearsal.

Better approach

Run regular load tests that follow the whole path, from the first request to the last dependency, and fix the first bottleneck you find before the next one appears.

23Frequently Asked Questions

Q1Does the Cluster Autoscaler use CPU usage to decide?
No. It uses pod requests and unschedulable pods. Live usage only matters indirectly, for example when the HPA reads it and creates more pods.
Q2How fast does it add a node?
The decision takes seconds, but the machine must boot, join the cluster and pull images. Expect a few minutes in total, depending on your cloud and image size.
Q3Why will it not remove a node that is almost empty?
A blocking pod is the usual reason: a bare pod, local storage, a strict disruption budget, a do-not-evict annotation, or a pod with nowhere else to go. The group may also be at its minimum, or a recent scale-up may still be in its waiting period.
Q4Can I use it together with the HPA?
Yes, and that is the standard setup. The HPA changes the pod count, and the Cluster Autoscaler supplies the nodes those pods need.
Q5Can it scale a group down to zero nodes?
Yes, for groups where the minimum is zero and the autoscaler knows what a node would look like. On some clouds you add tags describing labels and taints so it can plan from zero.
Q6What happens to my pods when a node is removed?
They are evicted politely, honouring disruption budgets and grace periods, and their controllers recreate them on other nodes. Pods that are not controlled by anything are protected from this and block the removal.
Q7Do I need it if I use a managed service?
You still need node autoscaling in some form. Some services provide it for you, such as GKE, while others let you choose between the open-source autoscaler and newer alternatives.
Q8How is it different from Karpenter?
The Cluster Autoscaler resizes pre-defined node groups. Karpenter launches machines directly in shapes that fit the waiting pods and can consolidate nodes. Both solve the same problem with different trade-offs.
Q9Is it safe to run only one replica?
It works, but if that pod fails, scaling stops until it restarts. Running two replicas with leader election improves resilience, since only one acts at a time.
Q10How do I stop certain pods from ever being moved?
Annotate the pod so it is not safe to evict. Use this sparingly, because every protected pod can keep an entire node alive.
Q11Why did the autoscaler create a node that did not help?
Usually the real node differed from the template it assumed, for example a different instance size, missing labels or an extra taint. Keep templates and real nodes consistent.

24Summary and Key Takeaways

If you remember only a handful of things, remember these.

Key Takeaways

  • It adds and removes nodes, nothing else. The HPA scales pods, the VPA resizes pods, and the Cluster Autoscaler scales the servers underneath.
  • Pending pods drive scale-up. It reacts to pods the scheduler could not place, not to CPU graphs.
  • Requests are everything. Honest, right-sized CPU and memory requests make good decisions possible.
  • Scale-down is careful by design. Underused nodes wait about ten minutes, and blockers such as bare pods or strict budgets keep nodes alive.
  • New nodes take minutes. Use headroom pods when your users cannot wait.
  • Guard the rails. Set minimums, maximums and quotas, give it minimal permissions, and never fight it with manual changes.
  • Watch events, status and metrics. They explain nearly every strange behaviour.