
Zu Beginn der Arbeit mit Kubernetes wird oft die Konfiguration der Containerressourcen vergessen. In dieser Phase ist es ausreichend sicherzustellen, dass das Docker-Image funktioniert und in einem Kubernetes-Cluster bereitgestellt werden kann.
Später muss die Anwendung jedoch in einem Produktionscluster zusammen mit anderen Anwendungen bereitgestellt werden. Dazu müssen Ressourcen für den Container zugewiesen werden, um sicherzustellen, dass diese ausreichend sind, um die Anwendung zu starten und auszuführen, ohne dass es zu Problemen in anderen laufenden Anwendungen kommt.
Der Befehl Ich habe einen Artikel über Containerressourcen (CPU & MEM), Ressourcaanforderungen und -beschränkungen übersetzt. Sie werden erfahren, welche Vorteile diese Einstellungen bieten und was passiert, wenn sie nicht vorgenommen werden.
Rechenressourcen
Wir haben zwei Arten von Ressourcen mit den folgenden Einheiten:
- Zentralprozessor (CPU) – Kerne;
- Speicher (MEM) – Bytes.
Ressourcen werden für jeden Container angegeben. In der folgenden YAML-Datei für Pods sehen Sie den Ressourcenabschnitt, der die angeforderten und begrenzten Ressourcen enthält:
- Angeforderte Ressourcen des Pods = Summe der angeforderten Ressourcen aller Container;
- Begrenzte Ressourcen des Pods = Summe der begrenzten Ressourcen aller Container.
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 # ANGEFRAGTE CPU: 200m Kerne
memory: "1Gi" # ANGEFRAGTER SPEICHER: 1Gi
limits:
cpu: 1 # MAXIMALER CPU-VERBRAUCH: 1 Kern
memory: "1Gi" # MAXIMALER SPEICHERVERBRAUCH: 1Gi
— name: other-container
image: other-app
tag: v1
ports:
— containerPort: 8000
resources:
requests:
cpu: "200m" # ANGEFRAGTE CPU: 200m Kerne
memory: "0.5Gi" # ANGEFRAGTER SPEICHER: 0.5Gi
limits:
cpu: 1 # MAXIMALER CPU-VERBRAUCH: 1 Kern
memory: "1Gi" # MAXIMALER SPEICHERVERBRAUCH: 1GiBeispiel für angeforderte und Grenzressourcen
Feld resources.requested aus der Pod-Spezifikation — ein Element, das zur Suche nach dem gewünschten Knoten verwendet wird. Auf diesem kann bereits die Bereitstellung des Pods geplant werden. Wie wird der passende Knoten gefunden?
Kubernetes besteht aus mehreren Komponenten und enthält unter anderem einen Master-Knoten (Kubernetes Control Plane). Auf dem Master-Knoten laufen mehrere Prozesse: kube-apiserver, kube-controller-manager und kube-scheduler.
Der kube-scheduler ist verantwortlich für die Überprüfung neu erstellter Pods und die Suche nach geeigneten Knoten, die allen Anforderungen der Pods, einschließlich der angeforderten Ressourcenmenge, entsprechen. Die vom kube-scheduler gefundenen Knoten werden bewertet. Der Pod wird auf dem Knoten mit den höchsten Punktzahlen geplant.
Wo wird der lila Pod platziert?
Auf dem Bild sieht man, dass der kube-scheduler einen neuen lila Pod planen muss. Das Kubernetes-Cluster enthält zwei Knoten: A und B. Wie man erkennen kann, kann der kube-scheduler den Pod nicht auf Knoten A planen — die verfügbaren (nicht angeforderten) Ressourcen entsprechen nicht den Anforderungen des lila Pods. So passt der angeforderte lila Pod mit 1 GB RAM nicht auf Knoten A, da der verfügbare Speicher 0,5 GB beträgt. Knoten B hat jedoch genügend Ressourcen. Schließlich entscheidet der kube-scheduler, dass das Ziel des lila Pods Knoten B ist.
Jetzt wissen wir, wie die angeforderten Ressourcen die Auswahl des Knotens für die Ausführung des Pods beeinflussen. Aber welchen Einfluss haben die maximalen Ressourcen?
Grenzwerte sind die Schwellen, die CPU/MEM nicht überschreiten kann. CPU-Ressourcen sind jedoch flexibel, daher führen Container, die die CPU-Grenzwerte erreicht haben, nicht zur Beendigung des Pods. Stattdessen wird eine CPU-Drosselung aktiviert. Wird jedoch das Limit für die Nutzung von MEM erreicht, wird der Container vom OOM-Killer gestoppt und neu gestartet, sofern dies durch die Einstellungsoption RestartPolicy erlaubt ist.
Geforderte und Grenzressourcen im Detail
Verbindung von Ressourcen zwischen Docker und Kubernetes
Der beste Weg, um zu erklären, wie geforderte und Grenzressourcen funktionieren, besteht darin, die Verbindung zwischen Kubernetes und Docker darzustellen. Im obigen Bild sehen Sie, wie die Kubernetes-Felder und die Docker-Startflags miteinander verbunden sind.
Speicher: Anfrage und Grenzwert
containers:
...
resources:
requests:
memory: "0.5Gi"
limits:
memory: "1Gi"
Wie bereits erwähnt, wird der Speicher in Bytes gemessen. Basierend auf , können wir den Speicher als Zahl angeben. Normalerweise ist es ganzzahlig, wie z. B. 2678 — das sind 2678 Bytes. Es können auch Suffixe verwendet werden, G und Gi, wichtig ist, dass sie nicht gleichwertig sind. Das erste ist dezimal, das zweite binär. Zum Beispiel, wie in der k8s-Dokumentation erwähnt: 128974848, 129e6, 129M, 123Mi — sie sind nahezu äquivalent.
Kubernetes-Parameter limits.memory entspricht dem Flag --memory von Docker. Bei request.memory ist die Angabe für Docker nicht vorhanden, da Docker dieses Feld nicht verwendet. Sie können fragen, ob das überhaupt notwendig ist? Ja, es ist notwendig. Wie bereits erwähnt, ist das Feld für Kubernetes von Bedeutung. Basierend auf diesen Informationen entscheidet der kube-scheduler, auf welchem Knoten er das Pod planen soll.
Was passiert, wenn für die Anfrage nicht genügend Speicher eingestellt wird?
Wenn der Container die Grenzen des angeforderten Speichers erreicht, wird das Pod in eine Gruppe von Pods eingestuft, die aufgrund von Speichermangel auf dem Knoten gestoppt werden.
Was passiert, wenn ein zu niedriger Grenzwert für den Speicher eingestellt wird?
Wenn der Container den Grenzwert für den Speicher überschreitet, wird er wegen OOM-Killed beendet. Und er wird neu gestartet, wenn dies basierend auf der RestartPolicy möglich ist, wobei der Standardwert — Always.
Was passiert, wenn kein angeforderter Speicher angegeben wird?
Kubernetes übernimmt den Grenzwert und setzt ihn als Standardwert.
Was kann passieren, wenn kein Grenzwert für den Speicher angegeben wird?
Ein Container hat keine Einschränkungen und kann so viel Speicher verwenden, wie er möchte. Wenn er jedoch den gesamten verfügbaren Speicher des Knotens verwendet, wird er durch OOM (Out of Memory) beendet. Anschließend wird der Container neu gestartet, sofern dies gemäß der RestartPolicy möglich ist.
Was passiert, wenn keine Speicherkapazitäten angegeben werden?
Das ist das schlechteste Szenario: Der Scheduler weiß nicht, wie viele Ressourcen der Container benötigt, was ernsthafte Probleme am Knoten verursachen kann. In diesem Fall wäre es gut, Standardbeschränkungen im Namespace zu haben (festgelegt durch LimitRange). Es gibt keine Standardbeschränkungen – der Pod hat keine Beschränkungen und kann so viel Speicher verwenden, wie er möchte.
Wenn der angeforderte Speicher größer ist als das, was der Knoten anbieten kann – wird der Pod nicht eingeplant. Es ist wichtig zu beachten, dass Requests.memory kein Minimalwert ist. Dies beschreibt das Speichervolumen, das für den kontinuierlichen Betrieb des Containers ausreicht.
Es wird allgemein empfohlen, denselben Wert für request.memory und limit.memoryfestzulegen. Dadurch wird verhindert, dass Kubernetes einen Pod auf einem Knoten plant, der zwar genügend Speicher für die Ausführung des Pods hat, aber nicht genügend für dessen Betrieb. Beachten Sie: Bei der Planung von Pods berücksichtigt Kubernetes nur requests.memory, und limits.memory wird nicht berücksichtigt.
CPU: Anfrage und Begrenzung
containers:
...
resources:
requests:
cpu: 1
limits:
cpu: "1200m"
Für C CPU ist es etwas komplizierter. Wenn wir auf das Bild mit der Beziehung zwischen Kubernetes und Docker zurückblicken, können wir feststellen, dass request.cpu entspricht --cpu-shareswährend limit.cpu entspricht dem Flag cpus in Docker.
Die von Kubernetes angeforderte CPU wird mit 1024 multipliziert — der Verhältnis von CPU-Zyklen. Wenn Sie ein volles Kern anfordern möchten, müssen Sie hinzufügen cpu: 1, wie oben gezeigt.
Die Anfrage nach einem vollen Kern (Verhältnis = 1024) bedeutet nicht, dass Ihr Container ihn erhält. Wenn Ihr Host-Rechner nur einen Kern hat und Sie mehr als einen Container verwenden, müssen sich alle Container die verfügbare CPU teilen. Wie funktioniert das? Schauen wir uns das Bild an.

CPU-Anfrage — System mit einem Kern
Stellen wir uns vor, dass Sie ein Host-System mit einem Kern haben, auf dem Container laufen. Mama (Kubernetes) hat einen Kuchen (CPU) gebacken und möchte ihn unter den Kindern (Containern) aufteilen. Drei Kinder wollen einen ganzen Kuchen (Verhältnis = 1024), während ein weiteres Kind eine halbe Torte will (512). Mama möchte gerecht sein und führt eine einfache Berechnung durch.
# Сколько пирогов хотят дети?
# 3 ребенка хотят по целому пирогу и еще один хочет половину пирога
cakesNumberKidsWant = (3 * 1) + (1 * 0.5) = 3.5
# Выражение получается так:
3 (ребенка/контейнера) * 1 (целый пирог/полное ядро) + 1 (ребенок/контейнер) * 0.5 (половина пирога/половина ядра)
# Сколько пирогов испечено?
availableCakesNumber = 1
# Сколько пирога (максимально) дети реально могут получить?
newMaxRequest = 1 / 3.5 =~ 28%Aus der Berechnung ergibt sich, dass drei Kinder jeweils 28 % eines Kerns erhalten, anstatt einen ganzen Kern. Das vierte Kind bekommt 14 % eines vollen Kerns, nicht die Hälfte. Doch alles wird anders, wenn Sie ein Multi-Core-System haben.

Anfrage CPU — Multi-Core (4) System
Auf dem obigen Bild ist zu sehen, dass drei Kinder einen ganzen Kuchen wollen, während eines die Hälfte möchte. Da Mama vier Kuchen gebacken hat, erhält jedes ihrer Kinder so viel, wie es möchte. In einem Multi-Core-System werden die CPU-Ressourcen auf alle verfügbaren Kerne verteilt. Wenn ein Container auf weniger als einen ganzen CPU-Kern beschränkt ist, kann er trotzdem 100 % davon nutzen.
Die obigen Berechnungen sind vereinfacht, um zu verstehen, wie die CPU zwischen Containern verteilt wird. Natürlich gibt es neben den Containern auch andere Prozesse, die CPU-Ressourcen nutzen. Wenn Prozesse in einem Container untätig sind, können andere deren Ressourcen verwenden. CPU: "200m" entspricht CPU: 0,2, was etwa 20 % eines Kerns entspricht.
Jetzt lassen Sie uns über limit.cpu. Die CPU, die Kubernetes einschränkt, wird mit 100 multipliziert. Das Ergebnis ist die Zeit, die der Container alle 100 μs nutzen kann (cpu-periode).
limit.cpu entspricht dem Docker-Flag --cpus. Dies ist eine neue Kombination alter --cpu-periode und --cpu-quota. Durch die Festlegung geben wir an, wie viele verfügbare CPU-Ressourcen der Container maximal nutzen kann, bevor es zu Drosselungen kommt:
- cpus — Kombination
cpu-periodeundcpu-quota. cpus = 1.5entspricht der Festlegungcpu-periode = 100000undcpu-quota = 150000; - cpu-periode — Zeitraum , standardmäßig 100 Mikrosekunden;
- cpu-quota — die Anzahl an Mikrosekunden innerhalb
cpu-periode, die der Container eingeschränkt ist.
Was passiert, wenn zu wenig angeforderte CPU eingestellt wird?
Wenn der Container mehr benötigt, als eingestellt ist, stiehlt er CPU von anderen Prozessen.
Was passiert, wenn ein unzureichendes CPU-Limit festgelegt wird?
Da die CPU-Ressource reguliert ist, wird das Drosseln aktiviert.
Was passiert, wenn kein CPU-Request angegeben wird?
Wie bei Arbeitsspeicher entspricht der Wert des Requests dem Limit.
Was passiert, wenn kein CPU-Limit angegeben wird?
Der Container verwendet so viel CPU, wie er benötigt. Wenn im Namensraum eine Standard-CPU-Richtlinie (LimitRange) definiert ist, wird dieses Limit auch für den Container verwendet.
Was passiert, wenn weder ein Request noch ein Limit für die CPU angegeben wird?
Wie bei Speicher ist auch hier das Worst-Case-Szenario. Der Scheduler weiß nicht, wie viele Ressourcen Ihr Container benötigt, und das kann ernsthafte Probleme auf dem Node verursachen. Um dies zu vermeiden, sollten Sie Standardgrenzen für Namespaces (LimitRange) festlegen.
Denken Sie daran: Wenn Sie mehr CPU anfordern, als die Nodes bereitstellen können, wird das Pod nicht geplant. Requests.cpu ist nicht der Mindestwert, sondern der Wert, der ausreicht, um das Pod zu starten und ohne Unterbrechungen zu arbeiten. Wenn die Anwendung keine komplexen Berechnungen durchführt, ist es am besten, request.cpu <= 1 festzulegen und so viele Replikate zu starten, wie nötig sind.
Die ideale Anzahl an angeforderten Ressourcen oder Ressourcenlimits
Wir haben von der Begrenzung der Rechenressourcen gelernt. Jetzt ist es an der Zeit, die Frage zu beantworten: "Wie viele Ressourcen benötigt mein Pod, um die Anwendung ohne Probleme auszuführen? Wie viel ist ideal?".
Leider gibt es auf diese Fragen keine eindeutigen Antworten. Wenn Sie nicht wissen, wie Ihre Anwendung funktioniert und wie viel CPU oder Arbeitsspeicher sie benötigt, ist es am besten, der Anwendung viel Speicher und CPU zur Verfügung zu stellen und dann Leistungstests durchzuführen.
Neben den Leistungstests sollten Sie eine Woche lang das Verhalten der Anwendung im Monitoring beobachten. Wenn die Grafiken zeigen, dass Ihre Anwendung weniger Ressourcen verbraucht, als Sie angefordert haben, können Sie die angeforderte CPU- oder Speichermenge reduzieren.
Als Beispiel sehen Sie dieses . Es zeigt den Unterschied zwischen den angeforderten Ressourcen oder dem Ressourcenlimit und der aktuellen Ressourcennutzung.
Fazit
Die Anforderung und das Limit von Ressourcen helfen, die Funktionsfähigkeit des Kubernetes-Clusters aufrechtzuerhalten. Eine richtige Konfiguration der Limits minimiert die Kosten und hält die Anwendungen ständig betriebsbereit.
Kurz gesagt, müssen Sie einige Punkte beachten:
- Die angeforderten Ressourcen sind die Konfiguration, die beim Start berücksichtigt wird (wenn Kubernetes die Platzierung der Anwendung plant). Im Gegensatz dazu ist das Ressourcenlimit während des Betriebs wichtig, wenn die Anwendung bereits auf einem Knoten ausgeführt wird.
- Im Vergleich zum Speicher ist die CPU eine regulierte Ressource. Bei CPU-Mangel wird Ihr Pod nicht beendet, sondern der Drosselungsmechanismus wird aktiviert.
- Die angeforderten Ressourcen und Ressourcengrenzen sind keine Mindest- und Höchstwerte! Durch die Festlegung der angeforderten Ressourcen garantieren Sie, dass die Anwendung reibungslos funktioniert.
- Es ist eine gute Praxis, die angeforderte Speichermenge gleich der Speichergrenze zu setzen.
- Es ist gut, die angeforderte
CPU <=1, wenn die Anwendung keine komplexen Berechnungen durchführt. - Wenn Sie mehr Ressourcen anfordern, als auf dem Knoten verfügbar sind, wird der Pod niemals auf diesem Knoten geplant.
- Um die richtige Anzahl an angeforderten Ressourcen/Ressourcengrenzen zu bestimmen, nutzen Sie Lasttests und Monitoring.
Ich hoffe, dieser Artikel hilft Ihnen, das grundlegende Konzept der Ressourcenkontrolle zu verstehen. So können Sie dieses Wissen in Ihrer Arbeit anwenden.
Viel Erfolg!
Weitere Leseempfehlungen:
- .
- .
- .
Quelle: habr.com
