Veröffentlicht am

Cluster Autoscaler: Kubernetes-Nodes optimal skalieren

Teilen:
Authors

Cluster Autoscaler optimieren: Nodes kosteneffizient skalieren

TL;DR

Der Cluster Autoscaler skaliert Nodes automatisch, aber die Default-Konfiguration verschwendet Geld. Mit der richtigen Expander-Strategie (least-waste oder priority), angepassten Scale-Down-Timings und Mixed-Instance-Node-Groups laesst sich der Cluster um 30-50% guenstiger betreiben. Karpenter ist die modernere Alternative mit schnellerem Scheduling und besserem Bin-Packing.


Das Problem mit Default-Einstellungen

Der Cluster Autoscaler funktioniert out-of-the-box, aber die Standard-Konfiguration ist konservativ: Nodes werden erst nach 10 Minuten herunterskaliert, der Expander waehlt zufaellig, und Node Groups sind oft nicht optimal konfiguriert.

# Aktuelle Autoscaler-Konfiguration pruefen
kubectl get configmap cluster-autoscaler-status -n kube-system -o yaml

# Autoscaler-Logs: Warum werden Nodes nicht skaliert?
kubectl logs -n kube-system -l app.kubernetes.io/name=cluster-autoscaler \
  --tail=50 | grep -E "scale|expander|unneeded"

Typische Symptome schlechter Konfiguration: Nodes laufen mit 20% Auslastung, Scale-Up dauert zu lange, oder der falsche Node-Typ wird gewaehlt.

Expander-Strategien im Detail

Der Expander entscheidet, welche Node Group beim Scale-Up gewaehlt wird. Diese Entscheidung hat direkten Einfluss auf die Kosten.

Random (Default)

Waehlt zufaellig eine passende Node Group. Einfach, aber ineffizient bei heterogenen Node Groups.

Most-Pods

Waehlt die Node Group, die die meisten Pending Pods aufnehmen kann. Sinnvoll bei Batch-Workloads mit vielen kleinen Pods.

Least-Waste

Waehlt die Node Group mit der geringsten Ressourcenverschwendung nach dem Scheduling. Die beste Wahl fuer Kostenoptimierung.

# Cluster Autoscaler mit least-waste Expander deployen
helm upgrade cluster-autoscaler autoscaler/cluster-autoscaler \
  --namespace kube-system \
  --set extraArgs.expander=least-waste \
  --set autoDiscovery.clusterName=mein-cluster \
  --set awsRegion=eu-central-1

Priority Expander

Der Priority Expander ermoeglicht eine feste Rangfolge. Der haeufigste Anwendungsfall: Spot-Instances bevorzugen, On-Demand als Fallback.

# priority-expander-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: cluster-autoscaler-priority-expander
  namespace: kube-system
data:
  priorities: |
    100:
      - .*spot-arm64.*
    80:
      - .*spot-amd64.*
    50:
      - .*ondemand-small.*
    30:
      - .*ondemand-medium.*
    10:
      - .*ondemand-large.*
kubectl apply -f priority-expander-configmap.yaml

# Autoscaler mit Priority-Expander konfigurieren
helm upgrade cluster-autoscaler autoscaler/cluster-autoscaler \
  --namespace kube-system \
  --set extraArgs.expander=priority \
  --set autoDiscovery.clusterName=mein-cluster

Der Autoscaler versucht zuerst die Node Group mit der hoechsten Prioritaet. Wenn diese nicht skalieren kann (z.B. weil Spot-Kapazitaet erschoepft ist), faellt er auf die naechste zurueck.

Scale-Down-Einstellungen optimieren

Die Scale-Down-Parameter bestimmen, wie aggressiv der Autoscaler ungenutzte Nodes entfernt.

# values-optimized.yaml
extraArgs:
  # Nach Scale-Up 5 Minuten warten statt 10
  scale-down-delay-after-add: "5m"

  # Node als unneeded markieren nach 5 Minuten statt 10
  scale-down-unneeded-time: "5m"

  # Node entfernen wenn unter 50% Auslastung
  scale-down-utilization-threshold: "0.5"

  # Scale-Down nach Fehler: 3 Minuten Pause
  scale-down-delay-after-failure: "3m"

  # Maximal 1 Node gleichzeitig entfernen (stabiler)
  max-graceful-termination-sec: "600"

  # Scan-Intervall: alle 10 Sekunden pruefen
  scan-interval: "10s"

  # Nodes mit local-storage duerfen entfernt werden
  skip-nodes-with-local-storage: "false"
helm upgrade cluster-autoscaler autoscaler/cluster-autoscaler \
  --namespace kube-system \
  -f values-optimized.yaml
ParameterDefaultEmpfehlung ProduktionEmpfehlung Staging
scale-down-delay-after-add10m5m2m
scale-down-unneeded-time10m5m2m
scale-down-utilization-threshold0.50.50.65
scan-interval10s10s10s
max-node-provision-time15m10m10m

Fuer Staging-Cluster koennen die Werte aggressiver eingestellt werden, da Ausfallzeiten weniger kritisch sind.

Node-Group-Konfiguration mit Mixed Instances

Eine einzelne Node Group mit einem Instanztyp ist selten optimal. Besser: Mehrere Node Groups mit unterschiedlichen Groessen, kombiniert mit dem Priority- oder Least-Waste-Expander.

# AWS EKS Managed Node Group mit Mixed Instances
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
  name: production-cluster
  region: eu-central-1

managedNodeGroups:
  - name: spot-arm64
    instanceTypes: ["m7g.large", "m6g.large", "c7g.large"]
    capacityType: SPOT
    minSize: 0
    maxSize: 20
    desiredCapacity: 2
    labels:
      capacity-type: spot
      arch: arm64
    tags:
      k8s.io/cluster-autoscaler/enabled: "true"
      k8s.io/cluster-autoscaler/production-cluster: "owned"

  - name: spot-amd64
    instanceTypes: ["m6i.large", "m5.large", "c6i.large", "c5.large"]
    capacityType: SPOT
    minSize: 0
    maxSize: 15
    desiredCapacity: 1
    labels:
      capacity-type: spot
      arch: amd64
    tags:
      k8s.io/cluster-autoscaler/enabled: "true"

  - name: ondemand-critical
    instanceTypes: ["m6i.xlarge"]
    capacityType: ON_DEMAND
    minSize: 2
    maxSize: 10
    desiredCapacity: 3
    labels:
      capacity-type: on-demand
      workload-type: critical
    taints:
      - key: workload-type
        value: critical
        effect: NoSchedule
    tags:
      k8s.io/cluster-autoscaler/enabled: "true"

Die Kombination aus Spot- und On-Demand-Node-Groups mit dem Priority-Expander ergibt eine kosteneffiziente und zuverlaessige Architektur: Unkritische Workloads laufen auf Spot, Datenbanken und Stateful-Services auf On-Demand.

Nodes vor Scale-Down schuetzen

Bestimmte Nodes sollen nie herunterskaliert werden -- etwa solche mit lokalen Datenbanken oder lang laufenden Batch-Jobs.

# Node vor Scale-Down schuetzen
kubectl annotate node ip-10-0-1-42.ec2.internal \
  cluster-autoscaler.kubernetes.io/scale-down-disabled=true

# Pod als safe-to-evict markieren (erlaubt Scale-Down)
kubectl annotate pod batch-job-xyz \
  cluster-autoscaler.kubernetes.io/safe-to-evict=true

# Schutz-Annotation entfernen
kubectl annotate node ip-10-0-1-42.ec2.internal \
  cluster-autoscaler.kubernetes.io/scale-down-disabled-

PodDisruptionBudgets blockieren ebenfalls das Scale-Down. Ein minAvailable: 100% verhindert jede Eviction. Mehr dazu in unserem PDB-Guide.

Karpenter als Alternative

Karpenter ersetzt das Node-Group-Konzept durch dynamische Provisionierung. Statt vordefinierter Node Groups waehlt Karpenter den optimalen Instanztyp pro Pod.

# Karpenter NodePool: Flexibel und kostenoptimiert
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: default
spec:
  template:
    spec:
      nodeClassRef:
        group: karpenter.k8s.aws
        kind: EC2NodeClass
        name: default
      requirements:
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot", "on-demand"]
        - key: karpenter.k8s.aws/instance-category
          operator: In
          values: ["m", "c", "r"]
        - key: karpenter.k8s.aws/instance-generation
          operator: Gt
          values: ["5"]
        - key: topology.kubernetes.io/zone
          operator: In
          values: ["eu-central-1a", "eu-central-1b", "eu-central-1c"]
  limits:
    cpu: "400"
    memory: 1600Gi
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    consolidateAfter: 30s

Die wichtigsten Unterschiede in der Praxis:

Geschwindigkeit: Karpenter provisioniert Nodes in unter 10 Sekunden, der Cluster Autoscaler braucht 30-60 Sekunden. Das liegt daran, dass Karpenter direkt die Cloud-API aufruft, waehrend der CA ueber Auto Scaling Groups arbeitet.

Bin-Packing: Karpenter konsolidiert aktiv -- wenn zwei halb ausgelastete Nodes durch einen voll ausgelasteten ersetzt werden koennen, macht Karpenter das automatisch. Der CA entfernt nur leere oder unterausgelastete Nodes.

Einschraenkung: Karpenter ist fuer AWS produktionsreif (GA), fuer Azure in Beta. Auf GCP und On-Prem bleibt der Cluster Autoscaler die einzige Option.

Einen ausfuehrlichen Vergleich finden Sie in unserem Cluster Autoscaler Grundlagen-Artikel.

FAQ

Welchen Expander soll ich waehlen?

Fuer die meisten Produktions-Cluster ist least-waste die beste Wahl. Wenn Spot-Instances bevorzugt werden sollen, ist priority mit einer Spot-First-Konfiguration optimal. random und most-pods sind nur fuer einfache oder spezielle Setups sinnvoll.

Warum werden meine Nodes nicht herunterskaliert?

Haeufigste Ursachen: Pods ohne Controller (bare Pods), PodDisruptionBudgets die Eviction blockieren, Pods mit local-storage, oder die Annotation safe-to-evict=false. Die Autoscaler-Logs zeigen den genauen Grund.

Kann ich Cluster Autoscaler und Karpenter gleichzeitig nutzen?

Nein, das wird nicht empfohlen. Beide wuerden um die Node-Verwaltung konkurrieren. Bei einer Migration von CA zu Karpenter sollte schrittweise umgestellt werden: Erst neue Workloads auf Karpenter, dann bestehende migrieren.

Wie verhindere ich, dass der Autoscaler zu viele Nodes startet?

Mit max-nodes-total laesst sich ein globales Limit setzen. Zusaetzlich hat jede Node Group eigene minSize- und maxSize-Werte. Kosten-Alerts ueber Kubecost oder OpenCost ergaenzen die technischen Limits.

Wie interagiert der Cluster Autoscaler mit HPA?

HPA skaliert Pods, CA skaliert Nodes. Wenn HPA neue Pods erstellt und kein Node Kapazitaet hat, erkennt der CA die Pending Pods und fuegt Nodes hinzu. Die Kombination funktioniert automatisch, aber die Reihenfolge (erst Pod-Scale-Up, dann Node-Scale-Up) fuehrt zu einer Latenz von 30-90 Sekunden.

Verwandte Artikel

Kubernetes-Expertise gesucht?

Managed Services, Beratung, Training oder Security – wir unterstützen deutsche Unternehmen bei allen Kubernetes-Themen.

Kubernetes-Beratung gesucht?

Wir helfen deutschen Unternehmen bei der Kubernetes-Implementierung, Migration und Optimierung. DSGVO-konform und praxiserprobt.

📖 Verwandte Artikel

Weitere interessante Beiträge zu ähnlichen Themen