In modernen Kubernetes-Umgebungen wird oft erwartet, dass Ressourcen effizient und dynamisch verteilt werden, um optimale Leistung bei minimalem Ressourcenverbrauch zu erzielen. Ein häufiges und zugleich verwirrendes Problem für Administratoren und DevOps-Teams ist das Phänomen, dass scheinbar inaktive oder leerlaufende Pods plötzlich CPU-Drosselungen (Throttling) erfahren. Dieses unerwartete Verhalten kann zu Alarmen in der Überwachung führen, ohne dass offensichtlich eine Überlastung vorliegt. Um zu verstehen, warum Kubernetes eigentlich Leerlauf-Pods drosseln kann, ist es wichtig, die Grundlagen des CPU-Managements im Kubernetes-Ökosystem sowie die zugrundeliegenden Linux-Mechanismen zu verstehen. Kubernetes basiert bei seiner Ressourcenverwaltung für CPUs auf dem Linux Completely Fair Scheduler (CFS), der CPU-Zeit in kontrollierten Zeitperioden von standardmäßig 100 Millisekunden verteilt.
Da Container CPU-Ressourcen in Kubernetes durch sogenannte CPU Requests und CPU Limits definiert werden, sind diese Parameter entscheidend für das Verhalten der CPU-Zuteilung und -Beschränkung eines Containers. Ein CPU Request definiert dabei, wie viel CPU-Zeit einem Container garantiert wird, während ein CPU Limit eine Obergrenze darstellt, wie viel CPU der Container maximal nutzen darf. Was viele Nutzer überraschen kann, ist die Tatsache, dass das Setzen eines CPU Limits zu häufigem Throttling selbst bei niedriger durchschnittlicher CPU-Nutzung führen kann. Dieses Phänomen wird vor allem durch die Art und Weise verursacht, wie CPU-Nutzung und Throttling berechnet und angezeigt werden. Überwachungswerkzeuge wie Grafana liefern oft Durchschnittswerte über einen bestimmten Zeitraum, wodurch kurze und intensive CPU-Spitzen geglättet werden.
Diese Spitzen können jedoch in jedes 100-Millisekunden-Zeitfenster fallen, in denen die Container ihr CPU-Limit erreichen, was in der Folge zu einem hohen Anteil an gedrosselten Perioden führt, während die durchschnittliche Auslastung dennoch niedrig erscheint. Dies erklärt, warum man in Metriken eine nahezu idle CPU-Auslastung sehen kann, aber gleichzeitig eine deutlich spürbare Drosselung auftritt. Um die Ursache dieses scheinbaren Widerspruchs zu verifizieren, ist ein tiefes Verständnis der erzeugten CPU-Metriken nötig. Kubernetes nutzt für CPU-Statistiken Prometheus als Monitoring-Tool, das die Werte oft von cAdvisor erhält. cAdvisor liest jegliche CPU-bezogenen Daten direkt aus cGroup-Dateisystemen eines Containers.
Diese Daten umfassen den gesamten CPU-Zeitverbrauch, die Anzahl der Zeitperioden, in denen ein Container CPU-Zeit nutzte, sowie die Anzahl der Perioden, in denen CPU-Throttling durchgesetzt wurde. Die zentrale Metrik container_cpu_usage_seconds_total zeigt die kontinuierliche Gesamtsumme der von einem Container verbrauchten CPU-Zeit an. Die Berechnung der aktuellen CPU-Auslastung erfolgt über die Änderung dieser Summe innerhalb einer definierten Zeitspanne, meist durch den irate-Funktion in Prometheus. Das CPU-Throttling wird als Verhältnis der throttled Perioden zu den insgesamt genutzten CPU-Perioden berechnet. Dabei basiert diese Berechnung auf den Metriken container_cpu_cfs_throttled_periods_total und container_cpu_cfs_periods_total.
Eine hohe Rate an throttled Perioden im Verhältnis zu genutzten Perioden zeigt an, dass die CPU-Nutzung häufig durch das Limit gedrosselt wird. In der Praxis ist es empfehlenswert, die eigentlichen cGroup-Dateien zu inspizieren, um eine detailliertere Ansicht zu erhalten. Der Zugriff zum Beispiel auf cpu.stat Dateien innerhalb eines Pods verrät genaue Zahlen zu Nutzung, Throttling-Zeiten und Anzahl der Perioden. Ein Vergleich der Werte vor und nach einer Änderung der CPU-Limits kann Aufschluss über das Ausmaß des Problems geben.
Ein praktischer Lösungsansatz zeigt sich im Entfernen der CPU-Limits. Durch das Weglassen der Obergrenzen kann der Container kurzfristig mehr CPU-Zeit erhalten, sofern diese auf dem Node verfügbar ist. Dadurch verschwindet das Throttling bei den kurzzeitigen Spitzen und die CPU-Auslastung wird nicht mehr künstlich beschränkt. Genau dieses Vorgehen wurde in einem Fall in einer Produktionsumgebung getestet, in der ein Netzwerkpolicy-Daemonset trotz niedriger Durchschnittsauslastung hohe Throttling-Raten zeigte. Nach dem Entfernen der CPU-Limits traten die Drosselungen innerhalb kürzester Zeit nicht mehr auf.
Ein weiteres Beispiel für die Entstehung von Throttling bei Idle-Pods kann durch synthetische Lasttests mit Tools wie sysbench simuliert werden. Hierbei erzeugt sysbench kurze CPU-Spitzenperioden, gefolgt von Phasen der Inaktivität. Wird dabei ein CPU-Limit gesetzt, kommt es an den kurzen Spikes zum Throttling, obwohl die durchschnittliche CPU-Nutzung über die gesamte Laufzeit gering bleibt. Dieses Verhalten verdeutlicht das Konfliktpotenzial zwischen der zeitlichen Verteilung von CPU-Spitzen und statischen Limits. Die Kubernetes-Community arbeitet an verbesserten Mechanismen, um diese Konflikte zukünftig besser zu adressieren.
Eine vielversprechende Entwicklung sind burstartige CPU-Limits, die ein aufgespartes CPU-Quota erlauben, welches in leerlaufenden Phasen akkumuliert und in Spitzenphasen genutzt werden kann. Obwohl diese Funktionalität aktuell noch nicht vollumfänglich in Kubernetes implementiert ist, wird sie perspektivisch die Notwendigkeit restriktiver, statischer CPU-Limits reduzieren und eine dynamischere CPU-Verteilung erlauben. Aufgrund der Komplexität und der feinen Abstimmung zwischen CPU Request, Limit, Scheduler und Linux-CFS ist es für Administratoren essenziell, die beobachteten Metriken genau zu verstehen. Allgemein gilt, dass CPU-Limits bei Pods mit spitzenhafter, unregelmäßiger Last mit Vorsicht zu verwenden sind. Eine Überwachung mit ausreichender Granularität, idealerweise unter Einbeziehung der cGroup-Metriken und nicht nur aggregierter Dashboard-Werte, hilft, das tatsächliche Verhalten besser einzuschätzen.
Zusammenfassend lässt sich sagen, dass hohe CPU-Drosselungen bei scheinbar idle Pods kein Anzeichen für ein Monitoring-Fehler sind. Vielmehr spiegeln sie die Funktionsweise des Linux-CFS und die konservative Verteilung von CPU-Ressourcen durch Kubernetes-CPU-Limits wider. Wer diese Mechanismen kennt, kann proaktiv handeln, indem er die CPU-Limits anpasst oder entfernt und so das Throttling bei CPU-Spitzen vermeidet. Dabei ist es wichtig, stets das Gesamtbild der Cluster-Auslastung im Auge zu behalten, denn das Entfernen von Limits birgt auch die Gefahr einer Überbeanspruchung der Knoten-Ressourcen, wenn Pod-Auslastung nicht genau überwacht wird. Die perfekte Lösung wird wahrscheinlich eine Kombination aus intelligentem Ressourcenmanagement, verbessertem Kubernetes-Support für burstfähige CPU-Limits und einem tiefen Verständnis der Anwendungslast sein.
Bis dahin bleibt die manuelle Analyse der CPU-Metriken und ein bewusster Umgang mit CPU-Limits die beste Methode, um ungewolltes Throttling bei Leerlauf-Pods zu vermeiden und die Leistung des Clusters zu optimieren.