Die Übersetzung des Artikels wurde im Vorfeld des Starts des Kurses vorbereitet .

Wie kann man bei Cloud-Kosten sparen, wenn man mit Kubernetes arbeitet? Es gibt nicht die eine richtige Lösung, aber in diesem Artikel werden mehrere Tools beschrieben, die Ihnen helfen, Ihre Ressourcen effizienter zu verwalten und die Ausgaben für Cloud-Computing zu senken.
Ich habe diesen Artikel mit Blick auf Kubernetes für AWS geschrieben, aber er wird (fast) genauso auch für andere Cloud-Anbieter anwendbar sein. Ich gehe davon aus, dass Ihr Cluster( ) bereits eine automatische Skalierung konfiguriert hat (). Das Entfernen von Ressourcen und das Reduzieren des Deployments wird nur dann Einsparungen bringen, wenn es auch Ihre Anzahl an Worker-Nodes (EC2-Instanzen) reduziert.
In diesem Artikel werden folgende Themen behandelt:
- Bereinigung ungenutzter Ressourcen ()
- Reduzierung des Scale in der Nebensaison ()
- Verwendung von Horizontal Pod Autoscaling (HPA),
- Reduzierung der Überbuchung von Ressourcen (, VPA)
- Nutzung von Spot-Instanzen
Bereinigung ungenutzter Ressourcen
In einer sich schnell ändernden Umgebung zu arbeiten, ist großartig. Wir möchten, dass technische Organisationen . Eine schnellere Softwarebereitstellung bedeutet auch eine größere Anzahl von PR-Deployments, Staging-Umgebungen, Prototypen und Analysetools. Alles wird auf Kubernetes bereitgestellt. Wer hat die Zeit, Testdeployments manuell zu bereinigen? Es ist leicht, zu vergessen, Experimente von vor einer Woche zu löschen. Die Cloud-Rechnung wird am Ende steigen, weil wir vergessen haben, Folgendes zu schließen:

(Henning Jacobs:
Realität:
(Zitat) Corey Quinn:
Mythos: Ihre AWS-Rechnung ist eine Funktion der Anzahl Ihrer Benutzer.
Fakt: Ihre AWS-Rechnung ist eine Funktion der Anzahl Ihrer Ingenieure.
Ivan Kurnosov (als Antwort):
Tatsächlicher Fakt: Ihre AWS-Rechnung ist eine Funktion der Anzahl von Dingen, die Sie vergessen haben, auszuschalten/zu löschen.)
(kube-janitor) hilft Ihnen bei der Bereinigung Ihres Clusters. Die Konfiguration des Janitors ist sowohl für die globale als auch für die lokale Nutzung flexibel:
- Allgemeine Regeln für den gesamten Cluster können die maximale Lebensdauer (TTL — Time-to-Live) für PR/Testdeployments festlegen.
- Einzelne Ressourcen können mit janitor/ttl annotiert werden, um beispielsweise Spike/Prototypen nach 7 Tagen automatisch zu löschen.
Die allgemeinen Regeln werden in der YAML-Datei festgelegt. Ihr Pfad wird über den Parameter --rules-file in kube-janitor übergeben. Hier ist ein Beispiel für eine Regel, um alle Namespaces mit -pr- im Namen nach zwei Tagen zu löschen:
- id: cleanup-resources-from-pull-requests
resources:
- namespaces
jmespath: "contains(metadata.name, '-pr-')"
ttl: 2dDas nächste Beispiel regelt die Verwendung des Labels application auf Deployment- und StatefulSet-Pods für alle neuen Deployments/StatefulSets im Jahr 2020, erlaubt jedoch gleichzeitig das Ausführen von Tests ohne dieses Label für eine Woche:
- id: require-application-label
# löschen von deployments und statefulsets ohne das Label "application"
resources:
- deployments
- statefulsets
# siehe http://jmespath.org/specification.html
jmespath: "!(spec.template.metadata.labels.application) && metadata.creationTimestamp > '2020-01-01'"
ttl: 7dStarten Sie eine zeitlich begrenzte Demo für 30 Minuten in einem Cluster, in dem kube-janitor läuft:
kubectl run nginx-demo --image=nginx
kubectl annotate deploy nginx-demo janitor/ttl=30mEine weitere Quelle für steigende Kosten sind persistente Volumes (AWS EBS). Beim Löschen eines Kubernetes StatefulSets werden dessen persistente Volumes (PVC — PersistentVolumeClaim) nicht gelöscht. Unbenutzte EBS-Volumes können schnell zu Kosten in Höhe von Hunderten von Dollar pro Monat führen. Kubernetes Janitor hat eine Funktion zur Bereinigung nicht verwendeter PVC. Zum Beispiel löscht diese Regel alle PVC, die nicht vom Modul gemountet sind und auf die das StatefulSet oder CronJob nicht verweist:
# удалить все PVC, которые не смонтированы и на которые не ссылаются StatefulSets
- id: remove-unused-pvcs
resources:
- persistentvolumeclaims
jmespath: "_context.pvc_is_not_mounted && _context.pvc_is_not_referenced"
ttl: 24hKubernetes Janitor kann Ihnen helfen, Ihren Cluster 'sauber' zu halten und langsam anfallende Kosten für Cloud-Computing zu vermeiden. Für Anleitungen zur Bereitstellung und Konfiguration folgen Sie in .
Skalierung in der Nebensaison reduzieren
Test- und Zwischenablagesysteme sind normalerweise nur während der Arbeitszeit erforderlich. Einige Produktionsanwendungen, wie Backoffice/Administrationswerkzeuge, erfordern ebenfalls nur eingeschränkte Verfügbarkeit und können nachts abgeschaltet werden.
(kube-downscaler) ermöglicht es Benutzern und Betreibern, das System außerhalb der Arbeitszeiten zu verringern. Deployments und StatefulSets können auf null Replikate skaliert werden. CronJobs können pausiert werden. Kubernetes Downscaler wird für den gesamten Cluster, einen oder mehrere Namespaces oder einzelne Ressourcen konfiguriert. Man kann entweder „Downtime“ oder umgekehrt „Uptime“ einstellen. Zum Beispiel, um das Scaling über Nacht und an Wochenenden maximal zu reduzieren:
image: hjacobs/kube-downscaler:20.4.3
args:
- --interval=30
# Infrastrukturkomponenten nicht abschalten
- --exclude-namespaces=kube-system,infra
# kube-downscaler nicht abschalten und Postgres Operator belassen, damit ausgelassene DBs verwaltet werden können
- --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-timeHier ist das Diagramm für das Scaling von Arbeitsknoten im Cluster an Wochenenden:

Das Reduzieren von ~13 auf 4 Arbeitsknoten macht definitiv einen erheblichen Unterschied in der AWS-Rechnung.
Aber was, wenn ich während der „Downtime“ des Clusters arbeiten muss? Bestimmte Deployments können für das Scaling dauerhaft ausgeschlossen werden, indem man die Annotation downscaler/exclude: true hinzufügt. Deployments können vorübergehend mit der Annotation downscaler/exclude-until mit einem absoluten Zeitstempel im Format JJJJ-MM-TT HH:MM (UTC) ausgeschlossen werden. Bei Bedarf kann der gesamte Cluster zurück skaliert werden, indem man einen Pod mit der Annotation downscaler/force-uptime, zum Beispiel durch Ausführen einer nginx-Vorlage:
kubectl run scale-up --image=nginx
kubectl annotate deploy scale-up janitor/ttl=1h # Deployment nach einer Stunde löschen
kubectl annotate pod $(kubectl get pod -l run=scale-up -o jsonpath="{.items[0].metadata.name}") downscaler/force-uptime=trueSiehe , wenn Sie an der Bereitstellungsanleitung und weiteren Optionen interessiert sind.
Nutzen Sie horizontale Autoskalierung
Viele Anwendungen/Dienste haben es mit einer dynamischen Lastenverteilung zu tun: Manchmal sind ihre Pods inaktiv, manchmal laufen sie mit voller Leistung. Ein ständiger Pool von Pods, um mit dem maximalen Spitzenbedarf umzugehen, ist unwirtschaftlich. Kubernetes unterstützt horizontale automatische Skalierung über die Ressource (HPA). Die CPU-Nutzung ist oft ein guter Indikator für das Scaling:
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: my-app
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
averageUtilization: 100
type: UtilizationZalando hat eine Komponente erstellt, um benutzerdefinierte Metriken für das Auto-Scaling einfach zu integrieren: (kube-metrics-adapter) ist ein universeller Metrikadapter für Kubernetes, der benutzerdefinierte und externe Metriken für das horizontale Autoscaling von Pods sammeln und bereitstellen kann. Er unterstützt das Scaling auf Basis von Prometheus-Metriken, SQS-Warteschlangen und anderen Konfigurationen. Um beispielsweise ein Deployment auf der Grundlage einer benutzerdefinierten Metrik zu skalieren, die von der Anwendung selbst im JSON-Format unter /metrics bereitgestellt wird, verwenden Sie:
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: myapp-hpa
annotations:
# metric-config.../
metric-config.pods.requests-per-second.json-path/json-key: "$.http_server.rps"
metric-config.pods.requests-per-second.json-path/path: /metrics
metric-config.pods.requests-per-second.json-path/port: "9090"
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
minReplicas: 1
maxReplicas: 10
metrics:
- type: Pods
pods:
metric:
name: requests-per-second
target:
averageValue: 1k
type: AverageValueDie Konfiguration des horizontalen Autoscaling mit HPA sollte eine der Standardeinstellungen sein, um die Effizienz für zustandslose Dienste zu steigern. Spotify hat eine Präsentation über ihre Erfahrungen und Empfehlungen zum HPA: .
Reduzierung der übermäßigen Ressourcennutzung
Kubernetes-Workloads definieren ihren Bedarf an CPU/Speicher durch "Ressourcenanforderungen". CPU-Ressourcen werden in virtuellen Kernen oder häufiger in „Millicores“ (millicores) gemessen, zum Beispiel es bedeutet 500m, was 50% vCPU entspricht. Speicherressourcen werden in Bytes gemessen, und es können übliche Suffixe verwendet werden, zum Beispiel 500Mi, was 500 Megabytes entspricht. Ressourcenanforderungen "blockieren" Kapazitäten auf den Worker-Knoten, das heißt, ein Modul mit einer CPU-Anforderung von 1000m auf einem Knoten mit 4 virtuellen CPUs lässt nur 3 virtuelle CPUs für andere Module verfügbar.
Slack (Überangebot der Reserven) — das ist der Unterschied zwischen den angeforderten Ressourcen und der tatsächlichen Nutzung. Zum Beispiel hat ein Pod, der 2 GiB Arbeitsspeicher anfordert, aber nur 200 MiB verwendet, ~ 1,8 GiB „überschüssigen“ Speicher. Überschuss kostet Geld. Man kann grob schätzen, dass 1 GiB überschüssigen Speichers ~ 10 Dollar pro Monat kostet.
(kube-resource-report) zeigt übermäßige Reserven an und kann Ihnen helfen, Einsparpotenziale zu identifizieren:

zeigt den Überschuss, aggregiert nach Anwendung und Team. Dies hilft, Stellen zu finden, an denen die Ressourcennachfragen gesenkt werden können. Der generierte HTML-Bericht liefert nur einen Snapshot der Ressourcennutzung. Sie sollten die CPU-/Speicherauslastung über die Zeit betrachten, um angemessene Ressourcennachfragen zu bestimmen. Hier ist ein Grafana-Diagramm für einen „typischen“ Dienst mit hoher CPU-Belastung: Alle Pods verwenden deutlich weniger als 3 angeforderte CPU-Kerne:

Die Senkung der CPU-Nachfrage von 3000m auf ~400m gibt Ressourcen für andere Arbeitslasten frei und ermöglicht es, das Cluster zu verkleinern.
„Die durchschnittliche CPU-Nutzung von EC2-Instanzen schwankt oft im Bereich von einstelligen Prozentzahlen“, - . Während für EC2 , ist das Ändern einiger Ressourcennachfragen in der YAML-Datei einfach und kann erhebliche Einsparungen bringen.
Aber wollen wir wirklich, dass die Leute Werte in YAML-Dateien ändern? Nein, Maschinen können das viel besser! Kubernetes (VPA) kümmert sich genau darum: es passt Ressourcennachfragen und -beschränkungen an die Arbeitslast an. Hier ist ein Beispiel für die im Zeitverlauf angepassten CPU-Anforderungen von Prometheus (dünne blaue Linie):

für Infrastrukturkomponenten. Auch nicht-kritische Anwendungen können VPA nutzen.
von Fairwind ist ein Werkzeug, das VPA für jedes Deployment im Namespace erstellt und dann die VPA-Empfehlung auf seinem Dashboard anzeigt. Es kann Entwicklern helfen, die richtigen CPU-/Speichereinstellungen für ihre Anwendungen festzulegen:

Ich habe 2019 einen kleinen geschrieben und kürzlich wurde das Thema VPA in der .
Verwendung von EC2 Spot-Instanzen
Schließlich, ebenso wichtig, können die Kosten für AWS EC2 gesenkt werden, indem Spot-Instanzen als Arbeitsknoten in Kubernetes verwendet werden. . Spot-Instanzen sind mit Rabatten von bis zu 90 % im Vergleich zu On-Demand-Preisen erhältlich. Kubernetes auf EC2 Spot zu betreiben ist eine gute Kombination: Sie müssen mehrere verschiedene Instanztypen angeben, um eine höhere Verfügbarkeit zu gewährleisten, das heißt, Sie können einen größeren Knoten zum gleichen oder geringeren Preis erhalten, und die erhöhte Kapazität kann von containerisierten Kubernetes-Arbeitslasten genutzt werden.
Wie startet man Kubernetes auf EC2 Spot? Es gibt mehrere Optionen: einen Drittanbieterdienst wie SpotInst (jetzt heißt er „Spot“, fragen Sie mich nicht warum) zu nutzen oder einfach eine Spot AutoScalingGroup (ASG) zu Ihrem Cluster hinzuzufügen. Zum Beispiel hier ein CloudFormation-Snippet für eine „kapazitätsoptimierte“ Spot-ASG mit mehreren Instanztypen:
MySpotAutoScalingGroup:
Properties:
HealthCheckGracePeriod: 300
HealthCheckType: EC2
MixedInstancesPolicy:
InstancesDistribution:
OnDemandPercentageAboveBaseCapacity: 0
SpotAllocationStrategy: capacity-optimized
LaunchTemplate:
LaunchTemplateSpecification:
LaunchTemplateId: !Ref LaunchTemplate
Version: !GetAtt LaunchTemplate.LatestVersionNumber
Overrides:
- InstanceType: "m4.2xlarge"
- InstanceType: "m4.4xlarge"
- InstanceType: "m5.2xlarge"
- InstanceType: "m5.4xlarge"
- InstanceType: "r4.2xlarge"
- InstanceType: "r4.4xlarge"
LaunchTemplate:
LaunchTemplateId: !Ref LaunchTemplate
Version: !GetAtt LaunchTemplate.LatestVersionNumber
MinSize: 0
MaxSize: 100
Tags:
- Key: k8s.io/cluster-autoscaler/node-template/label/aws.amazon.com/spot
PropagateAtLaunch: true
Value: "true"Einige Hinweise zur Verwendung von Spot mit Kubernetes:
- Sie müssen Spot-Abschaltungen behandeln, indem Sie beispielsweise den Knoten beim Stoppen der Instanz austauschen.
- Zalando verwendet offizielle Cluster-Autoskalierung mit Prioritäten für Node-Pools.
- Spot-Knoten „Registrierungen“ von Arbeitslasten zur Ausführung in Spot anzunehmen.
Zusammenfassung
Ich hoffe, dass Sie einige der vorgestellten Tools nützlich finden, um Ihre Cloud-Rechnung zu senken. Viele Inhalte des Artikels finden Sie auch in .
Was sind Ihre besten Praktiken zur Einsparung von Cloud-Kosten bei Kubernetes? Lassen Sie es mich bitte wissen in .
Tatsächlich werden weniger als 3 virtuelle CPUs einsatzbereit bleiben, da die Kapazität des Knotens durch reservierte Systemressourcen verringert wird. Kubernetes unterscheidet zwischen der physischen Kapazität eines Knotens und den "zugewiesenen" Ressourcen ().
Beispielrechnung: Eine Instanz m5.large mit 8 GiB RAM kostet etwa 84 US-Dollar pro Monat (eu-central-1, On-Demand), das heißt, die Blockierung von 1/8 eines Knotens kostet ungefähr 10 US-Dollar pro Monat.
Es gibt noch viele Möglichkeiten, Ihre EC2-Kosten zu senken, wie z.B. reservierte Instanzen, Sparpläne usw. — ich werde diese Themen hier nicht behandeln, aber Sie sollten sich unbedingt darüber informieren!
Quelle: habr.com
