Veröffentlicht am

Vertical Pod Autoscaler (VPA) einrichten und konfigurieren

Teilen:
Authors

Kubernetes Vertical Pod Autoscaler (VPA): Ressourcen automatisch optimieren

TL;DR

  • Der Vertical Pod Autoscaler analysiert die tatsaechliche CPU- und Memory-Nutzung und empfiehlt passende Resource Requests.
  • Drei Update-Modi: Off (nur Empfehlungen), Initial (setzt Requests beim Pod-Start), Auto (evicted und recreated Pods mit neuen Werten).
  • VPA und HPA duerfen nicht gleichzeitig auf CPU oder Memory skalieren -- das fuehrt zu Konflikten. HPA auf Custom Metrics + VPA auf CPU/Memory ist dagegen problemlos.
  • Starten Sie immer im Modus Off, um die Empfehlungen zu pruefen, bevor Sie Auto aktivieren.
  • Goldilocks visualisiert VPA-Empfehlungen fuer alle Workloads im Cluster und zeigt Einsparpotenziale.

Das Problem: Falsche Resource Requests

In den meisten Kubernetes-Clustern sind Resource Requests falsch konfiguriert. Entwickler setzen konservative Werte ("lieber zu viel als zu wenig"), und danach fasst niemand die Werte mehr an.

Das Ergebnis:

# Typischer Cluster: Requests vs. tatsaechliche Nutzung
kubectl top pods -n production
NAME                        CPU(cores)   MEMORY(bytes)
order-service-abc123        45m          180Mi
order-service-def456        52m          175Mi
payment-service-ghi789      12m          95Mi
# Die Requests sind aber:
kubectl get pods -n production -o custom-columns=\
NAME:.metadata.name,\
CPU_REQ:.spec.containers[0].resources.requests.cpu,\
MEM_REQ:.spec.containers[0].resources.requests.memory
NAME                        CPU_REQ   MEM_REQ
order-service-abc123        500m      1Gi
order-service-def456        500m      1Gi
payment-service-ghi789      500m      512Mi

Der order-service nutzt 10% der angeforderten CPU und 18% des angeforderten Memory. Diese Ueberprovisionierung kostet Geld -- Nodes laufen halbvoll, aber der Scheduler denkt, sie waeren ausgelastet.

Der Vertical Pod Autoscaler loest genau dieses Problem.

VPA Architektur: Drei Komponenten

Der VPA besteht aus drei Komponenten, die zusammenarbeiten:

1. Recommender

Beobachtet die historische und aktuelle Ressourcennutzung ueber den Metrics Server. Berechnet daraus Empfehlungen fuer Resource Requests mit Sicherheitspuffer.

2. Updater

Ueberwacht laufende Pods. Wenn die aktuellen Requests stark von den Empfehlungen abweichen und der Update-Modus Auto ist, evicted der Updater den Pod. Der neue Pod wird dann mit den empfohlenen Werten erstellt.

3. Admission Controller

Fuer die Modi Initial und Auto: Wenn ein neuer Pod erstellt wird, modifiziert der Admission Controller die Resource Requests basierend auf der VPA-Empfehlung, bevor der Pod auf einem Node gescheduled wird.

Metrics Server */} Recommender */} Empfehlungen
                                       |
                                       v
                   Updater */} evicted Pods (bei Auto)
                                       |
                                       v
              Admission Controller */} setzt neue Requests beim Pod-Start

Installation per Helm

Der VPA ist nicht standardmaessig in Kubernetes enthalten. Die Installation erfolgt per Helm:

# Voraussetzung: Metrics Server muss laufen
kubectl top nodes
# Wenn das funktioniert, ist der Metrics Server aktiv

# VPA ueber das offizielle Helm Chart installieren
helm repo add fairwinds-stable https://charts.fairwinds.com/stable
helm repo update

helm install vpa fairwinds-stable/vpa \
  --namespace vpa-system \
  --create-namespace \
  --set recommender.enabled=true \
  --set updater.enabled=true \
  --set admissionController.enabled=true
# Installation pruefen
kubectl get pods -n vpa-system

# Erwartete Ausgabe:
# vpa-admission-controller-xxx   1/1   Running
# vpa-recommender-xxx            1/1   Running
# vpa-updater-xxx                1/1   Running

Alternative Installation aus dem offiziellen Kubernetes Repository:

# Clone des autoscaler-Repos
git clone https://github.com/kubernetes/autoscaler.git
cd autoscaler/vertical-pod-autoscaler

# Installation mit dem mitgelieferten Skript
./hack/vpa-up.sh

# Deinstallation
# ./hack/vpa-down.sh

Die drei Update-Modi

Modus Off: Nur Empfehlungen (Einstieg)

Der sicherste Modus. VPA beobachtet und empfiehlt, aendert aber nichts. Ideal zum Kennenlernen und zur Analyse.

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: order-service-vpa
  namespace: production
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: order-service
  updatePolicy:
    updateMode: "Off"
  resourcePolicy:
    containerPolicies:
      - containerName: order-service
        minAllowed:
          cpu: 50m
          memory: 64Mi
        maxAllowed:
          cpu: 2000m
          memory: 4Gi
        controlledResources:
          - cpu
          - memory
# VPA anlegen
kubectl apply -f order-service-vpa.yaml

# Nach 5-10 Minuten: Empfehlungen abrufen
kubectl get vpa order-service-vpa -n production -o yaml

Die Empfehlungen finden Sie im Status-Feld:

status:
  recommendation:
    containerRecommendations:
      - containerName: order-service
        lowerBound:
          cpu: 25m
          memory: 131072k
        target:
          cpu: 60m
          memory: 200Mi
        uncappedTarget:
          cpu: 60m
          memory: 200Mi
        upperBound:
          cpu: 180m
          memory: 400Mi
FeldBedeutung
lowerBoundMinimale Empfehlung (unter diesem Wert ist OOM/Throttling wahrscheinlich)
targetOptimaler Wert (das sollten Ihre Requests sein)
uncappedTargetTarget ohne min/max Constraints
upperBoundMaximale Empfehlung (fuer Lastspitzen)

Modus Initial: Requests beim Pod-Start setzen

Im Initial-Modus setzt der VPA Admission Controller die Resource Requests, wenn ein neuer Pod erstellt wird. Laufende Pods werden nicht angefasst.

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: order-service-vpa
  namespace: production
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: order-service
  updatePolicy:
    updateMode: "Initial"
  resourcePolicy:
    containerPolicies:
      - containerName: order-service
        minAllowed:
          cpu: 50m
          memory: 128Mi
        maxAllowed:
          cpu: 2000m
          memory: 4Gi

Das ist nuetzlich fuer Workloads, die nicht einfach neu gestartet werden koennen. Beim naechsten Rollout oder Restart bekommen die Pods automatisch optimierte Requests.

# Pruefen ob die Requests beim naechsten Pod-Start gesetzt werden
kubectl rollout restart deployment/order-service -n production

# Danach: Requests des neuen Pods pruefen
kubectl get pod -n production -l app=order-service -o jsonpath=\
'{.items[0].spec.containers[0].resources.requests}'

Modus Auto: Vollautomatisch (mit Pod-Neustarts)

Im Auto-Modus evicted der VPA Updater laufende Pods, deren Requests stark von den Empfehlungen abweichen. Die Pods werden mit neuen Requests neu erstellt.

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: order-service-vpa
  namespace: production
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: order-service
  updatePolicy:
    updateMode: "Auto"
    minReplicas: 2
  resourcePolicy:
    containerPolicies:
      - containerName: order-service
        minAllowed:
          cpu: 50m
          memory: 128Mi
        maxAllowed:
          cpu: 2000m
          memory: 4Gi
        controlledResources:
          - cpu
          - memory

Wichtig: minReplicas: 2 stellt sicher, dass der Updater nicht den letzten Pod evicted. Setzen Sie diesen Wert auf die minimale Anzahl an Pods, die fuer Ihre Verfuegbarkeit noetig ist.

# VPA-Events ueberwachen: Wann werden Pods evicted?
kubectl get events -n production --field-selector reason=EvictedByVPA

# Aktuelle VPA-Recommendations vs. tatsaechliche Requests vergleichen
kubectl get vpa -n production -o custom-columns=\
NAME:.metadata.name,\
TARGET_CPU:.status.recommendation.containerRecommendations[0].target.cpu,\
TARGET_MEM:.status.recommendation.containerRecommendations[0].target.memory

VPA fuer mehrere Container im Pod

Pods mit Sidecars (Envoy, Filebeat, etc.) koennen pro Container unterschiedliche Policies haben:

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: web-app-vpa
  namespace: production
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web-app
  updatePolicy:
    updateMode: "Auto"
  resourcePolicy:
    containerPolicies:
      # Hauptcontainer: VPA steuert CPU und Memory
      - containerName: web-app
        minAllowed:
          cpu: 100m
          memory: 128Mi
        maxAllowed:
          cpu: 4000m
          memory: 8Gi
      # Sidecar: Nur Memory wird gesteuert, CPU bleibt fix
      - containerName: envoy-sidecar
        minAllowed:
          cpu: 50m
          memory: 64Mi
        maxAllowed:
          cpu: 200m
          memory: 512Mi
        controlledResources:
          - memory
      # Init-Container: VPA ignorieren
      - containerName: init-migration
        mode: "Off"

VPA und HPA: Die Abgrenzung

VPA und HPA gleichzeitig auf CPU oder Memory zu verwenden, fuehrt zu Konflikten. Der HPA skaliert horizontal (mehr Pods), weil die CPU-Auslastung steigt. Gleichzeitig senkt der VPA die CPU-Requests, was die prozentuale Auslastung weiter erhoeht -- eine Endlosschleife.

# FALSCH: VPA und HPA auf CPU
# VPA
spec:
  resourcePolicy:
    containerPolicies:
      - controlledResources: ["cpu", "memory"]

# HPA
spec:
  metrics:
    - type: Resource
      resource:
        name: cpu                    # Konflikt!
        target:
          type: Utilization
          averageUtilization: 70
# RICHTIG: VPA auf CPU/Memory, HPA auf Custom Metrics
# VPA steuert die Groesse der Pods
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: web-api-vpa
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web-api
  updatePolicy:
    updateMode: "Auto"
  resourcePolicy:
    containerPolicies:
      - containerName: web-api
        controlledResources:
          - cpu
          - memory
---
# HPA steuert die Anzahl der Pods (ueber Custom Metric)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web-api-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web-api
  minReplicas: 2
  maxReplicas: 20
  metrics:
    - type: Pods
      pods:
        metric:
          name: http_requests_per_second    # Custom Metric, kein CPU
        target:
          type: AverageValue
          averageValue: "100"

Fuer eine ausfuehrliche Erklaerung der HPA-Konfiguration empfehlen wir unseren Kubernetes Autoscaling Guide.

Praxisbeispiel: Java-Anwendung mit variablem Heap

Java-Anwendungen sind ein klassischer VPA-Use-Case. Der Heap waechst dynamisch, und die initialen Requests sind fast immer falsch geschaetzt.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: spring-boot-api
  namespace: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: spring-boot-api
  template:
    metadata:
      labels:
        app: spring-boot-api
    spec:
      containers:
        - name: spring-boot-api
          image: registry.example.com/spring-api:v2.3.0
          env:
            - name: JAVA_OPTS
              value: "-XX:MaxRAMPercentage=75.0 -XX:InitialRAMPercentage=50.0"
          resources:
            requests:
              cpu: 200m
              memory: 512Mi
            limits:
              memory: 1Gi
---
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: spring-boot-api-vpa
  namespace: production
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: spring-boot-api
  updatePolicy:
    updateMode: "Auto"
    minReplicas: 2
  resourcePolicy:
    containerPolicies:
      - containerName: spring-boot-api
        minAllowed:
          cpu: 100m
          memory: 256Mi
        maxAllowed:
          cpu: 4000m
          memory: 4Gi

Tipp: Verwenden Sie MaxRAMPercentage statt fester -Xmx-Werte. So passt sich der Heap automatisch an die vom VPA gesetzten Memory-Requests an.

Praxisbeispiel: Batch-Jobs optimieren

Batch-Jobs haben oft stark schwankenden Ressourcenbedarf. Mit VPA im Modus Initial bekommen neue Jobs automatisch passende Requests:

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: data-import-vpa
  namespace: batch
spec:
  targetRef:
    apiVersion: batch/v1
    kind: CronJob
    name: daily-data-import
  updatePolicy:
    updateMode: "Initial"
  resourcePolicy:
    containerPolicies:
      - containerName: data-import
        minAllowed:
          cpu: 100m
          memory: 256Mi
        maxAllowed:
          cpu: 8000m
          memory: 16Gi

Goldilocks: VPA-Empfehlungen visualisieren

Goldilocks von Fairwinds erstellt automatisch VPA-Objekte im Modus Off fuer alle Deployments in einem Namespace und zeigt die Empfehlungen in einem Dashboard an.

# Goldilocks installieren
helm repo add fairwinds-stable https://charts.fairwinds.com/stable
helm repo update

helm install goldilocks fairwinds-stable/goldilocks \
  --namespace goldilocks \
  --create-namespace \
  --set dashboard.enabled=true
# Namespace fuer Goldilocks aktivieren
kubectl label namespace production goldilocks.fairwinds.com/enabled=true

# Dashboard aufrufen
kubectl port-forward -n goldilocks svc/goldilocks-dashboard 8080:80

# Oeffnen Sie http://localhost:8080 im Browser

Das Dashboard zeigt fuer jedes Deployment:

  • Guaranteed QoS: Requests und Limits auf den empfohlenen Wert setzen
  • Burstable QoS: Requests auf den empfohlenen Wert, Limits hoeher
  • Aktuell vs. Empfohlen: Wie weit die aktuellen Werte von der Empfehlung abweichen
# Aktuelle Requests vs. VPA-Empfehlungen fuer alle Deployments anzeigen
kubectl get vpa -n production -o custom-columns=\
DEPLOYMENT:.spec.targetRef.name,\
CPU_TARGET:.status.recommendation.containerRecommendations[0].target.cpu,\
MEM_TARGET:.status.recommendation.containerRecommendations[0].target.memory,\
CPU_LOWER:.status.recommendation.containerRecommendations[0].lowerBound.cpu,\
CPU_UPPER:.status.recommendation.containerRecommendations[0].upperBound.cpu

VPA Troubleshooting

Empfehlungen bleiben leer

# Pruefen ob der Metrics Server funktioniert
kubectl top pods -n production

# Pruefen ob der VPA Recommender laeuft
kubectl logs -n vpa-system -l app=vpa-recommender --tail=50

# Haeufige Ursache: Metrics API nicht verfuegbar
kubectl get apiservice v1beta1.metrics.k8s.io -o yaml

Pods werden nicht evicted (Auto-Modus)

# Updater-Logs pruefen
kubectl logs -n vpa-system -l app=vpa-updater --tail=50

# Pruefen ob das PodDisruptionBudget den Evict blockiert
kubectl get pdb -n production

# Pruefen ob minReplicas das Evict verhindert
kubectl get vpa order-service-vpa -n production -o yaml | \
  grep -A2 updatePolicy

Admission Controller setzt keine Requests

# Webhook-Konfiguration pruefen
kubectl get mutatingwebhookconfigurations | grep vpa

# Admission Controller Logs
kubectl logs -n vpa-system -l app=vpa-admission-controller --tail=50

# Test: Pod loeschen und pruefen ob der neue Pod angepasste Requests hat
kubectl delete pod -n production -l app=order-service --wait=false
kubectl get pods -n production -l app=order-service -o yaml | \
  grep -A4 "resources:"

Best Practices

1. Immer minAllowed und maxAllowed setzen

Ohne Grenzen koennte der VPA extrem kleine oder grosse Werte empfehlen:

resourcePolicy:
  containerPolicies:
    - containerName: app
      minAllowed:
        cpu: 50m        # Unter 50m wird es fuer die meisten Apps eng
        memory: 64Mi    # Unter 64Mi sind OOM-Kills wahrscheinlich
      maxAllowed:
        cpu: 4000m      # Obergrenze basierend auf Node-Groesse
        memory: 8Gi     # Obergrenze basierend auf Budget

2. VPA-Empfehlungen in CI/CD einbauen

Statt den Auto-Modus zu nutzen, koennen Sie die Empfehlungen in Ihre Pipeline integrieren:

# Skript fuer die CI/CD-Pipeline
# VPA-Empfehlungen auslesen und als PR vorschlagen

NAMESPACE="production"
for vpa in $(kubectl get vpa -n "$NAMESPACE" -o jsonpath='{.items[*].metadata.name}'); do
  deployment=$(kubectl get vpa "$vpa" -n "$NAMESPACE" \
    -o jsonpath='{.spec.targetRef.name}')
  target_cpu=$(kubectl get vpa "$vpa" -n "$NAMESPACE" \
    -o jsonpath='{.status.recommendation.containerRecommendations[0].target.cpu}')
  target_mem=$(kubectl get vpa "$vpa" -n "$NAMESPACE" \
    -o jsonpath='{.status.recommendation.containerRecommendations[0].target.memory}')
  echo "Deployment: $deployment -> CPU: $target_cpu, Memory: $target_mem"
done

3. PodDisruptionBudgets verwenden

Im Auto-Modus evicted der VPA Pods. Ohne PDB koennte er alle Pods gleichzeitig evicten:

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: order-service-pdb
  namespace: production
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: order-service

Mehr zum Thema PodDisruptionBudgets finden Sie in unserem PDB Guide.

4. Schrittweise einfuehren

# Phase 1: VPA im Off-Modus fuer alle Namespaces (2 Wochen)
# -> Empfehlungen analysieren, Einsparpotenzial berechnen

# Phase 2: VPA im Initial-Modus fuer Staging (2 Wochen)
# -> Pruefen ob die empfohlenen Werte in der Praxis funktionieren

# Phase 3: VPA im Auto-Modus fuer Staging (2 Wochen)
# -> Eviction-Verhalten beobachten, PDBs pruefen

# Phase 4: VPA im Auto-Modus fuer Production
# -> Mit konservativen minAllowed-Werten starten

Kosten-Impact: Was bringt der VPA?

Ein typisches Beispiel aus der Praxis:

Vorher (manuelle Requests):
  20 Pods x 500m CPU x 1Gi Memory = 10 CPU Cores, 20Gi Memory reserviert
  Tatsaechliche Nutzung: 2 CPU Cores, 5Gi Memory
  Auslastung: 20% CPU, 25% Memory

Nachher (VPA-optimiert):
  20 Pods x 120m CPU x 300Mi Memory = 2.4 CPU Cores, 6Gi Memory reserviert
  Tatsaechliche Nutzung: 2 CPU Cores, 5Gi Memory
  Auslastung: 83% CPU, 83% Memory

Einsparung: 3-4 Nodes weniger noetig

In Kombination mit dem Cluster Autoscaler fuehrt das direkt zu geringeren Cloud-Kosten. Fuer eine umfassende Kosten-Strategie lesen Sie unseren Kubernetes Kosten-Optimierung Guide.

Fazit

Der Vertical Pod Autoscaler loest ein Problem, das in fast jedem Kubernetes-Cluster existiert: falsche Resource Requests. Die Installation ist einfach, der Modus Off ist risikolos, und die Empfehlungen sind in den meisten Faellen praezise.

Starten Sie mit dem Modus Off und Goldilocks fuer die Visualisierung. Analysieren Sie die Empfehlungen fuer zwei Wochen. Dann wechseln Sie schrittweise auf Initial oder Auto. Die typische Einsparung liegt bei 30-50% der reservierten Ressourcen -- das sind bei groesseren Clustern schnell mehrere tausend Euro im Monat.

Fuer das Zusammenspiel mit HPA und Cluster Autoscaler lesen Sie unseren Autoscaling-Gesamtueberblick.


Verwandte Artikel


Moechten Sie die Ressourcen-Effizienz Ihres Kubernetes-Clusters analysieren lassen? Unsere Experten fuehren eine kostenfreie Erstanalyse durch und zeigen Ihnen das konkrete Einsparpotenzial mit VPA und Goldilocks -- jetzt Termin vereinbaren.

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