Zum Inhalt springen
Alle Artikel

Kubernetes richtig dimensionieren: das Playbook, mit dem ein Cluster von 7 auf 4 Nodes kam

Die meisten Cluster laufen auf Schätzungen: Requests aus einem Tutorial kopiert, Node-Pools für einen Launch dimensioniert, der zwei Jahre zurückliegt, und eine Cloud-Rechnung, die niemand Zeile für Zeile erklären kann. Jeden Monat zahlen Sie für Kapazität, die leer steht, und jeden Monat fühlt es sich zu riskant an, etwas anzufassen. Right-Sizing behebt das, ohne etwas zu verändern, das Ihre Kunden sehen. Das ist genau die Reihenfolge, die ich nutze, mit Queries, Manifesten und Befehlen, und so kam ein Produktiv-Cluster von 7 auf 4 Nodes, ohne dass ein Kunde etwas merkte.

Aktualisiert 11 Min. Lesezeit

1. Eine Basis schaffen, der man trauen kann

Bevor sich etwas ändert, muss klar sein, was jeder Node-Pool kostet und wem er gehört. Die FinOps Foundation nennt das die Inform-Phase, und die Kostensäule des Azure Well-Architected Framework beginnt am selben Punkt: Was man nicht zuordnen kann, kann man nicht optimieren. In Azure zeigt Cost Management mit amortisierten Kosten den echten Preis pro Node-Pool, Reservierungen eingerechnet. Jeden Namespace mit Team und Produkt labeln, damit sich ein geteilter Cluster fair aufteilen lässt und jeder Euro einen Owner hat.

Dann pro Namespace drei Zahlen vergleichen: was angefordert ist, was tatsächlich genutzt wird und was die Nodes bereitstellen. Requests reserviert der Scheduler, und genau die bezahlen Sie; die Nutzung ist das, was die Container wirklich verbrauchen. In vielen Clustern liegen die Requests weit über der echten Nutzung, und genau diese Lücke bezahlen Sie. Die drei Zahlen pro Namespace in eine einfache Tabelle schreiben. Sie wird Ihr Vorher-Bild und später der Beweis, dass die Änderung gewirkt hat.

Tipp aus der Praxis

Amortisierte Kosten nutzen, nicht tatsächliche. Sonst sieht der Januar mit einer dort gekauften Reservierung teuer aus und der Rest des Jahres billig.

Der Right-Sizing-Kreislauf auf AKS: p95 messen, über Git ändern, Nodes folgen lassen, täglich berichten, zuletzt verpflichten.
Architektur des Right-Sizing-Kreislaufs auf AKS: Der verwaltete Prometheus von Azure Monitor misst die p95-Nutzung, FluxCD setzt neue Requests aus Git, der Cluster Autoscaler verkleinert den Node-Pool, Cost Management schickt einen Tagesreport, und Reservierungen werden für die kleinere Grösse gekauft.

2. p95 über echte Wochen messen

CPU und Speicher pro Container über zwei bis vier Wochen aus Prometheus ziehen, und sicherstellen, dass das Fenster einen Monatsabschluss, eine Kampagne oder den sonst stärksten Tag enthält. Auf AKS sammelt der von Azure Monitor verwaltete Prometheus-Dienst diese Metriken, ohne dass Sie Prometheus selbst betreiben. Nach dem 95. Perzentil dimensionieren, nicht nach dem Durchschnitt: Der Durchschnitt versteckt genau die Spitzen, die Throttling und Out-of-Memory-Kills auslösen.

CPU und Speicher unterschiedlich behandeln, denn Kubernetes tut das auch. CPU ist komprimierbar: Ein Container, der mehr als seinen Anteil will, läuft einfach langsamer. Speicher nicht: Ein Container über seinem Memory-Limit wird beendet, und der Pod startet neu. Beim Speicher deshalb zusätzlich das Maximum des Working Sets ansehen, nicht nur p95. Die Queries pro Container laufen lassen, das Ergebnis in eine Tabelle exportieren und nach der Lücke zwischen Request und p95 sortieren. Die grössten Lücken oben sind der Startpunkt.

promql
# p95 CPU (cores) per container over the last 14 days
quantile_over_time(0.95,
  sum by (namespace, pod, container) (
    rate(container_cpu_usage_seconds_total{container!="", container!="POD"}[5m])
  )[14d:5m]
)

# Peak working-set memory (bytes) per container over the last 14 days
max_over_time(
  container_memory_working_set_bytes{container!="", container!="POD"}[14d]
)

Tipp aus der Praxis

Speicher über lange Zeiträume nicht über Pods hinweg summieren. Bei Rollouts überlappen alte und neue Pods, und die Summe zeigt eine Nutzung, die es nie gab. Stattdessen das Maximum pro Container nehmen.

3. Requests und Limits aus den Daten ableiten

CPU-Requests auf etwa p95 plus 10 bis 20 Prozent Reserve setzen, Memory-Requests auf das gemessene Maximum plus einen ähnlichen Puffer. Memory-Limits gleich oder nahe am Request halten, damit ein Pod mit Speicherleck seine Nachbarn auf demselben Node nicht aushungert. Bei CPU verzichten viele Teams ganz auf das Limit und verlassen sich für faire Verteilung auf die Requests, das vermeidet Throttling bei latenzkritischen Diensten; ein CPU-Limit bleibt dort, wo harte Isolation nötig ist, etwa bei Batch-Jobs neben einer API.

Die Änderung wie jede andere Code-Änderung ausliefern. Die neuen Werte in die Helm-Values oder Kustomize-Overlays in Git schreiben und das GitOps-Tool, FluxCD oder Argo CD, ausrollen lassen. Namespace für Namespace vorgehen, mit internen Tools und Staging beginnen, und einen Tag lang Latenz, Fehlerraten und Neustarts beobachten, bevor der nächste dran ist. Sieht etwas komisch aus, ist der Rückweg ein Revert eines einzigen Commits. Dieser ruhige, umkehrbare Rhythmus sorgt dafür, dass die Leute dem Vorgehen vertrauen.

yaml
# Helm values for one service, derived from 14-day p95 and max
resources:
  requests:
    cpu: 250m        # p95 was ~210m
    memory: 512Mi    # max working set was ~430Mi
  limits:
    memory: 512Mi    # equal to the request: no noisy neighbours
    # no CPU limit: avoids throttling, requests keep sharing fair

Tipp aus der Praxis

Der Vertical Pod Autoscaler im Empfehlungsmodus (updateMode: Off) liefert pro Workload eine zweite Meinung, ohne einen einzigen Pod zu verändern.

Interaktiv

Wie viele Nodes brauchen Ihre Requests wirklich?

Schieben Sie die Regler auf Ihre Werte. Requests entscheiden, wo Pods Platz finden, zu grosse Requests kaufen also Nodes, die niemand nutzt.

Node-Grösse

5

Nodes heute

2

Nodes nach Right-Sizing (200m)

60%

weniger Node-Kapazität

Nur CPU, rund 90 % eines Nodes sind allokierbar, mindestens 2 Nodes für Verfügbarkeit. Speicher genauso prüfen, bevor ein Node wegfällt.

Alle Rechner und Checklisten

4. Node-Pools wählen, die zu den Pods passen

Mit ehrlichen Requests sieht man endlich die echte Form des Workloads, und diese Form bestimmt die Node-Grössen. Zu klein, und der Overhead von System-Pods, DaemonSets und der Kubelet-Reservierung frisst einen grossen Teil jeder Maschine. Zu gross, und ein halb leerer Node kostet viel, während der Autoscaler ihn nicht entfernen kann. Eine nützliche Prüfung: Wie viele typische Pods passen auf einen Node, und wie viel bleibt übrig? Die AKS-Kosten-Best-Practices empfehlen genau diese Übung, bevor man VM-Grössen wählt.

Die Arbeit danach trennen, wie sie sich verhält. Einen kleinen System-Node-Pool für Cluster-Komponenten, einen User-Pool für Produktion und einen Spot-Node-Pool mit Taint für unterbrechbare Arbeit wie Batch-Jobs, CI-Runner und Dev-Umgebungen. Spot-Kapazität kann kurzfristig zurückgeholt werden, also landen dort nur Workloads, die das vertragen. Auf AKS kann zudem Node Auto-Provisioning, das auf Karpenter basiert, die VM-Grössen anhand der wartenden Pods selbst wählen.

5. Den Autoscaler verkleinern lassen

Sind die Requests ehrlich und die Pools passend, packt der Scheduler die Pods dichter, und einige Nodes sind danach weitgehend leer. Der Cluster Autoscaler erkennt das und entfernt sie, solange die Pods darauf anderswo laufen können. Das ist der Moment, in dem die Rechnung tatsächlich sinkt, also sicherstellen, dass der Autoscaler handeln darf: ein sinnvolles Minimum und Maximum pro Pool und nichts, was Pods ohne Grund an bestimmte Nodes bindet.

Auf die klassischen Blocker achten. Pods mit lokalem Speicher, Pods ohne Controller und strenge PodDisruptionBudgets können verhindern, dass ein Node entfernt wird. Die Autoscaler-Logs zeigen, welcher Pod welchen Node blockiert hat, und diese wenigen Fälle zu beheben, bringt oft mehr als eine weitere Runde Request-Tuning. Ein paar Tage Geduld, und die Node-Anzahl pendelt sich auf einem neuen, tieferen Niveau ein.

Tipp aus der Praxis

Bewegt sich die Node-Anzahl nach einer Woche nicht, zuerst die Scale-down-Events des Autoscalers lesen. Fast immer nennen sie genau den einen Pod, der im Weg steht.

Workload Autoscaling, AKS Cost Management Series, Episode 3, Azure Kubernetes Service (AKS) (YouTube). Wird erst nach Ihrem Klick von YouTube geladen.

6. Nodes sicher entfernen

Manchmal will man schneller sein und Nodes selbst herausnehmen, etwa beim Wechsel auf eine neue VM-Grösse. Bevor Nodes wegfallen, prüfen, ob jeder wichtige Workload mindestens zwei Replikas, ein PodDisruptionBudget und sinnvolle Anti-Affinity hat, sonst kann ein Drain einen Dienst lahmlegen. Dann Kapazität Node für Node abbauen: cordon, drain, Fehlerraten und Latenz beobachten, warten, wiederholen.

Die alte Mindestanzahl an Nodes als Rückweg notieren und die Untergrenze des Autoscalers erst senken, wenn der Cluster eine Weile ruhig mit weniger Nodes gelaufen ist. In einem Produktiv-Cluster kamen wir so von 7 auf 4 Nodes, und kein Kunde hat etwas bemerkt. Die Arbeit selbst war unspektakulär, und genau darum geht es: kleine Schritte, klare Signale und ein Rückweg griffbereit.

bash
# Which workloads would block or break a drain?
kubectl get pdb -A

# One node at a time; check dashboards before the next one
kubectl cordon aks-userpool-12345678-vmss000003
kubectl drain aks-userpool-12345678-vmss000003 \
  --ignore-daemonsets --delete-emptydir-data --timeout=10m

# After a calm week on fewer nodes, lower the autoscaler floor
az aks nodepool update -g rg-platform --cluster-name aks-prod -n userpool \
  --update-cluster-autoscaler --min-count 2 --max-count 6

Tipp aus der Praxis

Während der Arbeitszeit drainen, mit Leuten vor den Dashboards, nicht um 3 Uhr nachts. Wenn sich etwas Unerwartetes bewegt, sollen Augen auf den Grafiken sein.

7. Sich erst auf die kleinere Grösse verpflichten

Erst jetzt Reservierungen oder Savings Plans kaufen, passend zum Cluster, der am Ende übrig ist, nicht zu dem vom Anfang. Die Kostensäulen der Well-Architected Frameworks von Azure und AWS sagen dasselbe mit anderen Worten: erst die Nutzung optimieren, dann den Preis, den man dafür zahlt. Die stabile Grundlast mit ein- oder dreijährigen Verpflichtungen abdecken, Spitzen bleiben Pay-as-you-go oder Spot.

Wer schon Reservierungen für VM-Grössen hält, die nicht mehr laufen, tauscht sie sofort um oder gibt sie zurück, wo der Anbieter das erlaubt, statt sie leer laufen zu lassen. Zuletzt verpflichten, nicht zuerst: In dem Projekt hinter diesem Playbook kamen die Reservierungen als letzter Schritt nach Right-Sizing und Aufräumen, und zusammen sanken die Azure-Kosten in fünf Wochen um 48 %.

8. Klein bleiben: eine Routine daraus machen

Cluster wachsen leise zurück: Ein neuer Dienst kopiert grosszügige Requests von einem alten, ein Lasttest lässt einen Node-Pool hochskaliert zurück, ein Debug-Flag verdoppelt die Logs. Die Operate-Phase der FinOps Foundation dreht sich genau darum: aus einem einmaligen Aufräumen eine Gewohnheit zu machen. Einen kurzen täglichen Kostenreport in den Team-Chat schicken, Budgets mit Prognose-Alerts setzen und pro Namespace eine ResourceQuota anlegen, damit Requests nicht unbemerkt wandern.

Dann den p95-Review jedes Quartal in den Kalender setzen. Wenn die Queries einmal existieren, dauert er etwa eine Stunde und findet meist ein, zwei Dienste, die seit dem letzten Mal gewachsen sind. Die Teams, die ihre Einsparungen behalten, haben nicht das cleverste Tooling; sie schauen jeden Tag auf die Zahlen und behandeln Kosten wie Latenz oder Fehler, als ein weiteres Signal einer gesunden Plattform.

Fazit

Right-Sizing ist ein Kreislauf, kein Projekt: p95 messen, einen Namespace ändern, beobachten, die Nodes folgen lassen, dann verpflichten. In dieser Reihenfolge bleiben die Einsparungen.

Weitere Artikel

    Kontakt aufnehmen

    Erzählen Sie mir von Ihrem Projekt, ich antworte innerhalb von 1–2 Werktagen.

    Dominik Heinrich
    Unternehmen
    MADO Consulting

    Weltweit verfügbar, remote. Vor Ort auf Anfrage, je nach Land.

    Ich antworte innerhalb von 1–2 Werktagen. Freie Termine: siehe Kalender

    Öffnet hier den Buchungskalender von Calendly. Beim Laden werden Daten an Calendly übertragen (siehe Impressum).