Kostensenkung bei Cloud-Ausgaben Kubernetes auf AWS

Die Übersetzung des Artikels wurde im Vorfeld des Starts des Kurses vorbereitet „Infrastrukturplattform auf Basis von Kubernetes“.

Kostensenkung bei Cloud-Ausgaben Kubernetes auf AWS

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 (Cluster-Autoscaler). 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 (kube-janitor)
  • Reduzierung des Scale in der Nebensaison (kube-downscaler)
  • Verwendung von Horizontal Pod Autoscaling (HPA),
  • Reduzierung der Überbuchung von Ressourcen (kube-resource-report, 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 schneller werden. 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:

Kostensenkung bei Cloud-Ausgaben Kubernetes auf AWS

(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.)

Kubernetes Janitor (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: 2d

Das 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: 7d

Starten 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=30m

Eine 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: 24h

Kubernetes 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 README kube-janitor.

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.

Kubernetes Downscaler (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-time

Hier ist das Diagramm für das Scaling von Arbeitsknoten im Cluster an Wochenenden:

Kostensenkung bei Cloud-Ausgaben Kubernetes auf AWS

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=true

Siehe README kube-downscaler, 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 HorizontalPodAutoscaler (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: Utilization

Zalando hat eine Komponente erstellt, um benutzerdefinierte Metriken für das Auto-Scaling einfach zu integrieren: Kube Metrics Adapter (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: AverageValue

Die 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: Skalieren Sie Ihre Deployments, nicht Ihr Budget.

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. [1]

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. [2]

Kubernetes Resource Report (kube-resource-report) zeigt übermäßige Reserven an und kann Ihnen helfen, Einsparpotenziale zu identifizieren:

Kostensenkung bei Cloud-Ausgaben Kubernetes auf AWS

Kubernetes Resource Report 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:

Kostensenkung bei Cloud-Ausgaben Kubernetes auf AWS

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“, - schreibt Corey Quinn. Während für EC2 die Schätzung der richtigen Größe eine schlechte Entscheidung sein kann,, 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 Vertical Pod Autoscaler (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):

Kostensenkung bei Cloud-Ausgaben Kubernetes auf AWS

Zalando verwendet VPA in all seinen Clustern für Infrastrukturkomponenten. Auch nicht-kritische Anwendungen können VPA nutzen.

Goldilocks 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:

Kostensenkung bei Cloud-Ausgaben Kubernetes auf AWS

Ich habe 2019 einen kleinen Blogpost über VPA geschrieben und kürzlich wurde das Thema VPA in der CNCF End User Community diskutiert..

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. [3]. 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 Fork offizielle Cluster-Autoskalierung mit Prioritäten für Node-Pools.
  • Spot-Knoten können dazu gebracht werden, „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 meinem Vortrag beim DevOps Gathering 2019 auf YouTube und in Form von Folien..

Was sind Ihre besten Praktiken zur Einsparung von Cloud-Kosten bei Kubernetes? Lassen Sie es mich bitte wissen in Twitter (@try_except_)..

[1] 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 (Node Allocatable).

[2] 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.

[3] 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!

Weitere Informationen zum Kurs.

Quelle: habr.com

60GB SSD 8Gb DDR4