Kubernetes Cluster Autoscaler Setup Guide
Configure the Cluster Autoscaler to automatically add and remove nodes based on pod scheduling demands. Covers AWS, GKE, Azure, and bare-metal setups.
π‘ Quick Answer: Configure the Cluster Autoscaler to automatically add and remove nodes based on pod scheduling demands. Covers AWS, GKE, Azure, and bare-metal setups.
The Problem
Your cluster runs out of capacity when demand spikes β pods stay Pending because no node has room for them β and manual node scaling is too slow to react. You also donβt want nodes sitting idle burning cost once demand drops.
The Solution
Install Cluster Autoscaler (AWS EKS)
helm repo add autoscaler https://kubernetes.github.io/autoscaler
helm install cluster-autoscaler autoscaler/cluster-autoscaler \
--namespace kube-system \
--set autoDiscovery.clusterName=my-cluster \
--set awsRegion=eu-west-1 \
--set extraArgs.balance-similar-node-groups=true \
--set extraArgs.skip-nodes-with-system-pods=false \
--set extraArgs.scale-down-delay-after-add=10m \
--set extraArgs.scale-down-unneeded-time=10mHow It Works
# Scale UP: Pod stuck in Pending β CA adds a node
kubectl get pods | grep Pending
# Scale DOWN: Node underutilized for 10min β CA drains & removes
# Node is "unneeded" if all pods can be rescheduled elsewhere
# Check CA status
kubectl -n kube-system logs -l app.kubernetes.io/name=cluster-autoscaler --tail=50
kubectl get configmap cluster-autoscaler-status -n kube-system -o yamlNode Group Configuration
# AWS: Auto-discovery via ASG tags
# Tag your ASG with:
# k8s.io/cluster-autoscaler/enabled: true
# k8s.io/cluster-autoscaler/my-cluster: owned
# GKE: Enable via gcloud
# gcloud container clusters update my-cluster --enable-autoscaling \
# --min-nodes=1 --max-nodes=10
# Priority-based expander (prefer cheaper instances)
apiVersion: v1
kind: ConfigMap
metadata:
name: cluster-autoscaler-priority-expander
namespace: kube-system
data:
priorities: |
10:
- spot-nodes.*
50:
- on-demand-nodes.*graph TD
A[Pod Pending - unschedulable] --> B[Cluster Autoscaler detects]
B --> C[Find suitable node group]
C --> D[Add node to cluster]
D --> E[Pod scheduled on new node]
F[Node underutilized 10min] --> G[CA marks unneeded]
G --> H[Drain pods to other nodes]
H --> I[Remove node]Expander Strategies
The expander controls which node group Cluster Autoscaler picks when several could satisfy a pending pod:
| Expander | Strategy |
|---|---|
random | Random selection |
most-pods | Add the node that fits the most pending pods |
least-waste | Add the node with least idle CPU/memory after scaling |
price | Add the cheapest node (cloud-provider specific) |
priority | Use a priority-based ConfigMap (shown above) |
- --expander=least-wasteScale-Down Configuration
- --scale-down-enabled=true
- --scale-down-delay-after-add=10m # wait this long after adding a node before considering scale-down
- --scale-down-delay-after-delete=0s # wait this long after deleting a node
- --scale-down-unneeded-time=10m # a node must be unneeded for this long before removal
- --scale-down-utilization-threshold=0.5 # scale down if utilization is below 50%Setting these delays too low causes thrashing β nodes get added and removed repeatedly as load fluctuates near the threshold.
Preventing Scale-Down
Protect a node running a workload that shouldnβt be evicted:
# Pod-level: this pod blocks its node from being scaled down
apiVersion: v1
kind: Pod
metadata:
name: important-pod
annotations:
cluster-autoscaler.kubernetes.io/safe-to-evict: "false"# Node-level: mark a specific node as non-scalable
kubectl annotate node my-node cluster-autoscaler.kubernetes.io/scale-down-disabled=trueAlso protect availability during scale-down with a PodDisruptionBudget:
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: myapp-pdb
spec:
minAvailable: 2
selector:
matchLabels:
app: myappMonitoring
kubectl get configmap cluster-autoscaler-status -n kube-system -o yaml
kubectl logs -n kube-system -l app.kubernetes.io/name=cluster-autoscaler -f# Pods stuck Pending
sum(kube_pod_status_phase{phase="Pending"})
# Cluster-wide node count
count(kube_node_info)
# Scaling activity
cluster_autoscaler_scaled_up_nodes_total
cluster_autoscaler_scaled_down_nodes_totalFrequently Asked Questions
Cluster Autoscaler vs Karpenter?
CA scales existing node groups (ASGs). Karpenter (AWS-only) provisions optimal instances directly β faster, more flexible, bin-packs better. Use Karpenter on EKS if possible.
Why isnβt my node scaling down?
Common blockers: pods with local storage (emptyDir), PDBs preventing drain, pods without controllers, system pods. Check CA logs for βcannot remove nodeβ reasons.
Best Practices
- Set a sane min/max per node group (e.g.
2:20) β a minimum of 2 helps HA; a hard max caps runaway cost - Use Pod Priority classes for critical workloads so preemption and scheduling favor them under pressure
- Donβt set scale-down delays too low β it causes node thrashing
- Use PodDisruptionBudgets to keep workloads available while nodes drain during scale-down
- Watch cloud cost dashboards, not just cluster metrics β scaling decisions have a direct cost impact
Key Takeaways
- Cluster Autoscaler adds nodes when pods are Pending and removes nodes that are underutilized for a sustained period
- It complements HPA: HPA scales pod replicas, Cluster Autoscaler scales nodes to fit them
safe-to-evict: "false"and PodDisruptionBudgets are the two levers to stop a node being scaled down- Karpenter is the modern alternative on AWS β it provisions right-sized instances directly instead of scaling fixed node groups
- Tune
scale-down-delay-after-addandscale-down-unneeded-timeto avoid thrashing under fluctuating load

Recommended
Kubernetes Recipes β The Complete Book100+ production-ready patterns with detailed explanations, best practices, and copy-paste YAML. Everything in one place.
Get the Book βLearn by Doing
CopyPasteLearn β Hands-on Cloud & DevOps CoursesMaster Kubernetes, Ansible, Terraform, and MLOps with interactive, copy-paste-run lessons. Start free.
Browse Courses βπ Deepen Your Skills β Hands-on Courses
Courses by CopyPasteLearn.com β Learn IT by Doing
