Man kann Pods planen, bis die Nodes voll sind. Das heißt nicht, dass man es tun sollte. Diese Lektion habe ich zweimal gelernt: einmal im Simulator, als wir die Tanks auf dem Papier leerflogen und trotzdem „landeten”, und Jahre später, als eine Marketing-E-Mail einen Cluster traf, der keine Luft mehr zum Atmen hatte. Das zweite Mal tat mehr weh, weil ich es besser hätte wissen müssen.

Reihen von Servern in einem Rechenzentrum

Foto von Tom Swinnen auf Pexels

Reserve ist keine Verschwendung

In der Flugplanung sind Treibstoffreserven kein Pessimismus. Sie sind der Puffer zwischen Plan und Realität. Wetter zwingt zum Ausweichen. Die Flugsicherung lässt einen warten. Ein Instrumentenanflug verbraucht mehr Treibstoff, als das Briefing vermuten ließ. Niemand prahlt damit, mit Reserve gelandet zu sein. Aber viele Berichte erwähnen Menschen, die sich genau diese Reserve gewünscht hätten.

Cluster verhalten sich ähnlich, nur mit anderen Einheiten. Surge beim Deploy bedeutet: Neue Pods starten, bevor alte beendet werden. Ein Node-Ausfall bedeutet: Workloads brauchen einen Platz zum Landen, ohne dass nachts hektisch neu gebaut wird. Spitzen im Datenverkehr bedeuten: Der Horizontal Pod Autoscaler braucht Reserve, bevor Scheduling zum Kampf um den letzten halb leeren Node wird. Storage füllt sich. IP-Pools erschöpfen sich. Das sind normale Ereignisse, keine schwarzen Schwäne.

Früher habe ich ungenutzte Kapazität als liegen gelassenes Geld gesehen. Finanzteams stimmen da oft zu. Bis zu einem Punkt ist das fair. Der Fehler ist, Effizienz nur im Ruhezustand zu messen. Produktion ruht nicht. Sie besteht aus Änderungen, Ausfällen und ganz normalen Dienstagen.

Wie Reserven am Boden aussehen

Ausweichreserven in der Luftfahrt haben Namen und Kategorien: Trip Fuel, Contingency, Alternate, Final Reserve, Extra Fuel, wenn der Captain es möchte. Betriebsteams übersetzen das in Richtlinien. In Kubernetes denke ich in Schichten:

Grundreserve auf Nodes. Nach normalem Scheduling sollte genug allocatable CPU und Memory übrig sein, dass der Verlust eines einzelnen Nodes nicht sofort einen Haufen Pending Pods erzeugt. „Normal” heißt hier: ehrliche Resource Requests, keine Fantasiezahlen von einer Folie vor zwei Jahren.

Deploy-Surge. Rolling Updates, maxSurge und Blue-Green-Umschaltungen setzen temporäre Duplikation voraus. Wenn der Cluster im Normalzustand bei achtundneunzig Prozent Allocation läuft, kann ein Routine-Deployment wie ein Ausfall aussehen.

Landebahn für Autoscaling. HPA braucht Nodes zum Landen oder Zeit, bis der Cluster Autoscaler Kapazität nachzieht. Wenn maximale Replikas mal Requests pro Pod das überschreiten, was die Flotte tragen kann, hat man einen Durchstart geplant, ohne dafür Luftraum zu lassen.

Abhängigkeiten mit eigenen Tanks. Datenbanken, Message Broker und API Rate Limits sind Treibstoff, den man nicht auf dem Node lagert. Ich habe perfekte Node-Reserve gesehen, während Postgres Connection Pools oder Drosselungen eines SaaS-Anbieters die eigentliche Grenze wurden.

Nichts davon ist glamourös. Es sind Tabellen, Dashboards und gelegentliche Diskussionen mit Menschen, die den Cluster centgenau „right-sized” haben wollen. Mir ist diese Diskussion lieber als die, in der wir erklären müssen, warum der Checkout während eines Sales nicht erreichbar war.

Signale, die ich wirklich beobachte

In Metriken ertrinkt man leicht. Ich halte die Liste kurz und orientiere sie an Entscheidungen, nicht an Eitelkeit.

Allocation versus Kapazität, nicht nur Nutzung. Kubernetes-Scheduling schaut auf Requests. Ein Node mit vierzig Prozent CPU-Nutzung kann trotzdem nicht mehr planbar sein, wenn Requests hoch angesetzt sind. Ich beobachte allocatable versus requested CPU und Memory pro Node und achte auf Ungleichgewichte in der Flotte.

Pending Pods und Scheduling Events. Ein Pending Pod ist nicht immer ein Notfall, aber eine steigende Anzahl ist wie eine Warnlampe für niedrigen Treibstoff. Ich lese Events: insufficient cpu, insufficient memory, volume topology, taints. Die Meldung ist meist deutlich, wenn man hinschaut.

HPA max replicas versus physische Grenze. Wenn der Autoscaler zehn Replikas will, der Cluster bei aktuellen Requests aber nur acht tragen kann, hat man eine Glasdecke gebaut. HPA versucht es, Scheduling lehnt ab, On-Call lernt.

Storage- und IP-Erschöpfung. Sie scheitern leise, bis sie laut scheitern. Wachstum bei PVC-Nutzung, Verbrauch von Subnet-IP-Adressen und Load-Balancer-Quotas gehören in denselben mentalen Ordner wie Treibstoff: langweilig, bis sie es nicht mehr sind.

Latenz und Error Budgets unter Lasttests. Einen einmaligen Gatling-Lauf behandle ich nicht als Evangelium für die Alltagsdimensionierung, aber als Stresstest für Reserven. Wenn Spitzenlast im Test Nodes ausreizt und die p99-Latenz schon ohne simulierte Node-Ausfälle steigt, wird normaler Datenverkehr plus ein schlechter Deploy noch unangenehmer.

Ich behaupte nicht, dass diese Liste vollständig ist. Zu ihr kehre ich zurück, wenn ich müde bin und jemand fragt: „Sind wir in Ordnung?”

Requests, Limits und ehrliche Mathematik

Zu niedrige Requests lassen Scheduling gesund aussehen, bis alle Pods gleichzeitig konkurrieren. Zu hohe Requests verschwenden Geld und verbergen echte Auslastung. Der Mittelweg ist langweilig: tatsächliche Nutzung über Zeit messen, Requests nahe am dauerhaften Bedarf setzen, Limits zum Schutz der Nachbarn verwenden und vierteljährlich oder nach großen Releases neu bewerten.

Ich habe jeden Fehler in diesem Satz gemacht. Requests aus einem Tutorial kopiert. Limits „zur Sicherheit” gleich Requests gesetzt und mich gewundert, warum CPU auf Nodes strandet. Requests weggelassen und gelernt, warum der Scheduler kein Freund ist.

Limits sind keine kostenlosen Gaspedale. Sie sind Leitplanken. Requests sind Versprechen, denen der Scheduler glaubt. Sie als Dekoration zu behandeln, ruiniert Kapazitätsplanung so wie Mindesttreibstoff auf einem Formular die Flugplanung ruiniert: Auf dem Papier funktioniert es, bis es das nicht mehr tut.

Für stark schwankende Workloads können Vertical Pod Autoscaler oder Rightsizing-Tools helfen, wenn man ihnen vertraut und Empfehlungen liest, statt sie blind automatisch anzuwenden. Ich habe VPA-Empfehlungen gesehen, die statistisch korrekt und für ein bestimmtes Release-Fenster trotzdem falsch waren. Automatisierung braucht weiterhin Urteilskraft.

Wie ich plane, ohne das Wetter vorherzusagen

Ich prognostiziere Datenverkehr nicht perfekt. Niemand, den ich kenne, tut das. Was ich kann: Szenarien definieren und Reserven daran knüpfen:

Einen Node verlieren. Lässt sich alles noch planen? Wenn nicht: Wie schnell können wir Kapazität nachziehen, und reicht das für das Service Level, das wir versprochen haben?

Routine-Deploy zur Spitzenzeit. Rollout-Mathematik rechnen: alte Replikas plus neue plus Surge-Einstellungen. Wenn die Summe die allocatable Resources überschreitet: Rollout ändern oder vor Freitag Reserve schaffen.

Sprung im Datenverkehr. Marketing-Kalender, Produktlaunches, Schulabende bei Consumer-Apps. Früh fragen, auch wenn die Antwort nur ein Schulterzucken ist. Ein Schulterzucken mit Datum ist besser als eine Überraschung.

Ausfall einer Region oder Zone. Bei Multi-Zone-Setups testen, ob die Vorstellung von Verteilung der Realität entspricht. Anti-Affinity-Regeln, die in YAML gut aussehen, scheitern trotzdem, wenn Image-Pull-Secrets, GPU-Anzahl oder PVC-Topologie an eine Zone binden.

Ich schreibe das in ein kurzes Dokument, das niemand liest, bis man es braucht. Das ist in Ordnung. Das Schreiben zwingt mich, Lücken zu bemerken.

Wenn „effiziente” Cluster Menschen schaden

Die schlimmsten Kapazitätsvorfälle, die ich miterlebt habe, waren nicht mysteriös. Sie waren das Ergebnis von Richtlinienentscheidungen.

Nodes dauerhaft mit hoher Allocation betreiben, um Geld zu sparen. Cluster Autoscaling abschalten, um Überraschungsrechnungen zu vermeiden. HPA max replicas auf „was wir hoffentlich brauchen” setzen statt auf das, was die Physik erlaubt. Stateful Services in der Surge-Mathematik wie stateless behandeln. Annehmen, dass Cloud-Provider-APIs immer schnell erfolgreich sind, gerade wenn man schon in Schwierigkeiten steckt.

Menschlich heißt das: On-Call-Engineers sollen „skalieren”, während das Dashboard zeigt, dass es nirgendwohin skaliert. Das ist eine grausame Lage. Reserven sind auch Freundlichkeit gegenüber der Person mit dem Pager.

Womit ich noch danebenliege

Ich behandle Zahlen aus Spitzenlasttests öfter als Alltagskapazität, als ich zugebe. Ein guter Test mit fünfzigtausend virtuellen Nutzern heißt nicht, dass wir diese Größe an einem ruhigen Morgen brauchen. Aber er sollte zeigen, wie viel Reserve wir wollen, bevor Marketing eine E-Mail verschickt. Diesen Schritt habe ich schon vergessen.

Ich unterschätze auch Grenzen außerhalb von Compute: API Gateways, DNS TTLs, Zertifikatsausstellung, Egress-NAT-Ports. Der Cluster hat Platz; der Weg nach draußen nicht.

Schließlich verwechsle ich Auslastung mit Gesundheit. Ausgelastete Nodes können gesund sein. Leere Nodes können falsch konfiguriert sein. Die Frage ist, ob das System das nächste gewöhnliche schlechte Ereignis verkraften kann, ohne dass jemand heldenhaft eingreifen muss.

Abschlussgedanke

Kapazitätsarbeit ist unglamourös. Treibstoffberechnungen auch. Beides schlägt die Erklärung, warum man nirgends landen konnte.

Ich lerne noch die cloud-nativen Versionen von Lektionen, die die Luftfahrt früh einübt: Pläne sind Fiktion, Reserven sind real, und das Ziel ist nicht, jeden Tropfen zu verbrauchen, sondern mit intakten Optionen anzukommen. Wer diese Woche einen Cluster dimensioniert, sollte vor dem Haken auf der Liste eine zusätzliche Frage stellen: Was passiert, wenn wir einen Node verlieren und gleichzeitig deployen? Wenn die ehrliche Antwort unangenehm ist, spricht darin die Reserve. Man sollte zuhören.