- Authors

- Name
- Phillip Pham
- @ddppham
Kubernetes Karpenter: 60% schnellere Node-Provisionierung auf AWS
TL;DR
- Karpenter provisioniert Nodes in unter 60 Sekunden -- der Cluster Autoscaler braucht 2-5 Minuten ueber Node Groups.
- Statt vordefinierter Node Groups waehlt Karpenter dynamisch aus ueber 700 EC2-Instance-Typen die optimale Instanz.
- NodePool und EC2NodeClass sind die zentralen Ressourcen seit Karpenter v1.0 (GA).
- Consolidation packt Pods automatisch auf weniger Nodes und entfernt ungenutzte Kapazitaet.
- Spot-Instance-Integration mit Interruption Handling spart 60-90% gegenueber On-Demand.
Warum der Cluster Autoscaler an seine Grenzen stoesst
Der Cluster Autoscaler skaliert ueber Managed Node Groups. Jede Node Group hat einen festen Instance-Typ, ein Minimum und Maximum. Braucht ein Team GPUs, muss vorab eine GPU-Node-Group existieren. In der Praxis entstehen 10-20 Node Groups, jede manuell konfiguriert.
Dazu kommen Timing-Probleme: CA prueft in Intervallen ob Pods pending sind, triggered die ASG, die EC2-Instanz muss booten und dem Cluster beitreten. Das dauert 2-5 Minuten. Mehr zu Autoscaling-Optionen unter Kubernetes Autoscaling und Kosten sparen.
Wie Karpenter anders arbeitet
Karpenter ueberspringt Node Groups komplett. Sobald ein Pod nicht schedulbar ist, berechnet Karpenter welcher EC2-Instance-Typ das beste Preis-Leistungs-Verhaeltnis bietet und startet die Instanz direkt ueber die AWS-API.
| Feature | Cluster Autoscaler | Karpenter |
|---|---|---|
| Provisionierungszeit | 2-5 Minuten | 30-90 Sekunden |
| Instance-Auswahl | Feste Node Groups | Dynamisch aus allen Typen |
| Spot-Integration | Mixed Instances Policy | Native Fleet-API |
| Bin Packing | Begrenzt | Aktive Consolidation |
| GPU-Support | Eigene Node Group noetig | Automatische Auswahl |
| Downscaling | 10+ Minuten Cooldown | Aggressiv konfigurierbar |
Installation auf EKS
IAM-Rollen und OIDC
export CLUSTER_NAME="production-cluster"
export AWS_REGION="eu-central-1"
export KARPENTER_VERSION="1.1.0"
# OIDC Provider erstellen
eksctl utils associate-iam-oidc-provider \
--cluster ${CLUSTER_NAME} \
--region ${AWS_REGION} --approve
# IAM-Rolle fuer Karpenter
eksctl create iamserviceaccount \
--cluster ${CLUSTER_NAME} \
--name karpenter --namespace kube-system \
--role-name "KarpenterControllerRole-${CLUSTER_NAME}" \
--attach-policy-arn "arn:aws:iam::$(aws sts get-caller-identity --query Account --output text):policy/KarpenterControllerPolicy" \
--approve
Helm-Installation
helm upgrade --install karpenter oci://public.ecr.aws/karpenter/karpenter \
--version "${KARPENTER_VERSION}" \
--namespace kube-system \
--set "settings.clusterName=${CLUSTER_NAME}" \
--set "settings.interruptionQueueName=karpenter-${CLUSTER_NAME}" \
--set controller.resources.requests.cpu=1 \
--set controller.resources.requests.memory=1Gi \
--wait
kubectl get pods -n kube-system -l app.kubernetes.io/name=karpenter
Fuer Helm-Grundlagen: Helm Charts Einfuehrung.
NodePool-Konfiguration
Allgemeiner Production NodePool
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: general-purpose
spec:
template:
metadata:
labels:
workload-type: general
spec:
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: default
requirements:
- key: kubernetes.io/arch
operator: In
values: ["amd64"]
- key: karpenter.sh/capacity-type
operator: In
values: ["on-demand", "spot"]
- key: karpenter.k8s.aws/instance-category
operator: In
values: ["c", "m", "r"]
- key: karpenter.k8s.aws/instance-generation
operator: Gt
values: ["5"]
- key: karpenter.k8s.aws/instance-size
operator: In
values: ["large", "xlarge", "2xlarge", "4xlarge"]
expireAfter: 720h
disruption:
consolidationPolicy: WhenEmptyOrUnderutilized
consolidateAfter: 60s
limits:
cpu: "200"
memory: 800Gi
weight: 50
Spot-optimierter NodePool fuer Batch-Jobs
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: batch-spot
spec:
template:
metadata:
labels:
workload-type: batch
taints:
- key: batch-only
value: "true"
effect: NoSchedule
spec:
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: default
requirements:
- key: karpenter.sh/capacity-type
operator: In
values: ["spot"]
- key: karpenter.k8s.aws/instance-category
operator: In
values: ["c", "m", "r"]
- key: karpenter.k8s.aws/instance-generation
operator: Gt
values: ["5"]
expireAfter: 168h
disruption:
consolidationPolicy: WhenEmptyOrUnderutilized
consolidateAfter: 30s
limits:
cpu: "400"
memory: 1600Gi
weight: 80
EC2NodeClass: AWS-spezifische Einstellungen
apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
metadata:
name: default
spec:
role: "KarpenterNodeRole-production-cluster"
amiSelectorTerms:
- alias: al2023@latest
subnetSelectorTerms:
- tags:
karpenter.sh/discovery: "production-cluster"
securityGroupSelectorTerms:
- tags:
karpenter.sh/discovery: "production-cluster"
blockDeviceMappings:
- deviceName: /dev/xvda
ebs:
volumeSize: 100Gi
volumeType: gp3
iops: 3000
throughput: 125
encrypted: true
deleteOnTermination: true
metadataOptions:
httpEndpoint: enabled
httpPutResponseHopLimit: 2
httpTokens: required
tags:
Environment: production
ManagedBy: karpenter
Consolidation: Automatisches Bin Packing
Consolidation ist eines der staerksten Karpenter-Features. Im Modus WhenEmptyOrUnderutilized ersetzt Karpenter unterausgelastete Nodes durch kleinere Instanzen:
Vorher:
Node 1 (m5.2xlarge - 8 vCPU): Pod A (2 CPU), Pod B (1 CPU) = 37%
Node 2 (m5.2xlarge - 8 vCPU): Pod C (1 CPU) = 12%
Node 3 (m5.2xlarge - 8 vCPU): leer = 0%
Nachher:
Node 1 (m5.xlarge - 4 vCPU): Pod A, Pod B, Pod C = 100%
Ersparnis: 2 Nodes weniger = ca. 66% Kostenreduktion
Disruption Budgets
disruption:
consolidationPolicy: WhenEmptyOrUnderutilized
consolidateAfter: 60s
budgets:
- nodes: "10%"
- nodes: "0"
schedule: "0 9 * * 1-5"
duration: 8h
Maximal 10% der Nodes gleichzeitig. Zwischen 9 und 17 Uhr an Werktagen keine Disruption. Karpenter respektiert ausserdem PodDisruptionBudgets:
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: webapp-pdb
namespace: webapp
spec:
minAvailable: 2
selector:
matchLabels:
app: webapp
Spot-Instance-Handling
Interruption Queue einrichten
export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
aws sqs create-queue \
--queue-name "karpenter-${CLUSTER_NAME}" \
--region ${AWS_REGION}
aws events put-rule \
--name "karpenter-spot-interruption" \
--event-pattern '{"source":["aws.ec2"],"detail-type":["EC2 Spot Instance Interruption Warning"]}' \
--region ${AWS_REGION}
aws events put-targets \
--rule "karpenter-spot-interruption" \
--targets "Id=karpenter-queue,Arn=arn:aws:sqs:${AWS_REGION}:${AWS_ACCOUNT_ID}:karpenter-${CLUSTER_NAME}" \
--region ${AWS_REGION}
Bei einer Spot-Interruption empfaengt Karpenter die Nachricht, cordoned den Node, draint Pods unter Beachtung der PDBs und startet einen Ersatz-Node. Die Fleet-API waehlt automatisch den Instance-Typ mit der hoechsten Verfuegbarkeit.
Kostenbeispiel
Cluster Autoscaler (On-Demand, m5.2xlarge):
Monatsdurchschnitt bei 60% Auslastung: ca. 1.800 EUR/Monat
Karpenter (Mix aus m5/m6i/m7i, Spot wo moeglich):
Consolidation + Spot: ca. 650 EUR/Monat
Ersparnis: ca. 64%
Fuer weitergehende Kostenstrategien: Kubernetes Kosten-Optimierung Praxis-Guide.
Migration vom Cluster Autoscaler
Schritt 1: Karpenter parallel installieren
# Cluster Autoscaler NICHT sofort deinstallieren
kubectl apply -f nodepool-general.yaml
kubectl get nodepools
kubectl get ec2nodeclasses
Schritt 2: Workloads schrittweise migrieren
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp
spec:
template:
spec:
nodeSelector:
karpenter.sh/nodepool: general-purpose
containers:
- name: webapp
image: webapp:latest
resources:
requests:
cpu: "500m"
memory: 512Mi
Schritt 3: Node Groups entfernen
# ASG auf 0 setzen, dann Cluster Autoscaler deinstallieren
aws autoscaling update-auto-scaling-group \
--auto-scaling-group-name "eks-nodegroup-general" \
--min-size 0 --desired-capacity 0 --max-size 0
helm uninstall cluster-autoscaler -n kube-system
Monitoring mit Prometheus
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: karpenter
namespace: kube-system
spec:
selector:
matchLabels:
app.kubernetes.io/name: karpenter
endpoints:
- port: http-metrics
interval: 30s
Wichtige Metriken:
karpenter_nodes_created_total # Provisionierte Nodes
karpenter_pods_startup_duration_seconds # Pod-Startzeit
karpenter_disruption_actions_performed_total # Consolidation-Aktivitaet
karpenter_nodepools_usage{resource_type="cpu"} # CPU-Auslastung
karpenter_nodeclaims_created_total{capacity_type="spot"} # Spot vs. On-Demand
Fuer die vollstaendige Monitoring-Strategie: Kubernetes Monitoring und Observability.
Troubleshooting
# Controller Logs
kubectl logs -n kube-system -l app.kubernetes.io/name=karpenter -f
# NodePool Limits erreicht?
kubectl get nodepool general-purpose -o jsonpath='{.status.resources}'
# Subnets/Security Groups pruefen
kubectl describe ec2nodeclass default
# Instance-Typ nicht verfuegbar?
kubectl logs -n kube-system -l app.kubernetes.io/name=karpenter | grep "InsufficientInstanceCapacity"
# Alle Karpenter-Nodes anzeigen
kubectl get nodes -l karpenter.sh/nodepool
Fazit
Karpenter ist fuer EKS-Cluster der klare Nachfolger des Cluster Autoscalers. Schnellere Provisionierung, automatische Instance-Auswahl und aggressive Consolidation sparen Kosten und reduzieren Komplexitaet. Die Migration kann schrittweise erfolgen. Fuer EKS-Best-Practices: AWS EKS Enterprise Kubernetes.
Verwandte Artikel
- Kubernetes Autoscaling und Kosten sparen
- Kubernetes Kosten-Optimierung Praxis-Guide
- AWS EKS Enterprise Kubernetes
- Kubernetes Monitoring und Observability
- Helm Charts fuer Kubernetes
Braucht ihr Unterstuetzung bei der Karpenter-Einfuehrung oder der Migration vom Cluster Autoscaler? Kontaktiert uns fuer eine individuelle Beratung.
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
Cluster Autoscaler einrichten: Nodes automatisch skalieren
Kubernetes Cluster Autoscaler installieren und konfigurieren für automatische Node-Skalierung mit Helm, Karpenter-Vergleich und Spot-Instance-Strategien.
Cluster Autoscaler: Kubernetes-Nodes optimal skalieren
Cluster Autoscaler optimieren mit Expander-Strategien, Scale-Down-Tuning und Priority-Konfiguration für kosteneffiziente Node-Skalierung.
Capacity Planning: Kubernetes-Autoscaling richtig nutzen
HPA, VPA, Cluster Autoscaler und KEDA kombinieren für Capacity Planning in Kubernetes. Mit Praxisbeispielen und Entscheidungshilfe.
Custom Metrics: Kubernetes-Autoscaling mit Prometheus
HPA mit Custom Metrics aus Prometheus konfigurieren. Prometheus Adapter installieren, Metriken registrieren und Pods nach Requests pro Sekunde skalieren.
Node.js auf Kubernetes: Express-App deployen
Express-Apps auf Kubernetes deployen mit Multi-Stage Dockerfile, Graceful Shutdown, Resource Limits und HPA für stabile Production-Cluster.