Kubernetes Requests und Limits

In diesem Beitrag geht es um die Konfiguration von Requests und Limits in einem Kubernetes-Cluster und wie diese die Performance und Stabilität des Clusters beeinflussen können. 

Request und Limits

Die Requests / Limits sind optionale Konfigurationsmöglichkeiten, die zur Optimierung der Ressourcennutzung verwendet werden können.  Requests / Limits müssen nicht konfiguriert werden.  Je nach Anwendung oder Situation können die Requests / Limits die Stabilität der einen oder anderen Anwendung positiv oder negativ beeinflussen. Diese Einstellung ist als zweischneidiges Schwert zu betrachten.

Request: In einem Request wird angegeben, wie viel CPU oder RAM für den Container mindestens erforderlich ist.

Limit: Mit einem Limit wird die maximale CPU- oder RAM-Nutzung des Containers festgelegt.

Das Thema "Requests / Limits für CPU und Speicher" ist sehr detaliert in diesem Beitrag bereits beschrieben: Optimale Nutzung von CPU- und Memory-Ressourcen in vSphere with Tanzu

 

Wenn keine Request und Limits konfiguriert sind...

Normalerweise werden in Kubernetes für alle Pods sowohl die Requests als auch Limits für CPU und Memory definiert. Diese Einstellungen helfen dabei, die Ressourcennutzung innerhalb des Clusters optimal zu steuern. Wenn diese Requests / Limits-Werte nicht festgelegt sind, können Pods potenziell mehr Ressourcen beanspruchen, als für ihre Funktion tatsächlich erforderlich ist. Dies kann zu einer ungleichmäßigen Ressourcenverteilung führen. Einige Pods können mehr Ressourcen erhalten, als sie benötigen, während andere möglicherweise zu wenig bekommen. Solche Fehlkonfigurationen können zu Performanceproblemen im Cluster führen und als Folge die Effizienz des Systems beeinträchtigen.

 

Wenn Request und Limits konfiguriert sind...

Requests

Beginnen wir mit den Requests. Wollte man die Requests in einem Satz beschreiben, so könnte dieser lauten: Die Requests dienen zwei Zwecken, erstens einen geeigneten Knoten mit ausreichender Kapazität zu finden und zweitens die Gesamtmenge der benötigten Ressourcen zu berechnen.

Mögliche Probleme mit den konfigurierten Requests werden erst sichtbar, wenn diese falsch konfiguriert sind. Dies betrifft sowohl zu niedrig als auch zu hoch eingestellte Requests.

Wenn die Requests für einen Pod zu niedrig eingestellt sind, als der Pod tatsächlich benötigt, werden diese Pods durch Scheduler auf den Knoten platziert, die dafür möglicherweise gar nicht geeignet sind. Dies kann dazu führen, dass die tatsächlich zur Verfügung stehenden Ressourcen schnell überschritten werden, was in der Folge zu Leitungsproblemen führt. Theoretisch könnte dies unter anderem zu Verzögerungen beim Start von Apps führen, da der Scheduler noch einen geeigneten Knoten finden muss.

Wenn die Ressourcen schnell überschritten werden, reagiert Kubernetes mit mehr oder weniger drastischen Mitteln, die eher in den Bereich „Limits“ fallen.

Limits

Wenn die Ressource die durch die Limits festgelegte Grenze erreicht, werden bestimmte Ereignisse ausgelöst, die unterschiedliche Auswirkungen auf die CPU und den Speicher haben. CPU-Throttling und Out-of-Memory-Kills sind die bekanntesten.

CPU-Throttling

CPU-Throttling bedeutet, dass die CPU-Nutzung eines Containers gedrosselt wird, wenn er sein CPU-Limit überschreitet. Das CPU-Throttling wird durch sogenannte "Throttling-Perioden" geregelt. Die "Throttling-Periode" ist ein Mechanismus zur Überprüfung der CPU-Nutzung des Containers in regelmäßigen Abständen (standardmäßig 100ms). Aus technischer Sicht sind die cgroups (Linux-Funktionen) die CPU-Drosselung zuständig.

Wenn z.B. ein Container ein Limit von "500m" hat, was 50% eines CPU-Kerns entspricht. Das bedeutet, dass dieser Container in jeder Throttling-Periode (100ms) bis zu 50ms CPU-Zeit verbrauchen (ebenfalls 50%) darf.  Hätte ein Container ein Limit von "300m" (30% eines CPU-Kerns), so hätte er Anspruch auf 30ms CPU-Zeit.

Kubernetes Requests Limits CPU

  1. Für einen Container reservierter CPU-Anteil.
  2. Maximale CPU-Auslastung für den Container.
  3. Grenzwert, bei dem das CPU-Throttling beginnt.

Die potentiellen Probleme des CPU-Throttling lassen sich anhand des folgenden Beispiels noch besser verdeutlichen:

Eine Funktion einer Applikation benötigt normalerweise 80ms CPU-Zeit, um ihre Tasks abzuschließen.

  • CPU-Limit: 500m
  • Throttling-Periode: 100ms
  • Verfügbare CPU-Zeit pro Periode: 50ms (50%)

Ohne CPU-Limit hätte der Container die 80ms CPU-Zeit-Aufgabe direkt abgearbeitet.

Andernfalls werden die CPU-Limits wie folgt auswirken:

  • Erste Periode (100ms): 50ms Arbeitszeit und wird dann gedrosselt.
  • Zweite Periode (nächste 100ms): die restlichen 30ms werden abgearbeitet.

Die CPU-Limits können zu Leistungseinbußen und längeren Antwortzeiten der Anwendung führen. Je mehr Iterationen eine Anwendung benötigt, desto schlechter sind die Performance-Werte. Dabei spielt es keine Rolle, ob die CPU des Nodes grundsätzlich ausgelastet ist oder nicht.

Out-Of-Memory (OOM)

Wenn ein Container mehr Speicher (RAM) anfordert, als ihm durch Limit zur Verfügung steht, wird er durch den OOM-Killer beendet und neu gestartet. Solche unerwarteten Neustarts können zu Instabilität und Datenverlust der Anwendung führen.

Kubernetes Requests Limits Memory

  1. Maximale Menge an Memory, die für den Container reserviert ist
  2. Maximaler Memory-Verbrauch für den Container
  3. Out-of-Memory greift ein und startet den Pod

Suboptimale Ressourcennutzung

Es ist außer Frage, dass die Festlegung von Limits dazu beitragen kann, die Nutzung der vorhandenen Hardwareressourcen besser planen zu können.  Aber wenn die Limits zu niedrig gesetzt sind, wird nicht die gesamte verfügbare Kapazität des Clusters verbraucht. Dies führt zu unnötigen Kosten, insbesondere bei Cloud-Ressourcen.

Ein weiterer Aspekt der restriktiven Begrenzung ist die eingeschränkte Fähigkeit der Container, auf Lastspitzen zu reagieren. Damit ist das Konzept des CPU Bursting gemeint.  CPU Bursting ermöglicht die Nutzung zusätzlicher Ressourcen auf den Knoten, wenn diese verfügbar sind.

Quality of Service (QoS)

In Kubernetes gibt es drei Arten von Quality of Service (QoS) Klassen für Pods, die einen direkten Bezug zu unserem Thema haben.

Die Zuordnung der Pods zu einer oder anderen QoS-Klasse wird durch die definierten Requests und Limits sowohl für die CPUs als auch für den Speicher bestimmt.

Guaranteed

Die Zuordnung zu dieser Klasse erfolgt nur, wenn für jeden Container sowohl Requests als auch Limits für CPU/Speicher konfiguriert sind. Die Werte der Requests müssen mit den Limits übereinstimmen. Wenn dies der Fall ist, wird diesen Pods die höchste Priorität bei der Ressourcenzuteilung garantiert. 

Burstable

Zu dieser Klasse gehören Pods, bei denen mindestens ein Container ungleiche Request oder Limits für CPU/Speicher hat, oder bei denen Request, aber keine Limits gesetzt sind. CPU Throttling kann für Container mit einem definierten Limit angewendet werden. Diese Pods haben eine mittlere Priorität und können zusätzliche Ressourcen nutzen, aber nur wenn diese verfügbar sind.

BestEffort

BestEffort ist das rechtlose Mitglied der QoS-Klassen. Pods, für die weder Requests noch Limits (für CPU und Speicher) definiert sind, werden der Klasse BestEffort zugeordnet. Diese Pods haben die niedrigste Priorität und werden CPU-mäßig als die letzten bedient und sind die ersten Kandidaten, die vom OOM Killer des Betriebssystems beendet werden. 

Fazit / Empfehlung

Wenn wir das Zitat „Sein oder Nichtsein“ auf unser Thema „Requests und Limits“ anwenden, ist eine typische IT-Antwort „it depends“.

Es ist sicherlich richtig, dass die Zuweisung von Requests/Limits eine bessere Kontrolle und Planung der Ressourcennutzung im Kubernetes-Cluster ermöglicht.

Ebenso richtig ist die Aussage, dass zu restriktive oder zu niedrige Limits (insbesondere CPU-Limits) die Effizienz und Flexibilität des Clusters negativ beeinflussen können.

Die Berücksichtigung der Auswirkungen von QoS-Klassen ist äußerst wichtig, da diese einen direkten Einfluss auf die Performance und Verfügbarkeit der Pods haben. Letztendlich spielen sie eine wichtige Rolle bei der Verteilung von Workloads im Kubernetes-Cluster.

Um mögliche Probleme zu vermeiden, ist es sinnvoll, die Requests und insbesondere die Limits auf Basis realer Messungen des tatsächlichen Bedarfs und Anwendungsverhaltens zu konfigurieren.

Letztendlich ist jede Entscheidung individuell und hängt von vielen Faktoren ab, wie z.B. der Anwendungsarchitektur, den betrieblichen Anforderungen, den Leistungszielen, dem Budget etc.

 

 


Befehle zur Request- und Limits-Erkennung

Prometheus-Abfragen

Wenn Sie in Ihrer Infrastruktur auch Prometheus verwenden, können die folgenden Prometheus-Abfragen hilfreich sein.

Containern ohne CPU-Limits finden

Diese Abfrage ermittelt, welche Container in einem bestimmten Namespace keine CPU-Limits gesetzt haben.

sum by (namespace)
(count by (namespace,pod,container)(kube_pod_container_info{container!=""})
unless sum by (namespace,pod,container)(kube_pod_container_resource_limits{resource="cpu"}))

Containern mit hoher CPU-Auslastung im Verhältnis zu ihren Limits identifizieren

Diese Abfrage sucht nach Containern, deren CPU-Auslastung in den letzten 5 Minuten 80% oder mehr des CPU-Limits erreicht hat.

sum by
(namespace,pod,container)(rate(container_cpu_usage_seconds_total{container!=""}[5m])) /
sum by(namespace,pod,container)(kube_pod_container_resource_limits{resource="cpu"})) > 0.8

 

Kubectl-Befehle

Mit den folgenden Befehlen können Sie die Konfiguration der Requests und Limits Pods anzeigen und bei der Fehlersuche in diesem Bereich behilflich sein.

1. Ausgabe als eine Liste in der Console

kubectl get pods -n <namespace-name> -o=jsonpath="{range .items[*]}{'\n'}{.metadata.name}:{'\n'}{range .spec.containers[*]}{.name}{':\n'}{'  Requests: '}{.resources.requests}{'\n  Limits: '}{.resources.limits}{'\n'}{end}{end}" 

2. Ausgabe in einer Datei umleiten

kubectl get pods -n <namespace-name> -o=jsonpath="{range .items[*]}{.metadata.name}{'\t'}{range .spec.containers[*]}{.name}{'\t'}{.resources.requests.cpu}{'\t'}{.resources.limits.cpu}{'\t'}{.resources.requests.memory}{'\t'}{.resources.limits.memory}{'\n'}{end}{end}" > pod_resources.txt 

3. Die Ausgabe in Tabellenformat anzeigen:

awk 'BEGIN {FS="\t"; print "Pod Name\tContainer Name\tCPU Requests\tCPU Limits\tMemory Requests\tMemory Limits"} {print $1"\t"$2"\t"$3"\t"$4"\t"$5"\t"$6}' pod_resources.txt 

4. Überprüfung der aktuellen Ressourcennutzung:

CPU-Auslastung:  kubectl top pod -A | sort -k 3 -nr

Memory-Auslastung:  kubectl top pod -A | sort -k 4 -nr

5. Mit dem Befehl describe pod können Sie auch die Requests und Limits der ausgewählten Pods sehen.

kubectl describe pod <namespace-name>  -n <namespace-name>

6. Überprüfung, ob der Workload gleichmäßig auf die Nodes verteilt ist.

kubectl top nodes

7. So erhalten Sie einen Überblick über die eingerichteten Requests und Limits:

kubectl describe pod [Pod-Name] -n [Namespace-Name] | grep -E 'Requests|Limits' -A 2

 

Grobe Berechnung der Ressourcen

Es lohnt sich die Summe der CPU-, Memory-Requests aller Pods grob zu berechnen, damit die Gesamtkapazität des Clusters nicht überschritten wird.

Hier ist ein fiktives Beispiel, das zeigt, wie die Ressourcen eines Kubernetes-Clusters berechnet werden können.

001 Cluster Ressourcen

Stellen wir uns einen Cluster vor, der aus drei Nodes besteht, wobei jeder Node über 4 vCPUs und 8 GB RAM verfügt. Insgesamt verfügt der Cluster über 12 vCPUs und 24 GB RAM. Auf diesem Cluster sollen 100 Pods betrieben werden.

Nehmen wir weiterhin an, dass alle Pods denselben Workload ausführen müssen. Das bedeutet, dass jeder Pod maximal 120m CPU-Ressourcen und 245,76 MB Speicher nutzen könnte, um die Ressourcen gleichmäßig auf alle Pods zu verteilen.

Requests

002 Request

Die Requests könnten in unserem Beispiel etwa so aussehen: {"cpu":"60m","memory":"120Mi"}. Dies würde bedeuten, dass jeder Pod mindestens 60m CPU und 120 Mi Speicher garantiert bekommt. So kann eine gleichmäßige Ressourcenaufteilung gewährleist werden.

Limits

003 Limits

In diesem Fall wäre es sinnvoll, die Limits wie folgt zu konfigurieren: {"cpu":"120m","memory":"245Mi"}. Dies stellt sicher, dass kein Pod mehr Ressourcen verbraucht, als ihm anteilig zustehen. Es ist auch ratsam, immer einen Puffer einzuplanen und nicht die gesamte verfügbare Kapazität einzuplanen.

 

Wir nutzen Cookies auf unserer Website. Einige von ihnen sind essenziell für den Betrieb der Seite, während andere uns helfen, diese Website und die Nutzererfahrung zu verbessern (Tracking Cookies). Sie können selbst entscheiden, ob Sie die Cookies zulassen möchten. Bitte beachten Sie, dass bei einer Ablehnung womöglich nicht mehr alle Funktionalitäten der Seite zur Verfügung stehen.