Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Cluster Autoscaler Explained

By Kokil Thapa | Last reviewed: September 2026

Cluster Autoscaler Explained starts with a simple idea: your Kubernetes cluster should grow when pods cannot be scheduled and shrink when nodes sit idle. That sounds obvious until you watch a staging cluster burn money on three empty nodes while production queues pending pods behind a single tainted pool. The Kubernetes autoscaling stack splits work across three layers—HPA scales pod replicas, VPA adjusts container requests, and Cluster Autoscaler changes the node count itself. This guide walks through how that node layer actually behaves in 2026, what cloud settings must align, and the production mistakes I keep seeing on real deployments.

How does Kubernetes Cluster Autoscaler work?

Cluster Autoscaler (CA) runs as a controller inside your cluster. It reads pod scheduling state and node utilisation signals, then talks to your cloud API. It does not pick container CPU limits or replica counts. Those jobs belong to HPA and VPA.

The loop is predictable once you map it. Every scan cycle, CA asks the scheduler a question: are any pods pending because no node fits? If yes, and the pod belongs to a node group CA manages, it requests another instance from that group. If nodes stay underused for long enough, CA may cordon, drain, and terminate them—subject to your min and max group sizes.

Cluster Autoscaler Control LoopPending PodsUnschedulableCA ControllerEvery ~10s scanCloud APIASG / MIG / VMSSScale UpAdd node to groupScale DownDrain idle nodesSchedulerPlaces podsCA never creates Deployments — only node capacityNode groups need min/max bounds and correct labels
Cluster Autoscaler Explained: the controller reacts to scheduling pressure, not CPU graphs alone.

The scale-up decision

CA scale-up triggers when a pod stays unschedulable and simulating a new node would fix placement. The scheduler must report that adding a machine from a managed group would schedule the pod. CA will not scale for pods that fail for other reasons—image pull errors, affinity rules no node can satisfy, or resource requests larger than any instance type in the group.

Scale-up is not instant. Cloud APIs create VMs, kubelet registers the node, and CNI attaches networking. On AWS EKS that often means two to four minutes. On GKE with pre-warmed node pools it can be faster. Plan HPA and pod disruption budgets around that delay, not around sub-minute fantasy.

The scale-down decision

Scale-down is conservative by design. A node must pass several checks: utilisation below threshold, no pods that block eviction, no local storage conflicts, and no pods ignored by CA annotations. CA cordons the node, evicts workloads, then asks the cloud to terminate the instance.

The default utilisation threshold is around 50% of allocatable CPU and memory after accounting for requests—not raw usage. That surprises teams who monitor Grafana CPU graphs at 20% and wonder why nodes stay up. Requests drive scheduling math; metrics alone do not.

What is the difference between Cluster Autoscaler, HPA, and VPA?

These three tools complement each other. They also get confused because all three appear under “autoscaling” in cloud consoles. Treat them as a pipeline: HPA changes replica count, VPA changes container size, CA changes machine count.

AutoscalerScalesTriggerTypical owner
HPAPod replicasCPU, memory, or custom metricsApp / platform team
VPAContainer requests/limitsHistorical or realtime usagePlatform / SRE
Cluster AutoscalerNodes in a node groupPending pods or idle capacityPlatform / cloud admin

A common healthy stack on a managed Kubernetes cluster looks like this: HPA on stateless API deployments, CA on a general-purpose node group, VPA in recommendation mode until you trust its numbers. Running VPA in auto mode on the same containers HPA controls still requires care—conflicts are documented in the upstream project.

Three Autoscaling LayersHPAMore pod replicasDeployment / StatefulSetVPABigger containersCPU / memory requestsCluster AutoscalerMore nodesNode group ASGKubernetes Cluster — Nodes and PodsScheduler places pods on available capacityTraffic spike: HPA adds pods → pending → CA adds nodes
HPA, VPA, and Cluster Autoscaler operate at different layers—together they cover replicas, sizing, and infrastructure.

On workloads I have run for enterprise Laravel APIs containerised behind queues, HPA on queue depth or request latency beats CPU-only targets. CA then follows when new pods cannot land. Without CA, HPA hits max replicas and requests still fail—exactly the failure mode that looks like an application bug in logs.

When should you enable Cluster Autoscaler on a production cluster?

Enable CA when pod demand is variable and you pay per node. Batch jobs, eCommerce traffic swings, and CI-heavy dev clusters are strong fits. Skip CA—or keep groups narrow—when workloads are flat, when you rely on fixed bare-metal sizing, or when scale-up latency exceeds your SLO anyway.

  • Variable traffic: Web frontends, API tiers, worker pools fed by message queues.
  • Multi-tenant platforms: Namespaces that grow at different times share one elastic node pool.
  • Cost control with bounds: Min size keeps baseline capacity; max size caps worst-case cloud bills.
  • Spot or preemptible groups: CA replaces interrupted nodes when pods reschedule—pair with PodDisruptionBudgets.

Do not enable CA as a substitute for right-sizing requests. If every pod requests 4 CPU “to be safe,” CA will scale out expensive nodes while real utilisation stays low. Fix requests first; autoscaling second. That order saves more money than any cloud discount.

Signals CA ignores (and should)

CA will not help pods stuck in CrashLoopBackOff, pods with node selectors pointing at a full tainted pool, or DaemonSets that already consume the node. System pods and pods with the cluster-autoscaler.kubernetes.io/safe-to-evict: "false" annotation block scale-down on their node. That is intentional—it prevents CA from evicting your payment webhook mid-transaction because a metric looked quiet.

How do you configure Cluster Autoscaler on AWS EKS, GKE, or AKS?

Every cloud wraps the same upstream binary with different node-group primitives. You must tell CA which groups it may touch, usually through auto-discovery flags or explicit ASG, MIG, or VMSS names. IAM permissions must allow Describe and SetDesiredCapacity (or cloud equivalents). Missing permissions produce log lines about failed scale-ups and angry on-call pages.

AWS EKS with managed node groups

On EKS, tag your Auto Scaling groups so CA discovers them:

k8s.io/cluster-autoscaler/enabled: true
k8s.io/cluster-autoscaler/<cluster-name>: owned

Deploy CA with Helm or the official manifest. A minimal values fragment for the autoscaler chart:

autoDiscovery:
  clusterName: my-production-cluster
awsRegion: ap-south-1
rbac:
  create: true
extraArgs:
  balance-similar-node-groups: true
  skip-nodes-with-local-storage: false
  scale-down-unneeded-time: 10m
  scale-down-delay-after-add: 10m

The scale-down-unneeded-time flag controls how long a node must look removable before termination. Ten minutes is a reasonable production starting point. Shorter windows save money but increase churn during oscillating traffic.

GKE node auto-provisioning vs CA

GKE can run Cluster Autoscaler on existing node pools or use node auto-provisioning to create new pool shapes dynamically. Standard node pool autoscaling maps cleanly to the mental model in this article. Node auto-provisioning adds flexibility at the cost of harder cost forecasting—document allowed machine families in policy.

AKS cluster autoscaler

AKS exposes autoscaling on node pools through the Azure API or Terraform. Enable the cluster autoscaler profile on the pool, set min and max counts, and ensure the Kubernetes version matches AKS support tables. The multi-cluster teams I advise standardise one CA flag set per environment so staging behaviour matches production logic at smaller bounds.

Node Group BoundariesCloud Auto Scaling Group — min 2, max 20, instance type m6i.largeNode 1BaselineNode 2BaselineNode 3+CA addedEmpty slotUp to maxRequired labels & taintsMatch pod nodeSelectorPod requests fitOr CA will not scaleSeparate groups for GPU, spot, and general workloads
Cluster Autoscaler respects min/max node group limits and scheduling labels—misconfigured pools stay frozen.
  1. Create a node group with min, max, and desired count aligned to baseline traffic.
  2. Apply discovery tags or pass explicit group names to the CA deployment.
  3. Grant cloud IAM rights for autoscaling APIs—verify with a controlled pending pod test.
  4. Set scale-down-delay-after-add to avoid flapping after scale-up events.
  5. Export CA metrics and events to your observability stack alongside HPA metrics.
  6. Document max node count as a cost ceiling—roughly Rs 15,000–25,000 per large node-month (~USD 110–185) adds up fast at max=50.

For YAML sanity checks during rollout, a quick pass through a JSON or YAML formatter catches indentation errors that silently drop autodiscovery blocks. Small tooling habits prevent big outages.

Official reference material lives in the Kubernetes Cluster Autoscaler repository and the Kubernetes autoscaling documentation. Cloud-specific notes for EKS appear in AWS EKS cluster autoscaling guidance.

What are common Cluster Autoscaler mistakes that waste money or break apps?

Most CA incidents I troubleshoot are configuration gaps, not autoscaler bugs. The controller does exactly what flags and scheduling state allow—often too much or too little.

Over-provisioned resource requests

Teams set requests to peak usage for every pod. CA sees full nodes while Grafana shows 15% CPU. Fix requests with VPA recommendations or manual profiling, then re-enable aggressive scale-down. This single change beats buying reserved instances for the wrong shape.

Single oversized node group

Mixing GPU jobs, spot-friendly batch work, and latency-sensitive APIs in one group forces CA to add expensive nodes for cheap work. Split groups by workload class. Use taints and tolerations so CA scales the right pool. Multi-cluster management patterns apply the same idea across environments.

Missing PodDisruptionBudgets during scale-down

CA respects PDBs when evicting pods. Without PDBs, scale-down can still disrupt apps if readiness probes lie or terminationGracePeriodSeconds is zero. With overly strict PDBs, nodes never drain and costs stick. Balance minAvailable against replica count.

Ignoring cluster autoscaler expander strategy

The expander flag chooses among multiple eligible node groups. least-waste is the common default—it picks the group that leaves the smallest idle fragment after placement. priority uses a ConfigMap ordering when you want spot tried before on-demand. Wrong expander choice sends traffic-shaped workloads to the wrong instance family.

Why Is CA Not Scaling?Pods pending?YesNoCheck requests vsinstance sizeNodes idle but noscale-down?Fix affinity / taintsOr raise max nodesPDB or safe-to-evictblocks evictionRead CA logs: FailedScaleUp and Unneeded events
Cluster Autoscaler troubleshooting: pending pods and stuck nodes usually trace back to scheduling rules, not the controller binary.

Observability ties back to platform hygiene. Export CA metrics to Prometheus—cluster_autoscaler_scaled_up_nodes_total and scale-down failures tell you more than guessing from the AWS console. Teams practising AIOps on infrastructure metrics often alert on repeated FailedScaleUp bursts before user-facing latency spikes.

Security matters too. CA needs broad cloud autoscaling permissions. Run it in a locked-down namespace, rotate cloud credentials via workload identity, and audit RBAC—similar discipline as Kubernetes RBAC hardening. On Linux-hosted clusters you maintain yourself, the same CA binary applies whether kube-apiserver runs on cloud VMs or on-prem hypervisors—the cloud integration layer changes, not the scheduling loop.

If you are new to the control plane pieces CA depends on, read how etcd stores cluster state and how your first Deployment gets scheduled. That context makes CA logs readable instead of mystical.

Production platforms I have helped ship—booking systems like Adventure Third Pole Trek and high-traffic eCommerce backends—eventually need elastic capacity when traffic outgrows fixed VPS sizing. CA is not mandatory on a two-node k3s lab, but it becomes essential when HPA-outgrown pods meet cloud billing every hour.

Key Takeaways

  • Cluster Autoscaler adds and removes nodes in configured groups—it never creates pod replicas by itself.
  • Scale-up follows unschedulable pods; scale-down follows request-based utilisation thresholds and eviction safety rules.
  • Pair CA with HPA for traffic spikes; use VPA to fix request sizing before chasing cheaper nodes.
  • Tag node groups correctly, set min/max bounds, and tune scale-down delays to prevent flapping and bill shock.
  • Split node pools by workload type, wire PDBs thoughtfully, and alert on FailedScaleUp events in metrics.
  • When Cluster Autoscaler Explained still leaves gaps in your stack, treat CA as one layer in a documented autoscaling runbook—not a silent cost optimizer.

People Also Ask

Does Cluster Autoscaler work with Kubernetes Horizontal Pod Autoscaler?

Yes—and they are designed to work together. HPA increases replica count when metrics cross thresholds. If the scheduler cannot place new pods, Cluster Autoscaler adds nodes. Without CA, HPA hits maxReplicas and users see errors even though autoscaling is “enabled.”

How long does Cluster Autoscaler take to add a node?

Typically two to five minutes on standard cloud node groups: API call, VM boot, kubelet registration, and CNI readiness. Pre-warmed pools and smaller instance types reduce that time. Do not size HPA reaction windows assuming instant nodes.

Can Cluster Autoscaler scale to zero nodes?

Only if you set a node group minimum of zero and your cloud provider integration supports it—common on GKE autopilot-style setups, less common on conservative EKS production pools. Most production clusters keep min ≥ 2 for control-plane adjacency and fast scale-up headroom.

What happens to pods when Cluster Autoscaler removes a node?

CA cordons the node, respects PodDisruptionBudgets, evicts workloads gracefully, then terminates the instance. Pods managed by Deployments reschedule elsewhere. StatefulSets with local storage or strict identity needs require extra planning—CA may refuse to remove those nodes.

Build elastic platforms with the right autoscaling layer

Cluster Autoscaler Explained boils down to supply meeting demand at the machine layer. Fix pod requests, wire HPA to meaningful metrics, bound your node groups, and CA will save you from midnight manual scaling—without surprise cloud invoices. If you are moving Laravel, API, or eCommerce workloads from fixed servers to Kubernetes and want the platform configured correctly from day one, review our support and maintenance and API development services—or contact us to audit an existing cluster autoscaling setup. For background on the full autoscaling picture, continue with the HPA, VPA, and Cluster Autoscaler overview and the about page for how production infrastructure work is delivered.

Frequently Asked Questions

It is a Kubernetes controller that adds or removes nodes in configured node groups when pods cannot be scheduled or nodes sit underused—it never creates pod replicas itself.

Each scan cycle, Cluster Autoscaler asks the scheduler whether any pending pods would fit on a new node from a managed group. Scale-up triggers only for truly unschedulable pods—not image pull failures or unsatisfiable affinity. Scale-down is conservative: a node must stay below roughly fifty percent of allocatable CPU and memory based on pod requests, pass eviction checks, and remain removable for the configured delay window before CA cordons, drains, and terminates it.

They operate at different layers. Horizontal Pod Autoscaler changes replica count based on CPU, memory, or custom metrics. Vertical Pod Autoscaler adjusts container requests and limits. Cluster Autoscaler changes machine count in node groups. A sensible production stack pairs HPA on stateless APIs, CA on a general-purpose node group, and VPA in recommendation mode until you trust its sizing. Without CA, HPA can hit maxReplicas while pods still fail to schedule.

Enable it when pod demand varies and you pay per node—batch jobs, eCommerce traffic swings, and CI-heavy dev clusters are strong fits. Set min and max bounds so baseline capacity stays available while worst-case bills stay capped. Skip CA or keep groups narrow for flat workloads, fixed bare-metal sizing, or when two-to-five-minute scale-up latency exceeds your SLO. Fix over-provisioned pod requests before relying on autoscaling; right-sizing saves more than discounts.

Typically two to five minutes on standard cloud node groups—VM creation, kubelet registration, and CNI readiness. Pre-warmed GKE pools can be faster.

Yes, and they are designed to work together. HPA increases replica count when metrics cross thresholds. If the scheduler cannot place new pods, Cluster Autoscaler adds nodes. Without CA, HPA reaches maxReplicas and requests still fail—a failure mode that often looks like an application bug in logs. On containerised Laravel APIs behind queues, pairing HPA on queue depth or latency with CA covers traffic spikes that CPU-only targets miss.

Only if the node group minimum is zero and your cloud integration supports it—common on GKE autopilot-style setups, uncommon on conservative EKS production pools.

Cluster Autoscaler cordons the node first, respects PodDisruptionBudgets, evicts workloads with normal grace periods, then asks the cloud provider to terminate the instance. Pods from Deployments reschedule elsewhere. StatefulSets with local storage or strict identity requirements need extra planning—CA may refuse scale-down on nodes hosting pods marked safe-to-evict false or pods that block eviction. Missing or overly strict PDBs either disrupt apps or prevent nodes from ever draining.

Tag Auto Scaling groups with k8s.io/cluster-autoscaler/enabled and k8s.io/cluster-autoscaler/your-cluster-name owned, then deploy CA via Helm or the official manifest with autoDiscovery clusterName and awsRegion set. Grant IAM permissions for Describe and SetDesiredCapacity. Useful starting flags include scale-down-unneeded-time of ten minutes and scale-down-delay-after-add of ten minutes to reduce flapping. Verify with a controlled pending pod test before trusting production traffic.

GKE can run Cluster Autoscaler on existing node pools—the model this article describes—or use node auto-provisioning to create new pool shapes dynamically. Standard node pool autoscaling maps cleanly to managed min and max counts per pool. Node auto-provisioning adds flexibility for mixed workloads but makes cost forecasting harder; document allowed machine families in policy so surprise instance types do not inflate monthly bills without review.

Scale-down decisions use pod resource requests against allocatable capacity, not raw CPU graphs. The default threshold is roughly fifty percent of allocatable CPU and memory after requests—not live utilisation. Teams watching Grafana at twenty percent wonder why nodes persist. Over-provisioned requests make nodes appear full to the scheduler while metrics look quiet. Fix sizing with VPA recommendations or profiling, then tune scale-down-unneeded-time for quicker removal.

Over-provisioned resource requests force CA to add nodes while real utilisation stays low. Mixing GPU, batch, and latency-sensitive APIs in one node group scales expensive machines for cheap work—split pools with taints and tolerations instead. Missing PodDisruptionBudgets allow disruptive evictions; overly strict PDBs block scale-down entirely. The wrong expander flag—least-waste versus priority—sends workloads to the wrong instance family. Alert on FailedScaleUp events in Prometheus rather than guessing from the cloud console.

Cluster Autoscaler will not scale for pods stuck in CrashLoopBackOff, pods whose node selectors point at a full tainted pool, or workloads whose resource requests exceed any instance type in the group. It ignores DaemonSets already consuming the node. Pods annotated cluster-autoscaler.kubernetes.io/safe-to-evict false block scale-down on that node—a deliberate safeguard for payment webhooks and similar critical processes. Pending pods from image pull errors or affinity no node can satisfy are scheduling issues, not CA bugs.

Cluster Autoscaler needs cloud IAM rights to describe autoscaling groups and change desired capacity—missing permissions produce failed scale-up log lines and on-call pages. Run the controller in a locked-down namespace, rotate credentials via workload identity rather than long-lived keys, and audit Kubernetes RBAC with the same discipline as general control-plane hardening. CA holds broad infrastructure permissions because it creates and terminates machines; treat that blast radius like any other platform admin component.

Set explicit max node counts on every managed group and treat max as a documented cost ceiling. A large node can run roughly Rs 15,000–25,000 per month (~USD 110–185); at max fifty nodes that arithmetic becomes real quickly. Pair min sizes with baseline traffic needs. Use priority expanders to prefer spot or preemptible groups before on-demand. Export cluster_autoscaler_scaled_up_nodes_total and scale-down failure metrics to Prometheus so repeated FailedScaleUp bursts surface before user-facing latency spikes.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: