Kubernetes Rightsizing ist ein Vertrauensproblem, nicht nur ein Metrikproblem
Kubernetes Rightsizing funktioniert, wenn Plattformteams Ressourcendaten mit Rollout-Disziplin, klaren Fehlersignalen und einem Pfad verbinden, dem Anwendungsteams vertrauen.
Jede Kubernetes-Plattform erreicht irgendwann denselben unangenehmen Moment. Die Dashboards zeigen, dass viele Workloads deutlich mehr CPU und Memory reservieren, als sie meistens verbrauchen. Finance will die Cloud-Kosten senken. Plattformteams sehen verschwendete Node-Kapazität. Anwendungsteams hören etwas anderes: "Wir nehmen euch den Puffer weg, der Produktion bisher gerettet hat."
Genau deshalb scheitert Rightsizing so oft. Nicht weil Teams kein Prometheus, Grafana, Kubecost, VPA-Empfehlungen oder Tabellen haben. Es scheitert, weil Ressourcenänderungen wie eine Rechenaufgabe behandelt werden, obwohl sie eigentlich eine Vertrauensfrage sind. Ein Entwickler, der nachts wegen eines Restarts gepaged wurde, lässt sich nicht von einem einzelnen p95-Memory-Chart überzeugen.

Rightsizing funktioniert am besten, wenn Teams von lauten Auslastungssignalen zu stufenweisen, beobachtbaren Änderungen wechseln.
Dashboard
durchschnittliche Memory-Nutzung
Runtime
Exit Code letzte Woche
Team
Vertrauen in die Änderung
Die Optimierung, die wie eine Drohung klingt
Requests und Limits sind nicht nur Kostenregler. In Kubernetes beeinflussen Requests das Scheduling, während Limits durch kubelet und Kernel erzwungen werden. Die Kubernetes-Dokumentation zu Resource Management trennt das klar: Requests reservieren Kapazität für Placement-Entscheidungen, Memory Limits werden reaktiv über OOM Kills durchgesetzt. Das ist ein wichtiger Unterschied. Ein niedrigerer Memory Request ändert meistens Platzierung und Dichte. Ein niedrigeres Memory Limit kann ändern, ob ein Workload einen Spike überlebt.
Hier laufen viele Rightsizing-Projekte falsch. Sie starten mit einem Report: "Service A requested 20 GiB, nutzt aber meistens 8 GiB." Das kann stimmen und trotzdem unvollständig sein. Vielleicht hat der Service einen wöchentlichen Import-Job. Vielleicht wärmt der Start einen Cache auf. Vielleicht wächst ein JVM Heap nach einem Release anders. Vielleicht wurde die Anwendung vom Kernel gekillt, durch Node Pressure evicted, von einer Probe neu gestartet oder während eines Incidents manuell beendet. Das sind unterschiedliche Geschichten mit demselben oberflächlichen Symptom: Der Pod ist neu gestartet.
Memory-Form, nicht nur Memory-Durchschnitt
Die erste sinnvolle Haltung ist: Diskutiere nicht, ob Entwickler "overprovisionen". Frage, welche Evidenz eine kleinere Einstellung sicher wirken lässt. Meistens bedeutet das Restart-Historie, p95- und p99-Nutzung, Verhalten während Deployments, Queue Depth, Latenz, Garbage-Collection-Pausen, Node-Pressure-Events und einen Rollback-Pfad, der unter Stress langweilig genug ist.
Exit Code 137 ist keine Diagnose
Exit Code 137 wird in Flurgesprächen oft zu "OOMKilled" übersetzt. Manchmal stimmt das. Manchmal nicht. Ein Prozess kann aus mehreren Gründen SIGKILL bekommen, und Kubernetes-State sollte geprüft werden, bevor ein Team Ressourcenpolitik um eine falsche Diagnose herum baut. Schau auf lastState.terminated.reason, Events, Node Pressure, Probe Failures, Rollout-Zeitpunkt und Application Logs um denselben Timestamp.
kubectl describe pod checkout-api-7f8c9
kubectl get pod checkout-api-7f8c9 -o jsonpath='{.status.containerStatuses[*].lastState}'
kubectl get events --sort-by=.lastTimestamp
kubectl top pod checkout-api-7f8c9 --containers
Die zweite sinnvolle Haltung ist, Rightsizing stufenweise zu machen. Senke zuerst Requests, wenn die Daten das tragen, weil Requests Scheduling und Bin Packing beeinflussen. Sei vorsichtiger mit Limits, besonders Memory Limits, weil sie die Grenze definieren, an der der Kernel den Prozess beenden kann. Bei latenzsensitiven Services kann auch ein CPU Limit Throttling erzeugen, das wie ein Anwendungsproblem aussieht.
Autoscaling hilft, ersetzt aber kein Urteil
Der Horizontal Pod Autoscaler kann Deployments und StatefulSets anhand von CPU, Memory, Custom Metrics oder External Metrics skalieren. KEDA erweitert dieses Modell um eventgetriebene Trigger und übergibt Scaling-Entscheidungen für die 1-bis-N-Phase an HPA. Das sind gute Werkzeuge. Sie ersetzen nicht das Verständnis des Workloads.
Aktuelle Forschung zu predictive autoscaling for Node.js on Kubernetes beschreibt das Problem gut: CPU-basierter HPA kann Event-Loop-Sättigung übersehen, und reaktives Scaling kann erst ankommen, wenn die Latenz bereits kaputt ist. Das heißt nicht, dass jedes Team einen forschungsnahen Predictive Scaler braucht. Es heißt: "Wir haben HPA" ist keine vollständige Antwort, wenn das Nutzersymptom Queueing, Tail Latency oder langsamer Startup ist.
Vor dem Senken einer Memory-Einstellung in Produktion
- p95 und p99 über einen vollständigen Business-Zyklus prüfen, nicht nur gestern.
- Startup-Spikes, Batch-Fenster und steady-state Serving Traffic trennen.
- Bestätigen, ob frühere Restarts OOM Kills, Probe Failures, Evictions oder manuelle Aktionen waren.
- Ein Deployment oder einen Namespace canaryen, bevor der Default geändert wird.
- Rollback-Owner und die exakte Metrik festlegen, die Rollback auslöst.
Der Rightsizing-Pfad, dem ich vertraue, ist langweilig. Miss lange genug, um echtes Verhalten zu sehen. Schlage einen kleineren Request mit sichtbarem Sicherheitsabstand vor. Canarye ihn in einem vernünftigen Zeitfenster. Beobachte die Signale, die Application Owner interessieren, nicht nur Cluster-Auslastung. Wenn der Service gesund bleibt, wird die Änderung permanent und das Template aktualisiert. Wenn sie fehlschlägt, rollst du zurück und behältst die Evidenz.
resources:
requests:
cpu: "500m" # vorher: "1000m"
memory: "10Gi" # vorher: "20Gi"
limits:
memory: "16Gi" # Headroom behalten, während Vertrauen wächst
---
autoscaling:
minReplicas: 3
maxReplicas: 12
targetCPUUtilizationPercentage: 65
# Queue Depth, Latenz oder Event-Loop-Metriken ergänzen,
# wenn CPU nicht der Bottleneck ist.
Der Nutzen ist größer als eine niedrigere Cloud-Rechnung. Gutes Rightsizing schafft eine gemeinsame Sprache zwischen Plattform- und Anwendungsteams: was der Workload normalerweise braucht, was er unter Stress braucht, welche Signale Sicherheit beweisen und welche Ausnahmen echt sind. Das ist Platform Engineering. Nicht Pods in kleinere Boxen pressen, sondern sicherere Defaults möglich machen, ohne jede Änderung zum Streit zu machen.
Meine Meinung ist einfach: Ein Plattformteam, das Requests senkt, ohne Vertrauen aufzubauen, verschiebt Risiko nur von der Rechnung auf den Pager. Ein Plattformteam, das mit Evidenz, Canaries und Rollback-Disziplin rightsized, gibt Entwicklern einen Grund, schlankere Defaults zu akzeptieren. Das ist die Art Optimierung, mit der Produktionsteams wirklich leben können.