Wie kann man bei der Arbeit mit Kubernetes Cloud-Kosten sparen? Es gibt keine einzige richtige Lösung, aber dieser Artikel beschreibt mehrere Tools, die Ihnen helfen können, Ihre Ressourcen effektiver zu verwalten und Ihre Cloud-Computing-Kosten zu senken.
Ich habe diesen Artikel mit Blick auf Kubernetes für AWS geschrieben, aber er gilt (fast) genauso für andere Cloud-Anbieter. Ich gehe davon aus, dass für Ihre Cluster bereits Autoscaling konfiguriert ist (Cluster-Autoscaler). Durch die Entfernung von Ressourcen und die Verkleinerung Ihrer Bereitstellung können Sie nur dann Geld sparen, wenn dadurch auch Ihre Flotte an Worker-Knoten (EC2-Instanzen) reduziert wird.
Es ist großartig, in einem schnelllebigen Umfeld zu arbeiten. Wir wollen Technologieorganisationen beschleunigt. Eine schnellere Softwarebereitstellung bedeutet auch mehr PR-Bereitstellungen, Vorschauumgebungen, Prototypen und Analyselösungen. Alles wird auf Kubernetes bereitgestellt. Wer hat die Zeit, Testbereitstellungen manuell zu bereinigen? Es kann leicht passieren, dass man vergisst, ein einwöchiges Experiment zu löschen. Die Cloud-Rechnung wird am Ende steigen, weil wir vergessen haben, sie abzuschließen:
(Henning Jacobs:
Zhiza:
(Zitate) Corey Quinn:
Mythos: Ihr AWS-Konto hängt von der Anzahl Ihrer Benutzer ab.
Tatsache: Ihr AWS-Score ist eine Funktion der Anzahl Ihrer Ingenieure.
Ivan Kurnosov (als Antwort):
Echte Tatsache: Ihr AWS-Score ist eine Funktion der Anzahl der Dinge, die Sie vergessen haben zu deaktivieren/löschen.)
Kubernetes-Hausmeister (kube-janitor) hilft beim Aufräumen Ihres Clusters. Die Janitor-Konfiguration ist flexibel für den globalen und lokalen Einsatz:
Clusterweite Regeln können die maximale Lebensdauer (TTL) für PR-/Testbereitstellungen definieren.
Einzelne Ressourcen können mit janitor/ttl annotiert werden, um beispielsweise den Spike/Prototyp nach 7 Tagen automatisch zu entfernen.
Allgemeine Regeln sind in der YAML-Datei definiert. Sein Pfad wird durch den Parameter übergeben --rules-file in Kube-Hausmeister. Hier ist eine Beispielregel zum Entfernen aller Namespaces -pr- im Namen nach zwei Tagen:
Das folgende Beispiel regelt die Verwendung des Anwendungslabels auf den Deployment- und StatefulSet-Pods für alle neuen Deployments/StatefulSets im Jahr 2020, ermöglicht aber gleichzeitig die Durchführung von Tests ohne dieses Label für eine Woche:
- id: require-application-label
# удалить deployments и statefulsets без метки "application"
resources:
- deployments
- statefulsets
# см. http://jmespath.org/specification.html
jmespath: "!(spec.template.metadata.labels.application) && metadata.creationTimestamp > '2020-01-01'"
ttl: 7d
Führen Sie eine zeitlich begrenzte Demo für 30 Minuten auf einem Cluster aus, auf dem kube-janitor ausgeführt wird:
kubectl run nginx-demo --image=nginx
kubectl annotate deploy nginx-demo janitor/ttl=30m
Eine weitere Quelle steigender Kosten sind persistente Volumina (AWS EBS). Durch das Löschen eines Kubernetes StatefulSet werden seine persistenten Volumes (PVC – PersistentVolumeClaim) nicht gelöscht. Ungenutzte EBS-Volumina können leicht zu Kosten in Höhe von Hunderten von Dollar pro Monat führen. Kubernetes Janitor verfügt über eine Funktion zum Bereinigen nicht verwendeter PVCs. Diese Regel entfernt beispielsweise alle PVCs, die nicht von einem Modul gemountet sind und auf die nicht von einem StatefulSet oder CronJob verwiesen wird:
# удалить все PVC, которые не смонтированы и на которые не ссылаются StatefulSets
- id: remove-unused-pvcs
resources:
- persistentvolumeclaims
jmespath: "_context.pvc_is_not_mounted && _context.pvc_is_not_referenced"
ttl: 24h
Kubernetes Janitor kann Ihnen helfen, Ihren Cluster sauber zu halten und zu verhindern, dass sich die Cloud-Computing-Kosten langsam anhäufen. Anweisungen zur Bereitstellung und Konfiguration finden Sie hier README kube-janitor.
Reduzieren Sie die Skalierung während der arbeitsfreien Zeit
Test- und Stagingsysteme sind in der Regel nur während der Geschäftszeiten für den Betrieb erforderlich. Einige Produktionsanwendungen, wie z. B. Backoffice-/Verwaltungstools, erfordern ebenfalls nur eine begrenzte Verfügbarkeit und können über Nacht deaktiviert werden.
Kubernetes-Downscaler (kube-downscaler) ermöglicht Benutzern und Betreibern, das System außerhalb der Arbeitszeiten zu verkleinern. Bereitstellungen und StatefulSets können auf null Replikate skaliert werden. CronJobs können ausgesetzt werden. Kubernetes Downscaler wird für einen gesamten Cluster, einen oder mehrere Namespaces oder einzelne Ressourcen konfiguriert. Sie können entweder „Leerlaufzeit“ oder umgekehrt „Arbeitszeit“ einstellen. Um beispielsweise die Skalierung nachts und am Wochenende so weit wie möglich zu reduzieren:
image: hjacobs/kube-downscaler:20.4.3
args:
- --interval=30
# не отключать компоненты инфраструктуры
- --exclude-namespaces=kube-system,infra
# не отключать kube-downscaler, а также оставить Postgres Operator, чтобы исключенными БД можно было управлять
- --exclude-deployments=kube-downscaler,postgres-operator
- --default-uptime=Mon-Fri 08:00-20:00 Europe/Berlin
- --include-resources=deployments,statefulsets,stacks,cronjobs
- --deployment-time-annotation=deployment-time
Hier ist ein Diagramm zur Skalierung von Cluster-Worker-Knoten an Wochenenden:
Die Skalierung von ca. 13 auf 4 Worker-Knoten macht sicherlich einen spürbaren Unterschied in Ihrer AWS-Rechnung.
Was aber, wenn ich während der „Ausfallzeit“ des Clusters arbeiten muss? Bestimmte Bereitstellungen können dauerhaft von der Skalierung ausgeschlossen werden, indem die Annotation „downscaler/exclude: true“ hinzugefügt wird. Bereitstellungen können mithilfe der Downscaler/exclude-until-Annotation mit einem absoluten Zeitstempel im Format JJJJ-MM-TT HH:MM (UTC) vorübergehend ausgeschlossen werden. Bei Bedarf kann der gesamte Cluster verkleinert werden, indem ein Pod mit der Annotation bereitgestellt wird downscaler/force-uptime, zum Beispiel durch den Start von nginx blank:
kubectl run scale-up --image=nginx
kubectl annotate deploy scale-up janitor/ttl=1h # удалить развертывание через час
kubectl annotate pod $(kubectl get pod -l run=scale-up -o jsonpath="{.items[0].metadata.name}") downscaler/force-uptime=true
sehen README kube-downscaler, wenn Sie an Bereitstellungsanweisungen und zusätzlichen Optionen interessiert sind.
Verwenden Sie horizontale Autoskalierung
Viele Anwendungen/Dienste unterliegen einem dynamischen Lademuster: Manchmal sind ihre Module im Leerlauf, manchmal arbeiten sie mit voller Kapazität. Der Betrieb einer permanenten Pod-Flotte zur Bewältigung der maximalen Spitzenlast ist nicht wirtschaftlich. Kubernetes unterstützt die horizontale automatische Skalierung über eine Ressource hinweg HorizontalPodAutoscaler (HPA). Die CPU-Auslastung ist oft ein guter Indikator für die Skalierung:
Zalando hat eine Komponente erstellt, um benutzerdefinierte Metriken für die Skalierung einfach zu verbinden: Kube-Metrik-Adapter (kube-metrics-adapter) ist ein generischer Metrikadapter für Kubernetes, der benutzerdefinierte und externe Metriken für die horizontale automatische Skalierung von Pods sammeln und bereitstellen kann. Es unterstützt die Skalierung basierend auf Prometheus-Metriken, SQS-Warteschlangen und anderen Einstellungen. Um beispielsweise Ihre Bereitstellung auf eine benutzerdefinierte Metrik zu skalieren, die von der Anwendung selbst als JSON in /metrics dargestellt wird, verwenden Sie Folgendes:
Die Konfiguration der horizontalen Autoskalierung mit HPA sollte eine der Standardaktionen sein, um die Effizienz zustandsloser Dienste zu verbessern. Spotify hat eine Präsentation mit ihren Erfahrungen und Empfehlungen für HPA: Skalieren Sie Ihre Bereitstellungen, nicht Ihren Geldbeutel.
Reduzieren Sie die Überbuchung von Ressourcen
Kubernetes-Workloads ermitteln ihren CPU-/Speicherbedarf durch „Ressourcenanfragen“. CPU-Ressourcen werden in virtuellen Kernen oder häufiger in „Millicores“ gemessen, zum Beispiel bedeutet 500 m 50 % vCPU. Speicherressourcen werden in Bytes gemessen und es können gängige Suffixe verwendet werden, z. B. 500Mi, was 500 Megabyte bedeutet. Ressourcenanforderungen „sperren“ die Kapazität auf Worker-Knoten, was bedeutet, dass ein Pod mit einer 1000-m-CPU-Anfrage auf einem Knoten mit 4 vCPUs nur 3 vCPUs für andere Pods verfügbar lässt. [1]
Slack (Überschussreserve) ist die Differenz zwischen angeforderten Ressourcen und tatsächlicher Nutzung. Beispielsweise verfügt ein Pod, der 2 GiB Speicher anfordert, aber nur 200 MiB nutzt, über etwa 1,8 GiB „überschüssigen“ Speicher. Überschüsse kosten Geld. Man kann grob schätzen, dass 1 GiB redundanter Speicher etwa 10 US-Dollar pro Monat kostet. [2]
Kubernetes-Ressourcenbericht (kube-resource-report) zeigt überschüssige Reserven an und kann Ihnen dabei helfen, Einsparpotenziale zu ermitteln:
Kubernetes-Ressourcenbericht zeigt den nach Anwendung und Befehl aggregierten Überschuss an. Dadurch können Sie Orte finden, an denen der Ressourcenbedarf reduziert werden kann. Der generierte HTML-Bericht bietet lediglich eine Momentaufnahme der Ressourcennutzung. Sie sollten die CPU-/Speicherauslastung im Laufe der Zeit betrachten, um angemessene Ressourcenanforderungen zu ermitteln. Hier ist ein Grafana-Diagramm für einen „typischen“ CPU-lastigen Dienst: Alle Pods verbrauchen deutlich weniger als die drei angeforderten CPU-Kerne:
Durch die Reduzierung der CPU-Anforderung von 3000 m auf ~400 m werden Ressourcen für andere Arbeitslasten frei und der Cluster kann kleiner werden.
Aber wollen wir wirklich, dass Leute Werte in YAML-Dateien ändern? Nein, Maschinen können das viel besser! Kubernetes Vertikaler Pod-Autoscaler (VPA) macht genau das: Passt Ressourcenanforderungen und -beschränkungen entsprechend der Arbeitslast an. Hier ist ein Beispieldiagramm der Prometheus-CPU-Anfragen (dünne blaue Linie), die von VPA im Laufe der Zeit angepasst wurden:
Goldlöckchen von Fairwind ist ein Tool, das für jede Bereitstellung in einem Namespace eine VPA erstellt und dann eine VPA-Empfehlung auf seinem Dashboard anzeigt. Es kann Entwicklern dabei helfen, die richtigen CPU-/Speicheranforderungen für ihre Anwendungen festzulegen:
Nicht zuletzt können die AWS EC2-Kosten durch die Verwendung von Spot-Instanzen als Kubernetes-Worker-Knoten gesenkt werden [3]. Spot-Instanzen sind mit einem Rabatt von bis zu 90 % im Vergleich zu On-Demand-Preisen erhältlich. Das Ausführen von Kubernetes auf EC2 Spot ist eine gute Kombination: Sie müssen mehrere verschiedene Instanztypen für eine höhere Verfügbarkeit angeben, was bedeutet, dass Sie einen größeren Knoten zum gleichen oder einem niedrigeren Preis erhalten und die erhöhte Kapazität von containerisierten Kubernetes-Workloads genutzt werden kann.
Wie führe ich Kubernetes auf EC2 Spot aus? Es gibt mehrere Möglichkeiten: Verwenden Sie einen Drittanbieterdienst wie SpotInst (jetzt „Spot“ genannt, fragen Sie mich nicht warum) oder fügen Sie einfach eine Spot AutoScalingGroup (ASG) zu Ihrem Cluster hinzu. Hier ist beispielsweise ein CloudFormation-Snippet für eine „kapazitätsoptimierte“ Spot-ASG mit mehreren Instanztypen:
Was sind Ihre Best Practices, um Cloud-Kosten auf Kubernetes zu sparen? Bitte lassen Sie es mich wissen unter Twitter (@try_exclusive_).
[1] Tatsächlich bleiben weniger als 3 vCPUs nutzbar, da der Durchsatz des Knotens durch reservierte Systemressourcen verringert wird. Kubernetes unterscheidet zwischen physischer Knotenkapazität und „bereitgestellten“ Ressourcen (Knoten zuweisbar).
[2] Berechnungsbeispiel: Eine m5.large-Instanz mit 8 GiB Speicher kostet ~84 $ pro Monat (eu-central-1, On-Demand), d. h. Das Blockieren von 1/8 Knoten kostet ungefähr 10 $/Monat.
[3] Es gibt viele weitere Möglichkeiten, Ihre EC2-Rechnung zu reduzieren, wie z. B. Reserved Instances, Savings Plan usw. – ich werde diese Themen hier nicht behandeln, aber Sie sollten sich auf jeden Fall damit befassen!