Inhoudsopgave
- Wat je hebt aan het einde
- Vereisten
- Hoe Cluster Autoscaler beslist om te schalen
- Configureren op EKS
- Configureren op GKE
- Configureren op AKS
- Een expander-strategie kiezen
- Scale-down timing afstellen
- Diagnose: waarom schaalt een node niet down
- Diagnose: waarom triggert een Pending pod geen scale-up
- Vergelijkbare node groups balanceren over zones
- Observeren en debuggen
- Wanneer Karpenter een betere keuze is
- Wanneer escaleren
Wat je hebt aan het einde
Een werkende Cluster Autoscaler (CA) deployment die automatisch nodes toevoegt wanneer pods niet ingepland kunnen worden, en ondergebruikte nodes verwijdert na een configureerbare cooldown. Je weet hoe je de belangrijkste timing-parameters afstelt, vastgelopen scale-down operaties deblokt, en CA's status-output leest om te begrijpen wat het doet en waarom.
Vereisten
kubectlverbonden met een Kubernetes 1.28+ cluster op EKS, GKE of AKS- Cluster-admin rechten (RBAC) en cloud IAM-permissies om node groups/ASGs/VMSS te beheren
- Kennis van resource requests en limits. CA gebruikt requests, niet daadwerkelijk verbruik, voor elke scheduling-beslissing
- PodDisruptionBudgets geconfigureerd op productie-workloads (CA respecteert PDBs bij scale-down)
Hoe Cluster Autoscaler beslist om te schalen
Scale-up
CA pollt de API server elke scan-interval (standaard 10 seconden). Wanneer het pods vindt in Pending state met reason: Unschedulable, simuleert het het toevoegen van een node uit elke beschikbare node group en kiest er een via de geconfigureerde expander-strategie.
De beslissing is volledig gebaseerd op resource requests. Een pod die 2 CPU en 4Gi geheugen vraagt op een node met 4 CPU allocatable registreert als 50% benut, zelfs als het werkelijke CPU-gebruik op 3% ligt.
Scale-down
Een node wordt een scale-down kandidaat wanneer drie condities tegelijkertijd waar zijn:
- De som van alle pod-requests op de node is lager dan
scale-down-utilization-threshold(standaard 0.5, dus 50%) - Elke pod op de node kan opnieuw ingepland worden op andere bestaande nodes
- De node is al minstens
scale-down-unneeded-time(standaard 10 minuten) in deze staat
Daar bovenop blokkeert scale-down-delay-after-add (standaard 10 minuten) alle scale-down na elke scale-up. Dat is bewuste thrash-preventie. Onder standaardinstellingen is de effectieve minimale tijd van "node wordt onderbenut" tot "node is verwijderd" 10-20 minuten.
Versiematching
De minor-versie van CA moet overeenkomen met de Kubernetes minor-versie. Een cluster op Kubernetes 1.32.x heeft CA 1.32.x nodig. De patch-versie hoeft niet te matchen. Update CA direct na het upgraden van het control plane.
Configureren op EKS
Op EKS deploy je de open-source Cluster Autoscaler zelf. Het heeft IAM-permissies en ASG discovery tags nodig.
Stap 1: maak een IAM policy
CA heeft leestoegang nodig om ASGs en EC2 instances te beschrijven, en schrijftoegang (beperkt tot getagde ASGs) om desired capacity in te stellen en instances te termineren.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"autoscaling:DescribeAutoScalingGroups",
"autoscaling:DescribeAutoScalingInstances",
"autoscaling:DescribeLaunchConfigurations",
"autoscaling:DescribeScalingActivities",
"autoscaling:DescribeTags",
"ec2:DescribeImages",
"ec2:DescribeInstanceTypes",
"ec2:DescribeLaunchTemplateVersions",
"ec2:GetInstanceTypesFromInstanceRequirements",
"eks:DescribeNodegroup"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"autoscaling:SetDesiredCapacity",
"autoscaling:TerminateInstanceInAutoScalingGroup"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"autoscaling:ResourceTag/k8s.io/cluster-autoscaler/enabled": "true",
"autoscaling:ResourceTag/k8s.io/cluster-autoscaler/production-main": "owned"
}
}
}
]
}
Vervang production-main door je clusternaam. Het Condition-blok zorgt ervoor dat CA alleen ASGs kan wijzigen die getagd zijn voor jouw cluster.
Stap 2: koppel IAM aan het CA service account
Optie A: EKS Pod Identity (voorkeur voor nieuwe clusters)
eksctl create podidentityassociation \
--cluster production-main \
--namespace kube-system \
--service-account-name cluster-autoscaler \
--role-arn arn:aws:iam::123456789012:policy/ClusterAutoscalerRole
Optie B: IRSA (oudere clusters)
eksctl create iamserviceaccount \
--cluster=production-main \
--namespace=kube-system \
--name=cluster-autoscaler \
--attach-policy-arn=arn:aws:iam::123456789012:policy/ClusterAutoscalerPolicy \
--approve
Stap 3: tag je ASGs
Elke ASG (of EKS Managed Node Group) die CA moet beheren heeft twee tags nodig:
| Tag key | Value |
|---|---|
k8s.io/cluster-autoscaler/enabled |
true |
k8s.io/cluster-autoscaler/production-main |
owned |
eksctl voegt deze automatisch toe. Terraform en CloudFormation vereisen handmatige toevoeging.
Voor schalen vanaf nul (node group min=0), voeg template-tags toe zodat CA node-eigenschappen kan afleiden zonder een draaiende node:
k8s.io/cluster-autoscaler/node-template/label/kubernetes.io/os = linux
k8s.io/cluster-autoscaler/node-template/label/workload-type = batch
Stap 4: deploy Cluster Autoscaler
Pin de image tag op de Kubernetes minor-versie van je cluster:
# Voor Kubernetes 1.32.x
helm upgrade --install cluster-autoscaler autoscaler/cluster-autoscaler \
--namespace kube-system \
--set autoDiscovery.clusterName=production-main \
--set awsRegion=eu-west-1 \
--set image.tag=v1.32.0 \
--set extraArgs.balance-similar-node-groups=true \
--set extraArgs.skip-nodes-with-local-storage=false \
--set podAnnotations."cluster-autoscaler\.kubernetes\.io/safe-to-evict"='"false"' \
--set priorityClassName=system-cluster-critical
De safe-to-evict: "false" annotatie voorkomt dat CA zijn eigen pod evict. De system-cluster-critical priority class zorgt dat CA niet gepreempt wordt bij nodedruk.
Stap 5: verifieer
kubectl logs -n kube-system -l app.kubernetes.io/name=cluster-autoscaler --tail=20
Verwachte output bevat regels als Cluster Autoscaler version v1.32.0 en periodiek Calculating unneeded nodes. Geen ERROR-regels over IAM of STS.
Mixed instance policies op EKS
Alle instance types in een MixedInstancePolicy ASG moeten dezelfde vCPU-count en RAM hebben. CA gebruikt het eerste instance type in de lijst voor scheduling-simulatie. Grotere types verspillen resources (CA plant minder pods in dan de node aankan). Kleinere types veroorzaken scheduling-fouten (CA belooft meer capaciteit dan de node levert).
Scheid On-Demand en Spot in aparte ASGs. Gebruik geen base capacity + spot overflow strategie binnen een enkele ASG.
Configureren op GKE
GKE's Cluster Autoscaler is een volledig managed component dat draait in het control plane. Je deployt de open-source CA niet zelf.
Inschakelen op een nieuw cluster
gcloud container clusters create production-cluster \
--num-nodes=2 \
--location=europe-west4-a \
--node-locations=europe-west4-a,europe-west4-b \
--enable-autoscaling \
--min-nodes=1 \
--max-nodes=8
Inschakelen op een bestaande node pool
gcloud container clusters update production-cluster \
--enable-autoscaling \
--min-nodes=1 \
--max-nodes=8 \
--node-pool=default-pool
Voor multi-zone node pools op GKE 1.24+ gebruik je --total-min-nodes en --total-max-nodes om de count over alle zones te sturen in plaats van per zone.
Kies een autoscaling profile
GKE biedt twee autoscaling profiles:
| Profile | Gedrag |
|---|---|
balanced (standaard) |
Gematigde scale-down, houdt buffer aan voor inkomende workloads |
optimize-utilization |
Agressieve scale-down voor kostenbesparing, kan schedulinglatentie verhogen |
gcloud container clusters update production-cluster \
--autoscaling-profile=optimize-utilization
GKE-beperkingen
- Kan niet naar nul schalen op een node pool
- Maximale clustergrootte: 15.000 nodes
- Node auto-provisioning (NAP) is een apart feature dat dynamisch nieuwe node pools aanmaakt; het is iets anders dan de autoscaler die bestaande pools beheert
Configureren op AKS
AKS beheert CA intern. Configureer het via az CLI, nooit door VMSS autoscaling-instellingen in de Azure portal te bewerken (dat conflicteert).
Inschakelen op een nieuw cluster
az aks create \
--resource-group production-rg \
--name production-aks \
--node-count 2 \
--vm-set-type VirtualMachineScaleSets \
--load-balancer-sku standard \
--enable-cluster-autoscaler \
--min-count 1 \
--max-count 8 \
--generate-ssh-keys
Autoscaler updaten op een bestaande node pool
az aks nodepool update \
--resource-group production-rg \
--cluster-name production-aks \
--name nodepool1 \
--update-cluster-autoscaler \
--min-count 1 \
--max-count 10
Het autoscaler profile configureren
AKS biedt een cluster-breed autoscaler profile dat voor alle node pools geldt:
az aks update \
--resource-group production-rg \
--name production-aks \
--cluster-autoscaler-profile \
scan-interval=30s \
scale-down-delay-after-add=5m \
scale-down-unneeded-time=5m \
scale-down-utilization-threshold=0.5 \
max-graceful-termination-sec=300 \
balance-similar-node-groups=true
Het profile kan niet per node pool worden ingesteld.
Een expander-strategie kiezen
Wanneer meerdere node groups een pending pod kunnen accommoderen, selecteert de expander welke group uitgebreid wordt:
| Expander | Gedrag | Geschikt voor |
|---|---|---|
random (standaard) |
Kiest een willekeurige eligible group | Gelijkwaardige groups, simpele setups |
least-waste |
Kiest de group die de minste ongebruikte CPU/geheugen achterlaat | Algemene kostenefficiency |
most-pods |
Kiest de group die de meeste pods kan plaatsen | Burst-workloads |
priority |
Door de gebruiker gedefinieerde rangschikking via ConfigMap | Spot voor on-demand, voorkeur instance types |
Expanders kunnen geketend worden: --expander=priority,least-waste past eerst priorityregels toe, en breekt dan ties op basis van least waste.
Priority ConfigMap voorbeeld (voorkeur Spot boven on-demand):
apiVersion: v1
kind: ConfigMap
metadata:
name: cluster-autoscaler-priority-expander
namespace: kube-system
data:
priorities: |-
10:
- .*spot.*
50:
- .*ondemand.*
Hogere nummers worden eerst geprobeerd. Regex-patronen matchen op node group-namen.
Scale-down timing afstellen
De meest impactvolle vlaggen voor kostenoptimalisatie:
| Vlag | Standaard | Wat het beheert |
|---|---|---|
--scale-down-unneeded-time |
10m | Hoe lang een node onderbenut moet zijn voor verwijdering |
--scale-down-delay-after-add |
10m | Cooldown na elke scale-up |
--scale-down-delay-after-delete |
scan-interval | Cooldown na een node-verwijdering |
--scale-down-delay-after-failure |
3m | Cooldown na een gefaalde scale-down poging |
--scale-down-utilization-threshold |
0.5 | Gebruik waaronder een node als "onderbenut" geldt |
Voor ontwikkelclusters waar kosten belangrijker zijn dan stabiliteit:
--scale-down-unneeded-time=3m \
--scale-down-delay-after-add=2m \
--scale-down-utilization-threshold=0.4
Voor productieclusters zijn de defaults prima, of verhoog ze juist. De 10-minuten buffers bestaan omdat voortijdig downscalen gevolgd door direct opschalen duurder uitpakt (node boot-tijd, pod-migratie, mogelijke service-onderbreking) dan een idle node een paar minuten extra draaien.
Diagnose: waarom schaalt een node niet down
CA evalueert nodes voor verwijdering elke scan-interval. Als een node blijft bestaan ondanks lage benutting, blokkeert een van deze oorzaken het:
PodDisruptionBudgets op nul
kubectl get pdb --all-namespaces -o wide
# Zoek naar ALLOWED DISRUPTIONS = 0
Een PDB met maxUnavailable: 0 of minAvailable gelijk aan het totaal aantal replicas blokkeert eviction op die node. Fix dit door percentage-based PDBs te gebruiken (minAvailable: 75%) of door replica counts te verhogen.
Pods met lokale opslag
Standaard blokkeert het eviction van pods die emptyDir of hostPath volumes gebruiken, omdat data verloren zou gaan. Zet --skip-nodes-with-local-storage=false globaal, of annoteer specifieke pods:
metadata:
annotations:
# CA 1.26+ — markeer specifieke volumes als safe to evict
cluster-autoscaler.kubernetes.io/safe-to-evict-local-volumes: "cache-volume,tmp-dir"
Systeempods in kube-system
--skip-nodes-with-system-pods=true (standaard bij de meeste providers) voorkomt het verwijderen van nodes die kube-system pods draaien anders dan DaemonSets. Add-ons als metrics-server of coredns kunnen nodes vasthouden. Zet de vlag op false of annoteer individuele systeempods:
metadata:
annotations:
cluster-autoscaler.kubernetes.io/safe-to-evict: "true"
De safe-to-evict annotatie
Elke pod met de annotatie cluster-autoscaler.kubernetes.io/safe-to-evict: "false" blokkeert scale-down van zijn node. Dit is gepast voor de CA pod zelf en voor langlopende batchjobs met dure herstartkosten.
Node affinity constraints
Als pods op een node requiredDuringSchedulingIgnoredDuringExecution affinity-regels hebben die geen andere node kan voldoen, kan de node niet gedraineerd worden. Gebruik preferredDuringSchedulingIgnoredDuringExecution waar mogelijk.
Timing-vertragingen
Zowel scale-down-delay-after-add als scale-down-unneeded-time moeten verstreken zijn. Na een scale-up wacht CA de volledige delay-after-add periode voordat het welke node dan ook evalueert voor verwijdering, ongeacht hoe onderbenut die is.
Diagnose: waarom triggert een Pending pod geen scale-up
Een pod die in Pending staat garandeert niet dat CA in actie komt. CA helpt alleen als het toevoegen van een node uit een bestaande node group het mogelijk maakt de pod in te plannen. Controleer deze oorzaken in volgorde:
- Geen node group matcht de pod-constraints. Als de pod een
nodeSelector,nodeAffinityof taint-toleratie heeft die geen enkele node group biedt, kan CA niets doen. Check CA events:
kubectl get events --field-selector source=cluster-autoscaler,reason=NotTriggerScaleUp
-
Maximum van de node group bereikt. Het
max-aantal van de ASG of VMSS is een hard plafond. CA logt dit alsmax node group size reached. -
Schalen vanaf nul zonder template tags. Een node group op nul nodes heeft ASG-tags nodig die labels, taints en resources beschrijven. Zonder die tags kan CA niet evalueren of opschalen van de group zou helpen.
-
Te veel unready nodes. Als meer dan
max-total-unready-percentage(standaard 45%) van de nodes NotReady is, stopt CA alle operaties. -
new-pod-scale-up-delayis ingesteld. Pods jonger dan deze waarde worden genegeerd. Handig voor bursty workloads waar de scheduler pieken afhandelt voordat CA hoeft in te grijpen.
Vergelijkbare node groups balanceren over zones
--balance-similar-node-groups=true zorgt dat CA nodes gelijkmatig verdeelt over node groups die dezelfde instance types, labels en taints hebben. Dit is de aanbevolen instelling voor multi-AZ clusters.
Zonder deze instelling kiest CA een enkele group op basis van de expander-strategie, wat alle nieuwe nodes in een beschikbaarheidszone kan concentreren. Bij een zone-uitval wordt die concentratie een single point of failure.
Op AKS stel je het in via het autoscaler profile:
az aks update --resource-group production-rg --name production-aks \
--cluster-autoscaler-profile balance-similar-node-groups=true
Op GKE wordt dit intern door de autoscaler beheerd.
Observeren en debuggen
Status ConfigMap
kubectl get configmap -n kube-system cluster-autoscaler-status -o yaml
Rapporteert de laatste scale-up en scale-down tijden, node group states en algemene gezondheid.
Logs
kubectl logs -n kube-system deployment/cluster-autoscaler --tail=50
Belangrijke logpatronen:
| Patroon | Betekenis |
|---|---|
Scale-up: no suitable node group found |
Pod-constraints niet vervulbaar door een group |
pod has local storage |
Lokale opslag blokkeert scale-down |
pod has PDB |
PDB blokkeert scale-down |
Node X was unneeded for X min |
Countdown tot scale-down |
Scale-down: removing node X |
Actieve node-verwijdering |
Events
# Scale-up beslissingen
kubectl get events --field-selector source=cluster-autoscaler,reason=ScaleUp
# Scale-up niet getriggerd (constraint-mismatches)
kubectl get events --field-selector source=cluster-autoscaler,reason=NotTriggerScaleUp
# Waarschuwingen
kubectl get events --field-selector source=cluster-autoscaler,type=Warning
EKS: verifieer API-toegang
kubectl exec -n kube-system -it deployment/cluster-autoscaler -- \
aws autoscaling describe-auto-scaling-groups --region eu-west-1 --output text --query 'length(AutoScalingGroups)'
Als dit faalt, is IRSA of Pod Identity verkeerd geconfigureerd.
AKS: schakel control plane logs in
Activeer de cluster-autoscaler categorie onder AKS control plane resource logs en query ze in Log Analytics.
Wanneer Karpenter een betere keuze is
Karpenter is een fundamenteel andere aanpak voor node-autoscaling. Waar CA werkt met voorgedefinieerde node groups en cloud-provider scaling APIs, roept Karpenter de EC2 Fleet API rechtstreeks aan en kiest het beste instance type per batch pending pods.
| Dimensie | Cluster Autoscaler | Karpenter |
|---|---|---|
| Provisioningsnelheid | 3-5 min (ASG spin-up) | 45-60 s (EC2 Fleet direct) |
| Instance-selectie | Voorgedefinieerd per node group | Elk instance dat aan NodePool-requirements voldoet |
| Consolidation | Verwijdert alleen idle nodes | Empty, multi-node en single-node consolidation |
| Cloud-ondersteuning | 24+ cloud providers | Alleen EKS (begin 2026) |
Kies CA als: je GKE of AKS draait (waar Karpenter niet beschikbaar is), je strikte AMI-controle per node group nodig hebt, je opereert in gereguleerde omgevingen met voorgedefinieerde instance pools, of je een multi-cloud setup hebt.
Kies Karpenter als: je EKS draait en snellere provisioning wilt, betere bin-packing, geautomatiseerde consolidation en Spot-diversificatie zonder ASGs te beheren. AWS raadt Karpenter aan voor nieuwe EKS-clusters sinds 2025.
Beide kunnen tegelijkertijd draaien tijdens een migratie. Deploy Karpenter naast CA en schaal CA dan geleidelijk af terwijl workloads overgaan naar Karpenter-provisioned nodes.
Wanneer escaleren
Verzamel deze informatie voordat je om hulp vraagt:
- CA logs:
kubectl logs -n kube-system deployment/cluster-autoscaler --tail=100 - Status ConfigMap:
kubectl get configmap -n kube-system cluster-autoscaler-status -o yaml - PDB-status:
kubectl get pdb --all-namespaces -o wide - Pending pods en hun events:
kubectl get pods --field-selector=status.phase=Pending -Aenkubectl describe pod <name> - CA events:
kubectl get events --field-selector source=cluster-autoscaler - Node group-configuratie (ASG-tags, VMSS-instellingen, GKE node pool-config)
- CA-versie en Kubernetes-versie (
kubectl version --short) - Cloud provider en regio