Kubernetes Cluster Autoscaler: automatisch nodes schalen voor managed clusters

Cluster Autoscaler houdt de API server in de gaten op pods die in Pending staan omdat er geen node capaciteit is, en voegt dan een node toe uit een passende node group. Wanneer nodes lang genoeg onder de 50% resource-gebruik zakken, worden ze verwijderd. Deze guide behandelt het configureren van Cluster Autoscaler op EKS, GKE en AKS, het afstellen van scale-down timing, het diagnosticeren van veelvoorkomende blokkades, en wanneer Karpenter een betere keuze is.

Inhoudsopgave

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

  • kubectl verbonden 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:

  1. De som van alle pod-requests op de node is lager dan scale-down-utilization-threshold (standaard 0.5, dus 50%)
  2. Elke pod op de node kan opnieuw ingepland worden op andere bestaande nodes
  3. 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:

  1. Geen node group matcht de pod-constraints. Als de pod een nodeSelector, nodeAffinity of 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
  1. Maximum van de node group bereikt. Het max-aantal van de ASG of VMSS is een hard plafond. CA logt dit als max node group size reached.

  2. 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.

  3. Te veel unready nodes. Als meer dan max-total-unready-percentage (standaard 45%) van de nodes NotReady is, stopt CA alle operaties.

  4. new-pod-scale-up-delay is 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 -A en kubectl 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

Terugkerende server- of deploymentproblemen?

Ik help teams productie betrouwbaar maken met CI/CD, Kubernetes en cloud—zodat fixes blijven en deploys geen stress meer zijn.

Bekijk DevOps consultancy

Doorzoek deze site

Begin met typen om te zoeken, of blader door de kennisbank en blog.