Kubernetes Kosten senken: Woher sie kommen und was zuerst zu tun ist
Der Scheduler berücksichtigt Ressourcen-Requests bei der Platzierung von Pods auf Nodes. Node-Autoscaler berücksichtigen die Scheduling-Anforderungen, wenn sie zusätzliche Kapazität bereitstellen. Dieser Ratgeber zeigt die Reihenfolge, in der jeder Schritt auf dem vorherigen aufbaut.
Aktualisiert
Woher die Kosten kommen
Sie können für jeden Container CPU- und Memory-Requests sowie Limits festlegen. Laut Kubernetes-Dokumentation nutzt der kube-scheduler den Request, um den Node für einen Pod zu wählen. Der kubelet reserviert für diesen Container mindestens die Request-Menge.
Ein Request hält also Kapazität fest, auch wenn der Container sie nicht nutzt. Ein Container darf mehr als seinen Request verbrauchen, wenn der Node freie Kapazität hat. Der Scheduler zählt aber nur den Request.
Ein Limit ist eine Obergrenze. Der Kernel setzt sie durch. Erreicht ein Container sein CPU-Limit, wird er gedrosselt. Überschreitet er sein Memory-Limit, kann er beendet werden.
Darum beginnt Kostenarbeit bei den Requests. Hohe Requests können dazu führen, dass Kapazität ungenutzt bleibt. Bei niedrigen CPU-Requests kann ein Container unter Konkurrenz zu wenig CPU-Zeit erhalten. Niedrige Memory-Requests können zu Speicherdruck auf dem Node und zur Verdrängung von Pods beitragen. CPU-Limits verursachen Drosselung. Memory-Limits können OOM-Kills auslösen.
Schritt 1: Kosten pro Namespace und Team sichtbar machen
Was Sie nicht sehen, können Sie nicht senken. Beginnen Sie mit Labels an jedem Workload. Die Kubernetes-Dokumentation beschreibt Labels als Key/Value-Paare, mit denen Sie Ihre eigene Struktur, etwa Umgebungen oder Tiers, auf Objekte abbilden.
Wählen Sie wenige Labels, zum Beispiel team und app. Setzen Sie sie überall gleich. Namespaces pro Team oder pro Umgebung helfen ebenfalls.
OpenCost ist ein Open-Source-Projekt, das Kosten von Cloud-Infrastruktur und Containern misst und zuordnet. Es ist ein CNCF-Projekt auf der Stufe "Incubating". Die Allocation API hat den Parameter aggregate. Sie können nach Namespace, Controller, Pod, Container oder nach einem benannten Label gruppieren, etwa label:app. Gruppen lassen sich mit Komma kombinieren, zum Beispiel namespace,label:app.
Notieren Sie die größten Namespaces und Workloads. Das ist die Basislinie für alle weiteren Schritte.
Schritt 2: Requests mit dem Vertical Pod Autoscaler anpassen
Der Vertical Pod Autoscaler (VPA) berechnet empfohlene Requests aus der echten Nutzung. Sein Update-Modus "Off" ändert die Ressourcen von Pods nie. Der Recommender schreibt seine Empfehlungen trotzdem in das VPA-Objekt. Laut API-Referenz lässt sich das als "Dry Run" nutzen.
Installieren Sie zuerst eine zu Ihrem Cluster passende VPA-Version. Installieren Sie auch deren CRDs und Controller. Prüfen Sie, dass Metrics Server verfügbar ist. Das folgende Manifest setzt diese Installation voraus.
Legen Sie pro Deployment einen VPA mit updateMode "Off" an. Lassen Sie ihn den Workload über einen normalen Zeitraum beobachten, einschließlich Lastspitzen. Lesen Sie das Ergebnis dann mit kubectl describe vpa.
Vergleichen Sie die Empfehlung mit dem aktuellen Request. Ändern Sie den Request in Ihren eigenen Manifesten, im normalen Review, Workload für Workload. Die größten Workloads aus Schritt 1 kommen zuerst.
Der VPA kennt weitere Modi (Initial, Recreate, InPlaceOrRecreate, InPlace), die Pods für Sie ändern. Starten Sie mit "Off". Wechseln Sie erst dann, wenn Sie geprüft haben, was der Modus mit Ihrem Workload macht, denn manche Modi starten Pods neu.
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: my-app-vpa
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
updatePolicy:
updateMode: "Off" Schritt 3: Pods mit dem Horizontal Pod Autoscaler skalieren
Der Horizontal Pod Autoscaler (HPA) ändert die Zahl der Pods eines Deployments oder StatefulSets passend zur Nachfrage. Er fügt Pods hinzu, wenn die Last steigt, und entfernt sie, wenn sie sinkt, aber nie unter das gesetzte Minimum. Die Regelschleife läuft standardmäßig alle 15 Sekunden.
Für CPU- und Memory-Ressourcenmetriken nutzt der HPA die API metrics.k8s.io. Meist stellt Metrics Server sie bereit. Auslastungsziele vergleichen die Nutzung mit den Requests. Dafür müssen die entsprechenden Requests gesetzt sein. Ziele mit absoluten Werten verwenden die Messwerte direkt.
Der HPA kann auch benutzerdefinierte oder externe Metriken nutzen. Prüfen Sie Änderungen an Requests gemeinsam mit auslastungsbasierten HPA-Zielen.
Schritt 4: Die Nodes den Pods folgen lassen
Weniger oder kleinere Pods helfen nur, wenn auch die Nodes schrumpfen. Zwei Open-Source-Werkzeuge übernehmen das.
Der Cluster Autoscaler fügt Nodes hinzu, wenn Pods wegen fehlender Ressourcen nicht eingeplant werden können. Er entfernt einen Node, der nicht gebraucht wird: Der Node ist wenig ausgelastet, und seine wichtigen Pods können anderswo laufen. Standardmäßig heißt "wenig" hier: Die Requests der Pods auf dem Node liegen unter 50 % seiner allocatable Ressourcen. Ein Node muss mehr als 10 Minuten unnötig bleiben, bevor er entfernt wird.
Karpenter beobachtet Pods, die der Scheduler als nicht einplanbar markiert hat. Es erstellt dazu passende Nodes und entfernt Nodes, die nicht mehr gebraucht werden. Mit den Requirements eines NodePools begrenzen Sie Instanztypen, Zonen und Kapazitätstyp. Mit spec.limits begrenzen Sie die gesamten Ressourcen. Die aktuelle Karpenter-Dokumentation nennt die Consolidation-Policies WhenEmpty, Balanced und WhenEmptyOrUnderutilized. Prüfen Sie, welche Ihre installierte Version unterstützt. Scheduling-Anforderungen und Disruption-Regeln können eine Consolidation verhindern. consolidateAfter legt fest, wie lange Karpenter wartet, bevor es einen Node betrachtet.
Prüfen Sie die Disruption-Einstellungen gegen Ihre Workloads, bevor Sie Consolidation aktivieren, denn Consolidation kann laufende Pods verdrängen.
Schritt 5: Spot-Nodes und leerlaufende Umgebungen
Spot-Nodes (oder Preemptible-Nodes) nutzen freie Cloud-Kapazität. Die Cloud kann sie zurückfordern. AWS dokumentiert das für EC2 Spot Instances: Sie eignen sich für Arbeit, die unterbrochen werden darf, etwa Batch-Jobs und Hintergrundverarbeitung. EC2 stellt Unterbrechungsmeldungen nach dem Best-Effort-Prinzip bereit. Vor dem Stoppen oder Beenden bleiben normalerweise zwei Minuten. Der Ruhezustand beginnt sofort. Verlassen Sie sich nicht darauf, eine Warnung zu erhalten. Andere Clouds haben eigene Regeln, lesen Sie daher die Seite Ihres Anbieters.
Legen Sie nur unterbrechbare Arbeit auf Spot-Nodes. Datenbanken und Services mit nur einem Replica gehören auf reguläre Nodes. Erlauben Sie mehr als einen Instanztyp, damit der Scheduler Auswahl hat.
Leerlaufende Umgebungen sind der zweite Fall. Test-, Staging- und Preview-Umgebungen laufen oft den ganzen Tag ohne Nutzer. Skalieren Sie deren Deployments herunter, wenn niemand sie nutzt, mit kubectl scale und --replicas. Sind die Pods weg, kann der Node-Autoscaler aus Schritt 4 die Nodes entfernen. Löschen Sie Preview-Umgebungen, die nicht mehr gebraucht werden.
Vor und nach jeder Änderung messen
Ändern Sie immer nur eine Sache. Notieren Sie vor jeder Änderung die Kosten pro Namespace aus Schritt 1, die Pod-Requests und die Zahl der Nodes. Sehen Sie sich nach der Änderung dieselben Zahlen über einen vergleichbaren Zeitraum an.
Achten Sie auch auf Schäden: CPU-Throttling, OOM-Kills, Pods im Status Pending, Neustarts und langsame Antworten. Eine niedrigere Zahl ist kein Erfolg, wenn der Service schlechter wurde.
Zeigt sich eine Änderung nicht in den Zahlen, machen Sie sie rückgängig oder lassen Sie sie. Behalten Sie die Basislinie für die nächste Runde.
Quellen
Für diesen Ratgeber gelesene Seiten. Prüfen Sie diese auf Änderungen, bevor Sie handeln.
- Kubernetes docs: Resource Management for Pods and Containers
- Kubernetes docs: Labels and Selectors
- Kubernetes docs: Horizontal Pod Autoscaling
- Kubernetes docs: kubectl scale
- OpenCost: home page
- OpenCost docs: Allocation API
- CNCF: OpenCost project page
- Vertical Pod Autoscaler: installation
- Vertical Pod Autoscaler: quick start
- Vertical Pod Autoscaler: API reference
- Cluster Autoscaler: FAQ
- Karpenter docs: Overview
- Karpenter docs: Disruption
- Karpenter docs: NodePools
- AWS docs: Amazon EC2 Spot Instances
- AWS docs: Spot Instance interruptions
- AWS docs: Spot Instance interruption notices