Automatisches Skalieren und Ressourcenmanagement in Kubernetes (Überblick und Vortragvideo)

Am 27. April fand auf der Konferenz Streik-2019, im Rahmen der Sitzung „DevOps“, wurde der Vortrag „Automatische Skalierung und Ressourcenmanagement in Kubernetes“ gehalten. Dabei wird erläutert, wie man mit Hilfe von K8s hohe Verfügbarkeit für Anwendungen sicherstellt und deren maximale Leistung garantiert.

Automatisches Skalieren und Ressourcenmanagement in Kubernetes (Überblick und Vortragvideo)

Traditionell freuen wir uns, das Video mit dem Vortrag (44 Minuten, deutlich informativer als der Artikel) sowie die Hauptinhalte in Textform. Lasst uns loslegen!

Lassen Sie uns das Thema des Vortrags schrittweise durchgehen und am Ende beginnen.

Kubernetes

Stellen Sie sich vor, wir haben Docker-Container auf dem Host. Warum? Um Reproduzierbarkeit und Isolation zu gewährleisten, die wiederum einen einfachen und effektiven Deploy sowie CI/CD ermöglichen. Wir haben viele Maschinen mit Containern.

Was bietet uns in diesem Fall Kubernetes?

  1. Wir hören auf, über diese Maschinen nachzudenken, und beginnen stattdessen mit der Arbeit im „Cloud“-Umfeld, einem Cluster von Containern oder Pods (Gruppen von Containern).
  2. Darüber hinaus denken wir nicht einmal mehr an einzelne Pods, sondern verwalten noch größere Gruppen.größtenSolche hochrangigen Primitiven ermöglichen es uns zu sagen, dass es eine Vorlage für das Starten einer bestimmten Arbeitslast gibt und wie viele Instanzen dafür erforderlich sind. Wenn wir später die Vorlage ändern, ändern sich auch alle Instanzen.
  3. Mit deklarative API Anstelle einer Abfolge spezifischer Befehle beschreiben wir das ‚Weltbild‘ (im YAML), das von Kubernetes erstellt wird. Und wieder: Bei Änderungen der Beschreibung ändert sich auch die tatsächliche Darstellung.

Ressourcenmanagement

CPU

Angenommen, wir betreiben nginx, php-fpm und mysql auf dem Server. Diese Dienste werden tatsächlich noch mehr Prozesse haben, die alle Rechenressourcen erfordern:

Automatisches Skalieren und Ressourcenmanagement in Kubernetes (Überblick und Vortragvideo)
(Die Zahlen auf der Folie sind ‚Papageien‘, eine abstrakte Darstellung des Ressourcenbedarfs jedes Prozesses.)

Um damit bequem zu arbeiten, ist es sinnvoll, die Prozesse in Gruppen zusammenzufassen (alle nginx-Prozesse beispielsweise in einer Gruppe ‚nginx‘). Ein einfacher und offensichtlicher Weg, dies zu tun, besteht darin, jede Gruppe in einen Container zu platzieren:

Automatisches Skalieren und Ressourcenmanagement in Kubernetes (Überblick und Vortragvideo)

Um fortzufahren, sollten wir uns erinnern, was ein Container (in Linux) ist. Ihr Aufkommen wurde durch drei Schlüsselfunktionen im Kernel ermöglicht, die schon seit einiger Zeit implementiert sind: Capabilities festzulegen., namespaces und cgroups. Die weitere Entwicklung wurde durch andere Technologien (einschließlich benutzerfreundlicher ‚Schalen‘ wie Docker) gefördert:

Automatisches Skalieren und Ressourcenmanagement in Kubernetes (Überblick und Vortragvideo)

Im Kontext dieses Vortrags interessiert uns nur cgroups, denn Kontrollgruppen sind der Teil der Funktionen von Containern (wie Docker usw.), der das Ressourcenmanagement ermöglicht. Die Prozesse, die in Gruppen zusammengeschlossen sind, entsprechen unseren Erwartungen — das sind die Kontrollgruppen.

Kehren wir zu den CPU-Anforderungen dieser Prozesse zurück, nun aber zu den Gruppen von Prozessen:

Automatisches Skalieren und Ressourcenmanagement in Kubernetes (Überblick und Vortragvideo)
(Ich wiederhole, dass alle Zahlen eine abstrakte Darstellung des Ressourcenbedarfs sind)

Dabei hat die CPU selbst eine gewisse begrenzte Ressource (in unserem Beispiel sind das 1000), die möglicherweise nicht für alle ausreicht (die Summe der Bedürfnisse aller Gruppen beträgt 150+850+460=1460). Was passiert in einem solchen Fall?

Der Kernel beginnt, Ressourcen zu verteilen, und tut dies „fair“, indem er jeder Gruppe die gleiche Menge an Ressourcen zuweist. Im ersten Fall benötigen sie jedoch mehr als nötig (333>150), weshalb der Überschuss (333-150=183) als Reserve bleibt, die ebenfalls gleichmäßig auf die beiden anderen Container verteilt wird:

Automatisches Skalieren und Ressourcenmanagement in Kubernetes (Überblick und Vortragvideo)

Am Ende: der erste Container hatte genügend Ressourcen, der zweite hatte deutlich zu wenig, der dritte kam ein wenig zu kurz. So lautet das Ergebnis der Handlungen des „fairen“ Planers in LinuxCFS. Seine Arbeit kann durch die Zuweisung von Gewichtungen für jeden der Container reguliert werden. Zum Beispiel so:

Automatisches Skalieren und Ressourcenmanagement in Kubernetes (Überblick und Vortragvideo)

Betrachten wir den Fall, dass der zweite Container (php-fpm) nicht genügend Ressourcen hat. Alle Ressourcen des Containers werden gleichmäßig auf die Prozesse verteilt. Infolgedessen läuft der Master-Prozess gut, während alle Worker-Prozesse aufgrund von weniger als der Hälfte der benötigten Ressourcen stocken.

Automatisches Skalieren und Ressourcenmanagement in Kubernetes (Überblick und Vortragvideo)

So funktioniert der CFS-Scheduler. Die Gewichtungen, die wir den Containern zuweisen, werden wir später als Requestsbezeichnen. Warum genau so – siehe weiter.

Blicken wir auf die gesamte Situation aus einer anderen Perspektive. Wie bekannt ist, führen alle Straßen nach Rom und im Fall eines Computers zum CPU. Der CPU ist einzigartig, die Aufgaben sind zahlreich – es braucht eine Ampel. Der einfachste Ansatz zur Ressourcenverwaltung ist das „Ampel“-System: einem Prozess wird eine fixe Zugriffszeit auf den CPU zugewiesen, dann dem nächsten usw.

Automatisches Skalieren und Ressourcenmanagement in Kubernetes (Überblick und Vortragvideo)

Dieser Ansatz wird als hartes Quoting bezeichnet.Wir merken uns einfach den Begriff Limits.Wenn wir jedoch allen Containern Limits zuweisen, entsteht ein Problem: MySQL fährt auf der Straße und benötigt irgendwann CPU-Ressourcen, während alle anderen Prozesse warten müssen, bis der CPU frei wird..

Automatisches Skalieren und Ressourcenmanagement in Kubernetes (Überblick und Vortragvideo)

Kehren wir zum Linux-Kernel und seiner Interaktion mit dem CPU zurück – das Gesamtbild sieht wie folgt aus:

Automatisches Skalieren und Ressourcenmanagement in Kubernetes (Überblick und Vortragvideo)

Eine cgroup hat zwei Einstellungen – es handelt sich im Wesentlichen um zwei einfache „Regler“, die es ermöglichen zu bestimmen:

  1. das Gewicht für den Container (Anfragen) – das ist Anteile;
  2. der Prozentsatz der gesamten CPU-Zeit, die für die Bearbeitung von Aufgaben des Containers zur Verfügung steht (Limits) – das ist Kontingent.

Wie misst man die CPU?

Es gibt verschiedene Methoden:

  1. Was ist Papageien, niemand weiß es – man muss sich jedes Mal absprechen.
  2. Prozentsätze sind verständlicher, aber relativ: 50 % von einem Server mit 4 Kernen und mit 20 Kernen sind völlig unterschiedliche Dinge.
  3. Man kann die bereits erwähnten von Gewichtungen, die Linux kennt, verwenden, aber die sind ebenfalls relativ.
  4. Die vernünftigste Möglichkeit ist, die Rechenressourcen in Sekundenzu messen. Das heißt, in CPU-Zeit im Verhältnis zu Echtzeit: 1 Sekunde CPU-Zeit in 1 realer Sekunde vergeben – das entspricht einem CPU-Kern vollständig.

Um es noch einfacher auszudrücken, wird jetzt direkt in Kernengemessen, wobei damit genau die CPU-Zeit im Verhältnis zur Realität gemeint ist. Da Linux Gewichte versteht und nicht solche CPU-Zeiten/Kerne, benötigte man einen Mechanismus zur Umrechnung von einem in das andere.

Betrachten wir ein einfaches Beispiel mit einem Server, der über 3 CPU-Kerne verfügt, wobei den drei Pods die Gewichte (500, 1000 und 1500) zugewiesen werden, die leicht in die entsprechenden Teile der zugewiesenen Kerne (0,5, 1 und 1,5) umgewandelt werden können.

Automatisches Skalieren und Ressourcenmanagement in Kubernetes (Überblick und Vortragvideo)

Wenn wir einen zweiten Server mit der doppelten Anzahl an Kernen (6) nehmen und dort dieselben Pods platzieren, lässt sich die Verteilung der Kerne einfach durch Multiplikation mit 2 berechnen (1, 2 und 3 entsprechend). Aber ein wichtiger Punkt tritt ein, wenn auf diesem Server ein vierter Pod erscheint, dessen Gewicht zum Zweck der Vereinfachung 3000 beträgt. Dieser belegt sich einen Teil der CPU-Ressourcen (die Hälfte der Kerne), und die Ressourcen der anderen Pods werden neu berechnet (halbiert):

Automatisches Skalieren und Ressourcenmanagement in Kubernetes (Überblick und Vortragvideo)

Kubernetes und CPU-Ressourcen

In Kubernetes werden die CPU-Ressourcen üblicherweise in Milliarden, d.h. als Basisgewicht wird 0,001 Kern verwendet. (Das Gleiche wird in der Linux-/cgroups-Terminologie als CPU-Anteil bezeichnet, wobei 1000 Milliarden = 1024 CPU-Anteile entspricht, um es genauer zu sagen.) K8s überwacht, dass auf einem Server nicht mehr Pods platziert werden, als Ressourcen für die Summe der Gewichte aller Pods vorhanden sind.

Wie funktioniert das? Wenn ein Server in ein Kubernetes-Cluster hinzugefügt wird, wird die Anzahl der verfügbaren CPU-Kerne gemeldet. Beim Erstellen eines neuen Pods weiß der Kubernetes-Planer, wie viele Kerne der Pod benötigt. So wird der Pod auf einem Server platziert, auf dem genügend Kerne vorhanden sind.

Was passiert, wenn nicht ein Request angegeben ist (d.h. die Anzahl der benötigten Kerne für den Pod ist nicht definiert)? Lassen Sie uns verstehen, wie Kubernetes Ressourcen insgesamt berechnet.

Für den Pod können sowohl Requests (CFS-Planer) als auch Limits angegeben werden (denken Sie an die Ampel):

  • Wenn sie gleich angegeben sind, wird dem Pod eine QoS-Klasse zugewiesen guaranteed. Diese Anzahl an immer verfügbaren Kernen wird garantiert.
  • Wenn der Request kleiner ist als das Limit — QoS-Klasse burstable. Das bedeutet, wir erwarten, dass der Pod beispielsweise immer 1 Kern verwendet, jedoch ist dieser Wert für ihn keine Begrenzung: manchmal der Pod kann auch mehr verwenden (wenn auf dem Server dafür freie Ressourcen vorhanden sind).
  • Es gibt noch die QoS-Klasse best effort — dazu gehören die Pods, für die kein Request angegeben ist. Ihnen werden Ressourcen zuletzt zugeteilt.

Speicher

Bei der Speicherverwaltung ist die Situation ähnlich, aber etwas anders – schließlich sind die Eigenschaften dieser Ressourcen unterschiedlich. Im Allgemeinen ist die Analogie wie folgt:

Automatisches Skalieren und Ressourcenmanagement in Kubernetes (Überblick und Vortragvideo)

Lassen Sie uns anschauen, wie Requests im Speicher umgesetzt werden. Stellen Sie sich vor, Pods leben auf einem Server und verändern den benötigten Speicher, bis einer von ihnen so groß wird, dass der Speicher erschöpft ist. In diesem Fall tritt der OOM-Killer auf und beendet den größten Prozess:

Automatisches Skalieren und Ressourcenmanagement in Kubernetes (Überblick und Vortragvideo)

Das ist nicht immer zufriedenstellend, daher gibt es die Möglichkeit zu steuern, welche Prozesse für uns wichtig sind und nicht beendet werden sollen. Dazu wird der Parameter verwendet: oom_score_adj.

Kehren wir zu den CPU-QoS-Klassen zurück und ziehen eine Analogie zu den Werten von oom_score_adj, die die Prioritäten der Pods beim Speicherverbrauch festlegen:

  • Der niedrigste Wert von oom_score_adj für einen Pod ist -998, was bedeutet, dass dieser Pod als letztes beendet werden sollte, das ist guaranteed.
  • Der höchste Wert ist 1000, das ist best effort, solche Pods werden als erstes beendet.
  • Zur Berechnung der anderen Werte (burstable) gibt es eine Formel, die besagt, dass je mehr Ressourcen ein Pod angefordert hat, desto geringer die Chancen, dass er beendet wird.

Automatisches Skalieren und Ressourcenmanagement in Kubernetes (Überblick und Vortragvideo)

Die zweite "Einstellung" — limit_in_bytes — bezieht sich auf die Limits. Es ist einfacher: Wir setzen einfach die maximale Menge an zugewiesenem Speicher, und hier (im Gegensatz zur CPU) stellt sich nicht die Frage, wie man ihn (den Speicher) messen soll.

Gesamt

Jeder Pod in Kubernetes erhält requests und Limits — beide Parameter für CPU und für den Arbeitsspeicher:

  1. Basierend auf den requests arbeitet der Kubernetes-Controller, der die pods auf den Servern verteilt;
  2. Basierend auf allen Parametern wird die QoS-Klasse des pods bestimmt;
  3. Basierend auf den CPU-Requests werden die relativen Gewichte berechnet;
  4. Basierend auf den CPU-Requests wird der CFS-Planer konfiguriert;
  5. Basierend auf den Memory-Requests wird der OOM-Killer eingerichtet;
  6. Basierend auf den CPU-Limits wird die "Ampel" konfiguriert;
  7. Basierend auf den Memory-Limits wird das Limit für die cgroup eingestellt.

Automatisches Skalieren und Ressourcenmanagement in Kubernetes (Überblick und Vortragvideo)

Insgesamt beantwortet dieses Bild alle Fragen zur Verwaltung von Ressourcen in Kubernetes.

Automatisches Skalieren

K8s Cluster-Autoscaler

Stellen wir uns vor, dass der gesamte Cluster bereits belegt ist und ein neuer pod erstellt werden muss. Solange der pod nicht erscheinen kann, bleibt er im Status Pending. Damit er dennoch erscheinen kann, können wir einen neuen Server an den Cluster anschließen oder… einen Cluster-Autoscaler installieren, der dies für uns erledigt: Er bestellt eine virtuelle Maschine beim Cloud-Anbieter (via API-Anfrage) und verbindet sie mit dem Cluster, woraufhin der pod hinzugefügt wird.

Automatisches Skalieren und Ressourcenmanagement in Kubernetes (Überblick und Vortragvideo)

Das ist das automatische Skalieren des Kubernetes-Clusters, das unserer Erfahrung nach hervorragend funktioniert. Allerdings gibt es, wie überall, auch hier einige Nuancen...

Während wir die Clustergröße erhöhten, lief alles gut. Aber was passiert, wenn der Cluster freigegeben wird?? Проблема в том, что мигрировать pod’ы (для освобождения хостов) очень технически сложно и дорого по ресурсам. В Kubernetes работает совсем другой подход.

Betrachten wir einen Cluster aus 3 Servern, der ein Deployment enthält. Er hat 6 Pods: zurzeit sind das 2 pro Server. Aus irgendeinem Grund möchten wir einen der Server ausschalten. Dafür verwenden wir den Befehl kubectl drain, der:

  • das Senden neuer Pods an diesen Server verbietet;
  • die bestehenden Pods auf dem Server entfernt.

Da Kubernetes darauf achtet, die Anzahl der Pods (6) aufrechtzuerhalten, wird es einfach diese auf anderen Knoten neu erstellen, jedoch nicht auf dem, der ausgeschaltet wird, da dieser bereits als nicht verfügbar für die Bereitstellung neuer Pods markiert ist. Dies ist eine grundlegende Mechanik für Kubernetes.

Automatisches Skalieren und Ressourcenmanagement in Kubernetes (Überblick und Vortragvideo)

Es gibt jedoch einen Unterschied. In einer ähnlichen Situation für ein StatefulSet (anstatt eines Deployments) wären die Reaktionen anders. Jetzt haben wir eine stateful Anwendung – beispielsweise drei Pods mit MongoDB, von denen einer ein Problem hat (Daten sind beschädigt oder ein anderer Fehler, der das korrekte Starten des Pods verhindert). Und wir entscheiden uns erneut, einen Server auszuschalten. Was wird passieren?

Automatisches Skalieren und Ressourcenmanagement in Kubernetes (Überblick und Vortragvideo)

MongoDB einfügen könnte sterben, da ein quorum erforderlich ist: für einen Cluster mit drei Instanzen müssen mindestens zwei funktionsfähig sein. Doch das geschieht nicht — dank PodDisruptionBudget. Dieser Parameter bestimmt die minimal erforderliche Anzahl an laufenden Pods. Da einer der Pods mit MongoDB bereits nicht mehr läuft und wir sehen, dass für MongoDB im PodDisruptionBudget festgelegt ist minAvailable: 2, wird Kubernetes das Entfernen des Pods nicht zulassen.

Fazit: Um eine korrekte Verschiebung (oder besser gesagt - Neuschaffung) von Pods bei der Freigabe des Clusters zu gewährleisten, ist es notwendig, das PodDisruptionBudget zu konfigurieren.

Horizontale Skalierung

Betrachten wir eine andere Situation. Es gibt eine Anwendung, die als Deployment in Kubernetes läuft. Auf ihre Pods (nehmen wir an, es sind drei) gelangt Benutzertraffik, und wir messen darin einen bestimmten Wert (sagen wir, die CPU-Auslastung). Wenn die Last steigt, erfassen wir dies im Diagramm und erhöhen die Anzahl der Pods, um die Anfragen zu verteilen.

Heute ist es in Kubernetes nicht mehr nötig, dies manuell zu tun: es wird eine automatische Erhöhung/Reduzierung der Anzahl an Pods basierend auf den gemessenen Lastwerten konfiguriert.

Automatisches Skalieren und Ressourcenmanagement in Kubernetes (Überblick und Vortragvideo)

Die Hauptfragen hier sind, was genau gemessen werden soll und und wie es interpretiert wird Erfasste Werte (für die Entscheidung über die Änderung der Anzahl der Pods). Es gibt viele Aspekte, die gemessen werden können:

Automatisches Skalieren und Ressourcenmanagement in Kubernetes (Überblick und Vortragvideo)

Wie man dies technisch umsetzt — das Sammeln von Metriken usw. — habe ich ausführlich in meinem Vortrag über Monitoring und Kubernetes. Ein wichtiger Ratschlag zur Auswahl optimaler Parameter ist der experimentieren Sie!

Es gibt USE-Methodik (Utilization, Saturation und Errors), deren Sinn folgendermassen ist: Worauf basiert die Entscheidung, zum Beispiel php-fpm zu skalieren? Wenn die Worker ausgehen — das ist die Nutzung. Wenn die Worker erschöpft sind und keine neuen Verbindungen mehr angenommen werden — das ist bereits die Sättigung. Beide Parameter müssen gemessen werden und basierend auf den Werten sollte eine Skalierung vorgenommen werden.

Abschließend

Der Vortrag hat eine Fortsetzung: über vertikale Skalierung und wie man Ressourcen richtig auswählt. Darüber werde ich in zukünftigen Videos auf unserem YouTube-Kanal berichten — abonnieren Sie, um nichts zu verpassen!

Videos und Folien

Das Video der Präsentation (44 Minuten):

Video abspielen

Präsentation des Vortrags:

P.S.

Erweiterung und Ergänzung von Kubernetes

Quelle: habr.com

Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server 🔥 Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server | ProHoster