Veröffentlicht am

Kubernetes Pod Evicted: Ursachen verstehen und verhindern

Teilen:
Authors

Kubernetes Pod Evicted: Ursachen verstehen und verhindern

TL;DR

Evicted Pods entstehen durch Resource Pressure auf dem Node -- zu wenig Memory, Disk oder Ephemeral Storage. Prüfen Sie kubectl describe node auf Conditions wie MemoryPressure oder DiskPressure. Verhindern Sie Evictions durch korrekte Resource Requests, LimitRanges und Pod Priority Classes.


127 Pods evicted über Nacht -- was ist passiert?

So oder ähnlich beginnt der Montag, wenn ein Node unter Resource Pressure gerät. Kubernetes schützt den Node, indem es Pods "evicted" -- zwangsweise beendet und vom Node entfernt. Das ist kein Bug, sondern ein Schutzmechanismus. Aber es hilft nicht, wenn Ihre Produktion betroffen ist.

# Evicted Pods finden
kubectl get pods -A --field-selector=status.phase=Failed | grep Evicted

# Details eines evicted Pods anzeigen
kubectl describe pod <evicted-pod-name> -n <namespace>
# Suchen Sie nach "Status: Failed" und "Reason: Evicted"

Die 3 Eviction-Trigger

Kubernetes überwacht drei Ressourcen auf jedem Node. Wird ein Schwellenwert unterschritten, beginnt die Eviction:

ConditionSchwellenwert (Default)Eviction-Signal
MemoryPressure< 100Mi verfügbarmemory.available
DiskPressure< 10% oder < 15% (imagefs)nodefs.available
PIDPressureKernel PID-Limit nahepid.available
# Node Conditions prüfen
kubectl describe node <node-name> | grep -A 5 Conditions

# Aktuelle Resource-Nutzung des Nodes
kubectl top node <node-name>

Wer wird zuerst evicted?

Kubernetes evicted Pods in dieser Reihenfolge:

  1. BestEffort Pods (keine Requests/Limits definiert) -- werden zuerst evicted
  2. Burstable Pods (Requests < Limits oder nur teilweise definiert)
  3. Guaranteed Pods (Requests = Limits für CPU und Memory) -- werden zuletzt evicted

Innerhalb derselben QoS-Klasse entscheidet die tatsächliche Nutzung relativ zu den Requests. Pods, die ihre Requests am stärksten überschreiten, fliegen zuerst.

# QoS-Klasse eines Pods prüfen
kubectl get pod <pod-name> -o jsonpath='{.status.qosClass}'

Ursache 1: Memory Pressure

Die häufigste Ursache. Ein oder mehrere Pods verbrauchen mehr Memory als angefordert, der Node läuft voll.

# Memory-Nutzung aller Pods auf einem Node
kubectl get pods --field-selector spec.nodeName=<node-name> -o wide -A
kubectl top pods -A --sort-by=memory | head -20

Fix: Resource Requests und Limits setzen

spec:
  containers:
  - name: app
    resources:
      requests:
        memory: "256Mi"    # Kubernetes reserviert diesen Wert
      limits:
        memory: "512Mi"    # Container wird OOMKilled bei Überschreitung

Die Faustregel: requests auf den durchschnittlichen Verbrauch, limits auf das 1,5- bis 2-fache der Requests.

Ursache 2: Ephemeral Storage Eviction

Diese Ursache wird oft übersehen. Container-Logs, temporäre Dateien und beschreibbare Layer verbrauchen Ephemeral Storage. Ohne Limits kann ein einzelner Pod den Node-Speicher füllen.

# Ephemeral Storage Nutzung prüfen
kubectl describe node <node-name> | grep -A 3 "Allocated resources"

# Welche Pods verbrauchen Ephemeral Storage?
kubectl get pods -o json -A | jq '.items[] | select(.spec.containers[].resources.requests["ephemeral-storage"] != null) | .metadata.name'

Fix: Ephemeral Storage Limits setzen

spec:
  containers:
  - name: app
    resources:
      requests:
        ephemeral-storage: "1Gi"
      limits:
        ephemeral-storage: "2Gi"   # Pod wird evicted bei Überschreitung

Typische Ephemeral-Storage-Verbraucher:

  • Container-Logs, die nicht rotiert werden
  • /tmp-Dateien in Containern
  • Writable Container Layers (z.B. bei apt install im laufenden Container)

Ursache 3: Disk Pressure (nodefs)

Der Node selbst hat zu wenig Disk Space. Oft verursacht durch Container Images, die den Image-Cache füllen.

# Disk-Nutzung auf dem Node prüfen (per SSH oder Debug-Container)
kubectl debug node/<node-name> -it --image=busybox -- df -h

# Image-Cache-Größe prüfen
kubectl debug node/<node-name> -it --image=busybox -- du -sh /var/lib/containerd

Fix: Alte Images bereinigen, Log-Rotation konfigurieren oder Node-Disk vergrößern.

Evictions verhindern: Best Practices

1. LimitRange im Namespace setzen

Erzwingt, dass jeder Pod Requests und Limits hat:

apiVersion: v1
kind: LimitRange
metadata:
  name: default-limits
  namespace: production
spec:
  limits:
  - default:
      memory: "256Mi"
      cpu: "250m"
    defaultRequest:
      memory: "128Mi"
      cpu: "100m"
    type: Container

2. PriorityClasses für kritische Pods

Pods mit höherer Priority werden bei Evictions bevorzugt behalten:

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: critical-production
value: 1000000
globalDefault: false
description: "Für produktionskritische Pods"

3. Pod Disruption Budgets

PDBs schützen nicht direkt vor Node-Pressure-Evictions, aber vor freiwilligen Disruptions (Upgrades, Drain):

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: app-pdb
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: my-app

Aufräumen: Evicted Pods löschen

Evicted Pods bleiben als Failed-Pods im Cluster. Sie verbrauchen keine Ressourcen, aber sie stören die Übersicht:

# Alle evicted Pods in allen Namespaces löschen
kubectl get pods -A --field-selector=status.phase=Failed -o json | \
  jq -r '.items[] | select(.status.reason=="Evicted") | "\(.metadata.namespace) \(.metadata.name)"' | \
  xargs -n2 kubectl delete pod -n

FAQ

Werden evicted Pods automatisch neu gestartet?

Ja, wenn sie von einem Controller (Deployment, StatefulSet, DaemonSet) verwaltet werden. Einzelne Pods ohne Controller sind nach der Eviction weg. Der neue Pod wird auf einem Node mit genügend Ressourcen gescheduled.

Kann ich die Eviction-Schwellenwerte anpassen?

Ja, über die Kubelet-Konfiguration mit --eviction-hard und --eviction-soft. Zum Beispiel: --eviction-hard=memory.available\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\<200Mi erhöht den Memory-Schwellenwert auf 200Mi. In Managed-Kubernetes-Clustern (EKS, AKS, GKE) haben Sie darauf meist keinen Zugriff.

Was ist der Unterschied zwischen Eviction und OOMKilled?

OOMKilled wird vom Linux Kernel ausgelöst, wenn ein einzelner Container sein Memory-Limit überschreitet. Eviction wird vom Kubelet ausgelöst, wenn der gesamte Node unter Memory Pressure steht. Bei OOMKilled wird nur der Container neu gestartet, bei Eviction wird der gesamte Pod vom Node entfernt.

Warum werden meine Guaranteed-Pods trotzdem evicted?

Guaranteed-Pods werden nur evicted, wenn Node-System-Prozesse (kubelet, containerd, OS) nicht mehr genügend Ressourcen haben. Das ist selten, kann aber bei sehr knapp dimensionierten Nodes passieren. Prüfen Sie, ob system-reserved und kube-reserved in der Kubelet-Konfiguration korrekt gesetzt sind.


Wenn Ihre Pods nach der Eviction in CrashLoopBackOff landen, hilft unser CrashLoopBackOff Troubleshooting Guide bei der weiteren Diagnose.

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