So greifen Sie auf Kubernetes-Pod-Ressourcen zu

So greifen Sie auf Kubernetes-Pod-Ressourcen zuDie Belohnung von Tohad

Wenn man mit Kubernetes anfängt, vergisst man häufig das Einrichten von Containerressourcen. Zu diesem Zeitpunkt reicht es aus, sicherzustellen, dass das Docker-Image funktioniert und im Kubernetes-Cluster bereitgestellt werden kann.

Später muss die Anwendung jedoch zusammen mit anderen Anwendungen in einem Produktionscluster bereitgestellt werden. Dazu müssen Sie dem Container Ressourcen zuweisen und sicherstellen, dass genügend davon vorhanden sind, um die Anwendung zum Laufen zu bringen, und dass bei anderen laufenden Anwendungen keine Probleme auftreten.

Team Kubernetes aaS von Mail.ru hat einen Artikel über Containerressourcen (CPU & MEM), Anfragen und Ressourcenbeschränkungen übersetzt. Sie erfahren, welche Vorteile diese Einstellungen haben und was passiert, wenn Sie sie nicht festlegen.

Rechenressourcen

Wir haben zwei Arten von Ressourcen mit den folgenden Einheiten:

  • Zentraleinheit (CPU) – Kerne;
  • Speicher (MEM) – Bytes.

Für jeden Container werden Ressourcen angegeben. In der folgenden Pod-YAML-Datei sehen Sie einen Ressourcenabschnitt, der die angeforderten und limitierten Ressourcen enthält:

  • Angeforderte Pod-Ressourcen = Summe der angeforderten Ressourcen aller Container;
  • Pod-Ressourcenlimit = Summe aller Pod-Ressourcenlimits.

apiVersion: v1
kind: Pod
metadata:
  name: backend-pod-name
  labels:
    application: backend
spec:
  containers:
    — name: main-container
      image: my-backend
      tag: v1
      ports:
      — containerPort: 8080
      resources:
        requests:
          cpu: 0.2 # REQUESTED CPU: 200m cores
          memory: "1Gi" # REQUESTED MEM: 1Gi
        limits:
          cpu: 1 # MAX CPU USAGE: 1 core
          memory: "1Gi" # MAX MEM USAGE:  1Gi
    — name: other-container
      image: other-app
      tag: v1
      ports:
      — containerPort: 8000
      resources:
        requests:
          cpu: "200m" # REQUESTED CPU: 200m cores
          memory: "0.5Gi" # REQUESTED MEM: 0.5Gi
        limits:
          cpu: 1 # MAX CPU USAGE: 1 core
          memory: "1Gi" # MAX MEM USAGE:  1Gi

Beispiel für angeforderte und begrenzte Ressourcen

Feld resources.requested Aus der Spezifikation ist Pod eines der Elemente, das zum Auffinden des gewünschten Knotens verwendet wird. Sie können bereits die Pod-Bereitstellung dafür planen. Wie findet man einen passenden Knoten?

Kubernetes besteht aus mehreren Komponenten, darunter einem Masterknoten bzw. Masterknoten (Kubernetes Control Plane). Der Masterknoten verfügt über mehrere Prozesse: kube-apiserver, kube-controller-manager und kube-scheduler.

Der Kube-Scheduler-Prozess ist dafür verantwortlich, neu erstellte Pods zu überprüfen und mögliche Worker-Knoten zu finden, die allen Pod-Anfragen entsprechen, einschließlich der Anzahl der angeforderten Ressourcen. Die Liste der von kube-scheduler gefundenen Knoten wird geordnet. Der Pod wird auf dem Knoten mit den höchsten Punktzahlen geplant.

So greifen Sie auf Kubernetes-Pod-Ressourcen zuWo wird der lila Pod platziert?

Im Bild sehen Sie, dass kube-scheduler einen neuen lila Pod planen soll. Der Kubernetes-Cluster enthält zwei Knoten: A und B. Wie Sie sehen, kann kube-scheduler keinen Pod auf Knoten A planen – die verfügbaren (nicht angeforderten) Ressourcen stimmen nicht mit den Anforderungen des lila Pods überein. Daher passen die vom violetten Pod angeforderten 1 GB Speicher nicht auf Knoten A, da der verfügbare Speicher 0,5 GB beträgt. Aber Knoten B verfügt über genügend Ressourcen. Infolgedessen entscheidet der Kube-Scheduler, dass das Ziel des lila Pods Knoten B ist.

Jetzt wissen wir, wie sich die angeforderten Ressourcen auf die Wahl des Knotens zum Ausführen des Pods auswirken. Doch welchen Einfluss haben marginale Ressourcen?

Das Ressourcenlimit ist eine Grenze, die die CPU/MEM nicht überschreiten darf. Die CPU-Ressource ist jedoch flexibel, sodass Container, die ihre CPU-Grenzen erreichen, nicht dazu führen, dass der Pod beendet wird. Stattdessen beginnt die CPU-Drosselung. Wenn das MEM-Nutzungslimit erreicht ist, wird der Container aufgrund von OOM-Killer gestoppt und neu gestartet, sofern die RestartPolicy-Einstellung dies zulässt.

Gewünschte und maximale Ressourcen im Detail

So greifen Sie auf Kubernetes-Pod-Ressourcen zuRessourcenkommunikation zwischen Docker und Kubernetes

Der beste Weg, die Funktionsweise von Ressourcenanforderungen und Ressourcenlimits zu erklären, besteht darin, die Beziehung zwischen Kubernetes und Docker vorzustellen. Im Bild oben können Sie sehen, wie die Kubernetes-Felder und Docker-Startflags zusammenhängen.

Erinnerung: Anforderung und Einschränkung

containers:
...
 resources:
   requests:
     memory: "0.5Gi"
   limits:
     memory: "1Gi"

Wie oben erwähnt, wird der Speicher in Bytes gemessen. Bezogen auf Kubernetes-Dokumentationkönnen wir den Speicher als Zahl angeben. Normalerweise ist es eine Ganzzahl, zum Beispiel 2678 – also 2678 Bytes. Sie können auch Suffixe verwenden G и Gi, die Hauptsache ist, sich daran zu erinnern, dass sie nicht gleichwertig sind. Der erste ist dezimal und der zweite binär. Wie das in der k8s-Dokumentation erwähnte Beispiel: 128974848, 129e6, 129M, 123Mi - Sie sind praktisch gleichwertig.

Kubernetes-Option limits.memory entspricht der Flagge --memory von Docker. Im Falle von request.memory Für Docker gibt es keinen Pfeil, da Docker dieses Feld nicht verwendet. Sie fragen sich vielleicht: Ist das überhaupt notwendig? Ja, nötig. Wie ich bereits sagte, ist das Feld für Kubernetes wichtig. Basierend auf den daraus gewonnenen Informationen entscheidet kube-scheduler, für welchen Knoten der Pod geplant werden soll.

Was passiert, wenn Sie für eine Anfrage nicht genügend Speicher festlegen?

Wenn der Container die Grenzen des angeforderten Speichers erreicht hat, wird der Pod in eine Gruppe von Pods eingefügt, die angehalten werden, wenn im Knoten nicht genügend Speicher vorhanden ist.

Was passiert, wenn Sie das Speicherlimit zu niedrig einstellen?

Wenn der Container das Speicherlimit überschreitet, wird er aufgrund von OOM-Killed beendet. Und wenn möglich basierend auf RestartPolicy neu starten, wo der Standardwert ist Always.

Was passiert, wenn Sie den angeforderten Speicher nicht angeben?

Kubernetes übernimmt den Grenzwert und legt ihn als Standardwert fest.

Was kann passieren, wenn Sie kein Speicherlimit angeben?

Für den Container gibt es keine Einschränkungen; er kann so viel Speicher nutzen, wie er möchte. Wenn er anfängt, den gesamten verfügbaren Speicher des Knotens zu nutzen, wird ihn OOM töten. Der Container wird dann, wenn möglich, basierend auf RestartPolicy neu gestartet.

Was passiert, wenn Sie keine Speichergrenzen angeben?

Dies ist das Worst-Case-Szenario: Der Scheduler weiß nicht, wie viele Ressourcen der Container benötigt, und dies kann zu ernsthaften Problemen auf dem Knoten führen. In diesem Fall wäre es schön, Standardgrenzen für den Namespace zu haben (festgelegt durch LimitRange). Es gibt keine Standardgrenzen – der Pod hat keine Grenzen, er kann so viel Speicher nutzen, wie er möchte.

Wenn der angeforderte Speicher größer ist, als der Knoten bieten kann, wird der Pod nicht geplant. Es ist wichtig, sich daran zu erinnern Requests.memory - nicht der Mindestwert. Dies ist eine Beschreibung der Speichermenge, die ausreicht, um den Container kontinuierlich laufen zu lassen.

Normalerweise wird empfohlen, denselben Wert festzulegen request.memory и limit.memory. Dadurch wird sichergestellt, dass Kubernetes keinen Pod auf einem Knoten plant, der über genügend Arbeitsspeicher zum Ausführen des Pods verfügt, aber nicht über genügend Speicher, um ihn auszuführen. Beachten Sie: Bei der Kubernetes-Pod-Planung wird nur berücksichtigt requests.memoryUnd limits.memory nicht berücksichtigt.

CPU: Anforderung und Limit

containers:
...
 resources:
   requests:
     cpu: 1
   limits:
     cpu: "1200m"

Bei einer CPU ist alles etwas komplizierter. Wenn wir uns das Bild der Beziehung zwischen Kubernetes und Docker noch einmal ansehen, können Sie das sehen request.cpu Streichhölzer --cpu-sharesWährend limit.cpu entspricht der Flagge cpus im Docker.

Die von Kubernetes angeforderte CPU wird mit 1024 multipliziert, dem Anteil der CPU-Zyklen. Wenn Sie 1 vollständigen Kern anfordern möchten, müssen Sie hinzufügen cpu: 1wie oben gezeigt.

Das Anfordern eines vollständigen Kernels (Anteil = 1024) bedeutet nicht, dass Ihr Container ihn erhält. Wenn Ihr Host-Computer nur über einen Kern verfügt und Sie mehr als einen Container ausführen, müssen alle Container die verfügbare CPU gemeinsam nutzen. Wie kommt es dazu? Schauen wir uns das Bild an.

So greifen Sie auf Kubernetes-Pod-Ressourcen zu
CPU-Anfrage – Single-Core-System

Stellen wir uns vor, dass Sie über ein Single-Core-Hostsystem verfügen, auf dem Container ausgeführt werden. Mama (Kubernetes) hat einen Kuchen gebacken (CPU) und möchte ihn unter den Kindern aufteilen (Behälter). Drei Kinder wollen einen ganzen Kuchen (Anteil = 1024), ein anderes Kind möchte einen halben Kuchen (512). Mama möchte fair sein und stellt eine einfache Rechnung auf.

# Сколько пирогов хотят дети?
# 3 ребенка хотят по целому пирогу и еще один хочет половину пирога
cakesNumberKidsWant = (3 * 1) + (1 * 0.5) = 3.5
# Выражение получается так:
3 (ребенка/контейнера) * 1 (целый пирог/полное ядро) + 1 (ребенок/контейнер) * 0.5 (половина пирога/половина ядра)
# Сколько пирогов испечено?
availableCakesNumber = 1
# Сколько пирога (максимально) дети реально могут получить?
newMaxRequest = 1 / 3.5 =~ 28%

Basierend auf der Berechnung erhalten drei Kinder 28 % des Kerns und nicht den gesamten Kern. Das vierte Kind erhält 14 % des gesamten Kernels, nicht die Hälfte. Anders verhält es sich jedoch, wenn Sie über ein Multicore-System verfügen.

So greifen Sie auf Kubernetes-Pod-Ressourcen zu
CPU-Anfrage – Multi-Core (4) System

Im Bild oben sehen Sie, dass drei Kinder einen ganzen Kuchen wollen und eines die Hälfte. Da Mama vier Kuchen gebacken hat, bekommt jedes ihrer Kinder so viele, wie es möchte. In einem Mehrkernsystem werden die Prozessorressourcen auf alle verfügbaren Prozessorkerne verteilt. Wenn ein Container auf weniger als einen vollen CPU-Kern beschränkt ist, kann er ihn trotzdem zu 100 % nutzen.

Die obigen Berechnungen werden vereinfacht, um zu verstehen, wie die CPU auf die Container verteilt wird. Natürlich gibt es neben den Containern selbst auch andere Prozesse, die ebenfalls CPU-Ressourcen beanspruchen. Wenn Prozesse in einem Container inaktiv sind, können andere seine Ressource nutzen. CPU: "200m" Streichhölzer CPU: 0,2, was ungefähr 20 % eines Kerns bedeutet.

Jetzt reden wir darüber limit.cpu. Die von Kubernetes begrenzte CPU wird mit 100 multipliziert. Das Ergebnis ist die Zeit, die der Container alle 100 µs nutzen kann (cpu-period).

limit.cpu entspricht der Docker-Flagge --cpus. Dies ist eine neue Kombination aus Altem --cpu-period и --cpu-quota. Indem wir es festlegen, geben wir an, wie viele verfügbare CPU-Ressourcen der Container maximal nutzen kann, bevor die Drosselung beginnt:

  • CPU - Kombination cpu-period и cpu-quota. cpus = 1.5 gleichbedeutend mit Einstellung cpu-period = 100000 и cpu-quota = 150000;
  • CPU-Periode - Zeitraum CPU-CFS-Scheduler, Standard 100 Mikrosekunden;
  • CPU-Kontingent - Anzahl der darin enthaltenen Mikrosekunden cpu-period, die durch den Container begrenzt wird.

Was passiert, wenn Sie nicht genügend angeforderte CPU installieren?

Wenn der Container mehr benötigt, als er installiert hat, entzieht er anderen Prozessen CPU.

Was passiert, wenn Sie das CPU-Limit zu niedrig einstellen?

Da die CPU-Ressource anpassbar ist, wird die Drosselung aktiviert.

Was passiert, wenn Sie keine CPU-Anfrage angeben?

Wie beim Speicher entspricht der Anforderungswert dem Grenzwert.

Was passiert, wenn Sie kein CPU-Limit angeben?

Der Container verbraucht so viel CPU, wie er benötigt. Wenn im Namespace eine Standard-CPU-Richtlinie (LimitRange) definiert ist, wird dieses Limit auch für den Container verwendet.

Was passiert, wenn Sie weder eine Anfrage noch ein CPU-Limit angeben?

Wie beim Speicher ist dies das Worst-Case-Szenario. Der Scheduler weiß nicht, wie viele Ressourcen Ihr Container benötigt, und dies kann zu ernsthaften Problemen auf dem Knoten führen. Um dies zu vermeiden, müssen Sie Standardgrenzen für Namespaces festlegen (LimitRange).

Denken Sie daran: Wenn Sie mehr CPU anfordern, als die Knoten bereitstellen können, wird der Pod nicht geplant. Requests.cpu - nicht der Mindestwert, aber ein Wert, der ausreicht, um den Pod zu starten und ohne Fehler zu arbeiten. Wenn die Anwendung keine komplexen Berechnungen durchführt, ist die Installation die beste Option request.cpu <= 1 und starten Sie so viele Replikate wie nötig.

Ideale Menge der angeforderten Ressourcen oder Ressourcenlimit

Wir haben erfahren, dass die Rechenressourcen begrenzt sind. Jetzt ist es an der Zeit, die Frage zu beantworten: „Wie viele Ressourcen benötigt mein Pod, um die Anwendung problemlos auszuführen?“ Was ist die ideale Menge?

Leider gibt es auf diese Fragen keine klaren Antworten. Wenn Sie nicht wissen, wie Ihre Anwendung funktioniert oder wie viel CPU oder Speicher sie benötigt, ist es die beste Option, der Anwendung viel Speicher und CPU zu geben und dann Leistungstests durchzuführen.

Überwachen Sie zusätzlich zu den Leistungstests eine Woche lang das Verhalten der Anwendung im Monitoring. Wenn die Diagramme darauf hinweisen, dass Ihre Anwendung weniger Ressourcen verbraucht als angefordert, können Sie die angeforderte CPU- oder Speichermenge reduzieren.

Als Beispiel sehen Sie hier Grafana-Dashboard. Es zeigt die Differenz zwischen den angeforderten Ressourcen oder dem Ressourcenlimit und der aktuellen Ressourcennutzung an.

Abschluss

Das Anfordern und Begrenzen von Ressourcen trägt dazu bei, dass Ihr Kubernetes-Cluster gesund bleibt. Durch die richtige Limitkonfiguration werden die Kosten minimiert und die Anwendungen bleiben jederzeit betriebsbereit.

Kurz gesagt, es gibt ein paar Dinge, die Sie beachten sollten:

  1. Bei den angeforderten Ressourcen handelt es sich um eine Konfiguration, die beim Start berücksichtigt wird (wenn Kubernetes plant, die Anwendung zu hosten). Im Gegensatz dazu ist die Begrenzung der Ressourcen zur Laufzeit wichtig – wenn die Anwendung bereits auf dem Knoten ausgeführt wird.
  2. Im Vergleich zum Speicher ist die CPU eine regulierte Ressource. Wenn nicht genügend CPU vorhanden ist, wird Ihr Pod nicht heruntergefahren und der Drosselmechanismus wird aktiviert.
  3. Angeforderte Ressourcen und Ressourcenlimit sind keine Minimal- und Maximalwerte! Durch die Definition der angeforderten Ressourcen stellen Sie sicher, dass die Anwendung problemlos ausgeführt werden kann.
  4. Eine gute Vorgehensweise besteht darin, die Speicheranforderung auf den Wert des Speicherlimits festzulegen.
  5. Ok, Installation angefordert CPU <=1, wenn die Anwendung keine komplexen Berechnungen durchführt.
  6. Wenn Sie mehr Ressourcen anfordern, als auf einem Knoten verfügbar sind, wird der Pod niemals für diesen Knoten geplant.
  7. Um die richtige Menge der angeforderten Ressourcen/Ressourcenlimits zu ermitteln, verwenden Sie Lasttests und -überwachung.

Ich hoffe, dieser Artikel hilft Ihnen, das Grundkonzept der Ressourcenbeschränkung zu verstehen. Und Sie können dieses Wissen in Ihrer Arbeit anwenden.

Good Luck!

Was es sonst noch zu lesen gibt:

  1. SRE-Beobachtbarkeit: Namespaces und Metrikstruktur.
  2. Über 90 nützliche Tools für Kubernetes: Bereitstellung, Verwaltung, Überwachung, Sicherheit und mehr.
  3. Unser Kanal Rund um Kubernetes in Telegram.

Source: habr.com

Kommentar hinzufügen