Veröffentlicht am

Resource Requests und Limits: Kubernetes-Guide

Teilen:
Authors

TL;DR

Requests reservieren Ressourcen für den Scheduler, Limits begrenzen den tatsächlichen Verbrauch. CPU wird bei Überschreitung gedrosselt (Throttling), Memory führt zum OOMKill. Kubernetes ordnet Pods in drei QoS-Klassen ein: Guaranteed, Burstable und BestEffort. Setzen Sie immer Memory-Limits und nutzen Sie LimitRange als Namespace-Default.

Requests vs. Limits verstehen

Der Scheduler nutzt Requests um zu entscheiden, auf welchem Node ein Pod platziert wird. Limits begrenzen, was ein Container maximal nutzen darf.

apiVersion: v1
kind: Pod
metadata:
  name: web-app
spec:
  containers:
    - name: app
      image: nginx:1.27
      resources:
        requests:
          cpu: 250m       # 0.25 CPU-Cores reserviert
          memory: 128Mi   # 128 MiB reserviert
        limits:
          cpu: 500m       # max 0.5 CPU-Cores
          memory: 256Mi   # max 256 MiB

CPU-Einheiten: 1000m = 1 vCPU/Core. 250m = ein Viertel Core.

Memory-Einheiten: Mi (Mebibyte), Gi (Gibibyte). Vermeiden Sie M und G (Dezimal) - die Differenz kann bei großen Werten relevant werden.


CPU vs. Memory: Unterschiedliches Verhalten

Das ist die wichtigste Unterscheidung bei Kubernetes-Ressourcen:

AspektCPUMemory
TypKompressibelInkompressibel
Bei Limit-ÜberschreitungThrottling (gedrosselt)OOMKill (Pod-Neustart)
Unter-ProvisionierungLangsamere AntwortzeitenCrash
Über-ProvisionierungVerschwendungVerschwendung

CPU-Throttling erkennen

CPU-Throttling ist heimtückisch - der Container stürzt nicht ab, wird aber langsamer. So erkennen Sie es:

# Throttling-Statistiken aus cgroup lesen
kubectl exec web-app -- cat /sys/fs/cgroup/cpu.stat
# nr_throttled: Anzahl der Throttling-Perioden
# throttled_usec: Gesamte gedrosselte Zeit

# Aktuellen Verbrauch prüfen
kubectl top pod web-app

OOMKill erkennen

# Pod-Status prüfen
kubectl get pod web-app -o jsonpath='{.status.containerStatuses[0].lastState}'

# Events zeigen OOMKilled
kubectl describe pod web-app | grep -i oom

# Typische Ausgabe:
# Last State: Terminated
#   Reason: OOMKilled
#   Exit Code: 137

Exit Code 137 bedeutet immer OOMKill (128 + Signal 9).


QoS-Klassen im Detail

Kubernetes ordnet jedem Pod automatisch eine Quality-of-Service-Klasse zu. Bei Ressourcenknappheit werden Pods in dieser Reihenfolge evicted: BestEffort zuerst, dann Burstable, zuletzt Guaranteed.

Guaranteed: Höchste Priorität

Requests und Limits sind identisch für alle Container im Pod:

apiVersion: v1
kind: Pod
metadata:
  name: database
spec:
  containers:
    - name: postgres
      image: postgres:16
      resources:
        requests:
          cpu: "1"
          memory: 2Gi
        limits:
          cpu: "1"
          memory: 2Gi

Einsatz: Datenbanken, Stateful Workloads, kritische Services. Der Pod bekommt exakt die angeforderten Ressourcen.

Burstable: Mittlere Priorität

Mindestens ein Container hat Requests, aber Limits und Requests unterscheiden sich:

apiVersion: v1
kind: Pod
metadata:
  name: api-server
spec:
  containers:
    - name: api
      image: my-api:v3
      resources:
        requests:
          cpu: 200m
          memory: 256Mi
        limits:
          cpu: "1"
          memory: 1Gi

Einsatz: Die meisten Anwendungen. Der Pod kann bei Bedarf mehr Ressourcen nutzen als reserviert, riskiert aber Throttling und Eviction.

BestEffort: Niedrigste Priorität

Keine Requests und keine Limits definiert:

apiVersion: v1
kind: Pod
metadata:
  name: batch-job
spec:
  containers:
    - name: worker
      image: busybox
      command: ["sh", "-c", "echo hello"]
      # Keine resources-Sektion

Einsatz: Nur für unkritische Batch-Jobs oder Entwicklungsumgebungen. Diese Pods werden bei Ressourcenknappheit als Erstes beendet.

# QoS-Klasse eines Pods prüfen
kubectl get pod database -o jsonpath='{.status.qosClass}'
# Ausgabe: Guaranteed

LimitRange: Namespace-weite Defaults

Ohne LimitRange können Entwickler Pods ohne Limits deployen - ein Risiko für die Cluster-Stabilität. LimitRange setzt Defaults und erzwingt Grenzen pro Container.

apiVersion: v1
kind: LimitRange
metadata:
  name: default-limits
  namespace: production
spec:
  limits:
    - type: Container
      default:          # Standard-Limits wenn keine gesetzt
        cpu: 500m
        memory: 512Mi
      defaultRequest:   # Standard-Requests wenn keine gesetzt
        cpu: 100m
        memory: 128Mi
      min:              # Minimum pro Container
        cpu: 50m
        memory: 64Mi
      max:              # Maximum pro Container
        cpu: "4"
        memory: 8Gi
# LimitRange anwenden
kubectl apply -f limitrange.yaml

# Prüfen
kubectl describe limitrange default-limits -n production

Pods die nach dem Erstellen der LimitRange deployed werden, bekommen automatisch die Defaults. Bestehende Pods sind nicht betroffen.

ResourceQuota: Gesamtbudget pro Namespace

Während LimitRange einzelne Container begrenzt, limitiert ResourceQuota den gesamten Namespace:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: team-quota
  namespace: production
spec:
  hard:
    requests.cpu: "10"
    requests.memory: 20Gi
    limits.cpu: "20"
    limits.memory: 40Gi
    pods: "50"

Sizing-Empfehlungen

Richtig dimensionieren ist keine exakte Wissenschaft. Starten Sie konservativ und optimieren Sie basierend auf Monitoring-Daten.

Workload-TypCPU RequestCPU LimitMemory RequestMemory Limit
Web-API100-500m500m-1128-512Mi256Mi-1Gi
Datenbank500m-22-41-4Gi2-8Gi
Batch-Job100m-11-4256Mi-1Gi512Mi-2Gi
Cache (Redis)100-250m250-500m256Mi-2Gi512Mi-4Gi

Praktische Regeln:

  • Memory-Limit = 1.5-2x Memory-Request als Startpunkt
  • CPU-Limit weglassen ist eine valide Strategie - viele Teams setzen bewusst kein CPU-Limit um Throttling zu vermeiden (nur Request für Scheduling)
  • Memory-Limit immer setzen - ohne Limit kann ein Memory-Leak den gesamten Node destabilisieren
  • Nutzen Sie kubectl top pods und den Vertical Pod Autoscaler (VPA) im Recommend-Modus für datenbasiertes Sizing
# Aktuellen Verbrauch aller Pods im Namespace
kubectl top pods -n production --sort-by=memory

# Node-Auslastung prüfen
kubectl top nodes

# VPA-Empfehlungen abrufen (wenn installiert)
kubectl get vpa -n production -o yaml

FAQ

Soll ich CPU-Limits setzen oder weglassen?

Das ist umstritten. Ohne CPU-Limit vermeiden Sie Throttling und der Pod kann freie CPU-Kapazität nutzen. Das Risiko: Ein Pod kann temporär einen ganzen Node auslasten. Setzen Sie mindestens CPU-Requests und testen Sie beide Varianten.

Was passiert wenn Requests die Node-Kapazität übersteigen?

Der Scheduler platziert den Pod nicht auf dem Node - er bleibt Pending. Requests sind Garantien: Der Scheduler summiert alle Requests und vergleicht mit der Node-Kapazität (Allocatable).

Wie finde ich die richtigen Resource-Werte?

Starten Sie mit großzügigen Limits, beobachten Sie den tatsächlichen Verbrauch über 1-2 Wochen mit kubectl top oder Prometheus, und passen Sie dann an. Der VPA im Recommend-Modus schlägt automatisch passende Werte vor.

Warum wird mein Pod trotz freiem Memory OOMKilled?

Das Memory-Limit bezieht sich auf den einzelnen Container, nicht den Node. Auch Kernel-Memory und Cache zählen zum Verbrauch. Prüfen Sie mit kubectl describe pod den tatsächlichen Verbrauch aller Container im Pod, inklusive Sidecars.

Was ist der Unterschied zwischen LimitRange und ResourceQuota?

LimitRange setzt Grenzen pro einzelnem Container/Pod und definiert Defaults. ResourceQuota limitiert die Summe aller Ressourcen in einem Namespace. Beide ergänzen sich und sollten zusammen eingesetzt werden.

Kubernetes ohne DevOps-Overhead?

Wir betreiben Ihre Kubernetes-Cluster 24/7 – Sie fokussieren auf Ihr Kerngeschäft. Ab 4.000€/Monat, DSGVO-konform, mit deutschem Support.

24/7 SupportDeutsche RechenzentrenDSGVO-konform

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