Wenn bei Ihren Google Kubernetes Engine-Anwendungen (GKE) unerwartete Containerbeendigungen, Instabilität oder CrashLoopBackOff-Fehler auftreten, kann dies auf OOM-Ereignisse (Out of Memory) zurückzuführen sein. OOM-Ereignisse treten auf, wenn ein Container oder Knoten nicht mehr genügend Arbeitsspeicher hat. Der Linux-OOM-Killer beendet dann Prozesse, um Ressourcen freizugeben.
Auf dieser Seite können Sie feststellen, ob ein OOM-Ereignis auf Container- oder Knotenebene aufgetreten ist, und effektive Strategien zur Risikominderung anwenden, um ein erneutes Auftreten zu verhindern.
Diese Informationen sind wichtig für Anwendungsentwickler, die dafür sorgen müssen, dass ihre Anwendungen mit geeigneten Speicheranfragen und -limits konfiguriert sind und keine Speicherlecks aufweisen. Sie ist auch für Plattformadministratoren und -operatoren wichtig, die die Ressourcenauslastung von Knoten überwachen und dafür sorgen, dass der Cluster über genügend Speicherkapazität verfügt, um die bereitgestellten Arbeitslasten zu unterstützen. Weitere Informationen zu den gängigen Rollen und Beispielaufgaben, auf die wir in Google Cloud -Inhalten verweisen, finden Sie unter Häufig verwendete GKE-Nutzerrollen und -Aufgaben.
Häufige Ursachen für OOM-Ereignisse
OOM-Ereignisse treten in der Regel bei Last- oder Trafficspitzen auf, wenn die Speichernutzung der Anwendung stark ansteigt und das für den Container konfigurierte Speicherlimit erreicht.
Die folgenden Szenarien können ein OOM-Ereignis verursachen:
- Unzureichendes Arbeitsspeicherlimit: Die Einstellung
resources.limits.memoryim Manifest des Pods ist zu niedrig für die typischen oder maximalen Arbeitsspeicheranforderungen der Anwendung. - Nicht definierte Arbeitsspeicheranfragen oder ‑limits: Wenn weder
resources.limits.memorynochresources.requests.memorydefiniert ist, ist die Arbeitsspeichernutzung des Containers unbegrenzt. - Hohe oder unregelmäßige Last: Plötzliche, extreme Lastspitzen können die Ressourcen eines Systems, einschließlich des Arbeitsspeichers, überlasten, auch wenn die Limits normalerweise ausreichen.
- Speicherleck: Die App hat möglicherweise einen Codefehler, der dazu führt, dass der Speicher nicht ordnungsgemäß freigegeben wird.
OOM-Ereignisse können einen kaskadierenden Fehler auslösen, da weniger Container für die Verarbeitung des Traffics übrig bleiben, was die Last auf den verbleibenden Containern erhöht. Diese Container werden dann möglicherweise ebenfalls beendet.
Wie Kubernetes mit OOM-Ereignissen umgeht
Der Linux-OOM-Killer verarbeitet jedes OOM-Ereignis. Der OOM-Killer ist ein Kernel-Prozess, der aktiviert wird, wenn der Arbeitsspeicher des Systems kritisch niedrig ist. Sein Zweck besteht darin, einen vollständigen Systemabsturz zu verhindern, indem Prozesse strategisch beendet werden, um Ressourcen freizugeben. Der Kernel verwendet ein Bewertungssystem, um auszuwählen, welcher Prozess beendet werden soll. Ziel ist es, die Systemstabilität zu erhalten und Datenverluste zu minimieren.
In einer Kubernetes-Umgebung arbeitet der OOM-Killer in zwei verschiedenen Bereichen: der Kontrollgruppe (cgroup), die sich auf einen Container auswirkt, und dem System, das sich auf den gesamten Knoten auswirkt.
Beendigung aufgrund von Arbeitsspeichermangel auf Containerebene
Ein OOM-Kill auf Containerebene tritt auf, wenn ein Container versucht, sein vordefiniertes Speicherlimit zu überschreiten. Kubernetes weist jeden Container einer bestimmten cgroup mit einem harten Arbeitsspeicherlimit zu. Wenn die Speichernutzung eines Containers dieses Limit erreicht, versucht der Kernel zuerst, Speicher innerhalb dieser cgroup freizugeben. Wenn der Kernel mit diesem Prozess nicht genügend Speicher freigeben kann, wird der cgroup-OOM-Killer aufgerufen. Er beendet Prozesse innerhalb dieser spezifischen cgroup, um die Ressourcengrenze durchzusetzen.
Wenn der Hauptprozess in einem Container auf diese Weise beendet wird, beobachtet Kubernetes das Ereignis und markiert den Status des Containers als OOMKilled. Die konfigurierte restartPolicy des Pods bestimmt dann das Ergebnis:
AlwaysoderOnFailure: Der Container wird neu gestartet.Never: Der Container wird nicht neu gestartet und bleibt im Status „Beendet“.
Durch die Isolierung des Fehlers auf den fehlerhaften Container verhindert der OOM-Killer, dass ein einzelner fehlerhafter Pod den gesamten Knoten zum Absturz bringt.
Auswirkungen der cgroup-Version auf das Verhalten von OOM Killer
Das OOM-Kill-Verhalten kann sich zwischen cgroup-Versionen erheblich unterscheiden. Wenn Sie sich nicht sicher sind, welche cgroup-Version Sie verwenden, prüfen Sie den cgroup-Modus der Clusterknoten.
In
cgroup v1kann ein OOM-Ereignis innerhalb der Speicher-cgroup eines Containers zu unvorhersehbarem Verhalten führen. Der OOM-Killer kann jeden Prozess innerhalb dieser cgroup beenden, einschließlich untergeordneter Prozesse, die nicht der Hauptprozess des Containers (PID 1) sind.Dieses Verhalten stellt eine erhebliche Herausforderung für Kubernetes dar. Da Kubernetes hauptsächlich den Zustand des Hauptcontainerprozesses überwacht, bleiben diese „partiellen“ OOM-Kills unbemerkt. Der Hauptcontainerprozess wird möglicherweise weiter ausgeführt, auch wenn kritische untergeordnete Prozesse beendet wurden. Dieses Verhalten kann zu subtilen App-Fehlern führen, die für Kubernetes oder Operatoren nicht sofort sichtbar sind, aber im Systemjournal des Knotens (
journalctl) sichtbar sind.cgroup v2bietet ein besser vorhersehbares OOM-Killer-Verhalten.Um die Integrität der Arbeitslast in einer cgroup v2-Umgebung zu gewährleisten, verhindert der OOM-Killer teilweise Beendigungen und sorgt für eines von zwei Ergebnissen: Entweder werden alle Aufgaben, die zu dieser cgroup und ihren Nachfolgern gehören, beendet (wodurch der Fehler für Kubernetes sichtbar wird), oder wenn die Arbeitslast keine Aufgaben hat, die zu viel Arbeitsspeicher verbrauchen, bleibt die Arbeitslast unberührt und wird ohne unerwartete interne Prozessbeendigungen weiter ausgeführt.
Für Szenarien, in denen Sie das
cgroup v1-Verhalten des Beendens eines einzelnen Prozesses wünschen, bietet das Kubelet das FlagsingleProcessOOMKillfürcgroup v2. Dieses Flag bietet eine detailliertere Steuerung, da bei einem OOM-Ereignis einzelne Prozesse beendet werden können, anstatt die gesamte cgroup.
OOM-Beendigung auf Systemebene
Ein OOM-Kill auf Systemebene ist ein schwerwiegenderes Ereignis, das auftritt, wenn der gesamte Knoten und nicht nur ein einzelner Container keinen verfügbaren Arbeitsspeicher mehr hat. Dieses Ereignis kann auftreten, wenn die kombinierte Arbeitsspeichernutzung aller Prozesse (einschließlich aller Pods und System-Daemons) die Kapazität des Knotens überschreitet.
Wenn dieser Knoten Out of Memory ist, bewertet der globale OOM Killer alle Prozesse auf dem Knoten und beendet einen Prozess, um Arbeitsspeicher für das gesamte System freizugeben. Der ausgewählte Prozess ist in der Regel kurzlebig und verbraucht viel Arbeitsspeicher.
Um schwerwiegende OOM-Situationen zu vermeiden, verwendet Kubernetes die Knotendruck-Entfernung, um Knotenressourcen zu verwalten. Dabei werden weniger kritische Pods von einem Knoten entfernt, wenn Ressourcen wie Arbeitsspeicher oder Speicherplatz kritisch knapp werden. Ein OOM-Kill auf Systemebene weist darauf hin, dass dieser Bereinigungsvorgang nicht schnell genug Speicher freigeben konnte, um das Problem zu verhindern.
Wenn der OOM-Killer den Prozess eines Containers beendet, ist der Effekt in der Regel identisch mit einem von einer cgroup ausgelösten Kill: Der Container wird als OOMKilled markiert und gemäß seiner Richtlinie neu gestartet. Wenn jedoch ein kritischer Systemprozess beendet wird (was selten vorkommt), kann der Knoten selbst instabil werden.
OOM-Ereignisse untersuchen
In den folgenden Abschnitten erfahren Sie, wie Sie ein OOM-Ereignis erkennen und bestätigen. Dabei beginnen Sie mit den einfachsten Kubernetes-Tools und gehen dann zu einer detaillierteren Loganalyse über.
Pod-Status auf sichtbare OOM-Ereignisse prüfen
Der erste Schritt zur Bestätigung eines OOM-Ereignisses besteht darin, zu prüfen, ob Kubernetes das OOM-Ereignis beobachtet hat. Kubernetes beobachtet das Ereignis, wenn der Hauptprozess des Containers beendet wird. Dies ist das Standardverhalten in cgroup v2-Umgebungen.
Prüfen Sie den Pod-Status:
kubectl describe pod POD_NAMEErsetzen Sie
POD_NAMEdurch den Namen des Pods, den Sie sich prüfen möchten.Wenn ein sichtbares OOM-Ereignis aufgetreten ist, sieht die Ausgabe in etwa so aus:
... Last State: Terminated Reason: OOMKilled Exit Code: 137 Started: Tue, 13 May 2025 19:05:28 +0000 Finished: Tue, 13 May 2025 19:05:30 +0000 ...
Wenn im Feld Reason der Wert OOMKilled angezeigt wird, haben Sie das Ereignis bestätigt. Ein Exit Code-Wert von 137 weist ebenfalls auf einen OOM-Kill hin. Wenn das Feld Reason einen anderen Wert hat oder der Pod trotz Anwendungsfehlern weiterhin ausgeführt wird, fahren Sie mit dem nächsten Abschnitt fort, um weitere Untersuchungen durchzuführen.
Protokolle nach unsichtbaren OOM-Ereignissen durchsuchen
Ein OOM-Kill ist für Kubernetes „unsichtbar“, wenn ein untergeordneter Prozess beendet wird, der Hauptcontainerprozess aber weiter ausgeführt wird (ein häufiges Szenario in cgroup v1-Umgebungen). Sie müssen die Logs des Knotens durchsuchen, um Belege für diese Ereignisse zu finden.
So finden Sie unsichtbare OOM-Kills mit dem Log-Explorer:
Rufen Sie in der Google Cloud Console den Log-Explorer auf.
Geben Sie im Abfragebereich eine der folgenden Abfragen ein:
Wenn Sie bereits einen Pod haben, bei dem Ihrer Meinung nach ein OOM-Ereignis aufgetreten ist, fragen Sie diesen bestimmten Pod ab:
resource.type="k8s_node" jsonPayload.MESSAGE:(("POD_NAME" AND "ContainerDied") OR "TaskOOM event") resource.labels.cluster_name="CLUSTER_NAME"Ersetzen Sie Folgendes:
POD_NAME: der Name des Pods, den Sie abfragen möchten.CLUSTER_NAME: der Name des Clusters, zu dem der Pod gehört.
Wenn Sie herausfinden möchten, bei welchen Pods oder Knoten ein OOM-Ereignis aufgetreten ist, fragen Sie alle GKE-Arbeitslasten ab:
resource.type="k8s_node" jsonPayload.MESSAGE:("ContainerDied" OR "TaskOOM event") resource.labels.cluster_name="CLUSTER_NAME"
Klicken Sie auf Abfrage ausführen.
Suchen Sie in der Ausgabe nach OOM-Ereignissen, indem Sie nach Logeinträgen mit dem String
TaskOOMsuchen.Optional: Wenn Sie nach OOM-Ereignissen für alle GKE-Arbeitslasten gesucht haben und den spezifischen Pod identifizieren möchten, bei dem die OOM-Ereignisse aufgetreten sind, führen Sie die folgenden Schritte aus:
- Notieren Sie sich für jedes Ereignis die zugehörige Container-ID.
Suchen Sie nach Logeinträgen, die den String
ContainerDiedenthalten und kurz nach den OOM-Ereignissen aufgetreten sind, um Containerstopps zu identifizieren. Ordnen Sie die Container-ID aus dem OOM-Ereignis der entsprechendenContainerDied-Zeile zu.Nachdem Sie die
container IDsabgeglichen haben, enthält die ZeileContainerDiednormalerweise den Pod-Namen, der dem fehlgeschlagenen Container zugeordnet ist. Dieser Pod war vom OOM-Ereignis betroffen.
OOM-Ereignisse mit Containerneustarts korrelieren
Wenn ein OOM-Kill den Hauptprozess eines Containers beendet, startet Kubernetes den Container basierend auf der restartPolicy des Pods neu, wie unter OOM-Kill auf Containerebene und OOM-Kill auf Systemebene beschrieben. Wenn Sie OOMKilling-Ereignisse und die darauf folgenden Containerstarts in einer einzigen chronologischen Liste aufrufen möchten, verwenden Sie den Log-Explorer:
Rufen Sie in der Google Cloud Console den Log-Explorer auf.
Geben Sie im Bereich „Abfrage“ die folgende Abfrage ein:
log_id("events") resource.labels.cluster_name="CLUSTER_NAME" ( ( resource.type="k8s_pod" resource.labels.namespace_name="NAMESPACE_NAME" jsonPayload.message:"Started container" ) OR ( resource.type="k8s_node" jsonPayload.reason="OOMKilling" ) )Ersetzen Sie Folgendes:
CLUSTER_NAME: Der Name des Clusters, den Sie abfragen möchten.NAMESPACE_NAME: der Namespace der Pods, die Sie untersuchen möchten.
OOMKilling-Ereignisse werden für den Knoten (Ressourcentypk8s_node) gemeldet und haben daher kein Namespace-Label. Der Namespace-Filter gilt nur fürStarted container-Ereignisse, die für den Pod (Ressourcentypk8s_pod) gemeldet werden.Klicken Sie auf Abfrage ausführen.
Suchen Sie in der Ausgabe nach
Started container-Ereignissen, die kurz nach einemOOMKilling-Ereignis auf demselben Knoten auftreten. Die EreignisnachrichtOOMKillingidentifiziert den beendeten Prozess und das EreignisStarted containeridentifiziert den gestarteten Pod und Container.Nicht jedes
Started container-Ereignis wird durch einen OOM-Kill verursacht. Wenn Sie prüfen möchten, ob ein Container aufgrund eines OOM-Ereignisses neu gestartet wurde, prüfen Sie den Status des Pods, wie unter Pod-Status auf sichtbare OOM-Ereignisse prüfen beschrieben.
journalctl für Echtzeitinformationen verwenden
Wenn Sie eine Echtzeitanalyse Ihres Systems durchführen müssen, verwenden Sie journalctl-Befehle.
Stellen Sie eine SSH-Verbindung zum Knoten her:
gcloud compute ssh NODE_NAME --location ZONEErsetzen Sie Folgendes:
NODE_NAME: der Name des Knotens, den Sie prüfen möchten.ZONE: die Compute Engine-Zone, zu der Ihr Knoten gehört.
Sehen Sie sich in der Shell die Kernel-Nachrichten aus dem Systemjournal des Knotens an:
journalctl -kAnalysieren Sie die Ausgabe, um den Ereignistyp zu unterscheiden:
- Beendigung auf Containerebene: Der Logeintrag enthält Begriffe wie
memory cgroup,mem_cgroupodermemcg, die darauf hinweisen, dass ein cgroup-Limit erzwungen wurde. - Beendigung auf Systemebene: Der Logeintrag ist eine allgemeine Nachricht wie
Out of memory: Killed process..., ohne dass eine cgroup erwähnt wird.
- Beendigung auf Containerebene: Der Logeintrag enthält Begriffe wie
OOM-Ereignisse beheben
Versuchen Sie Folgendes, um ein OOM-Ereignis zu beheben:
- Speicherlimits erhöhen: Dies ist die direkteste Lösung. Bearbeiten Sie das Pod-Manifest, um einen höheren
resources.limits.memory-Wert anzugeben, der der Spitzennutzung der Anwendung entspricht. Weitere Informationen zum Festlegen von Limits finden Sie in der Kubernetes-Dokumentation unter Ressourcenverwaltung für Pods und Container. - Speicheranfragen hinzufügen oder anpassen: Prüfen Sie im Manifest des Pods, ob das Feld
resources.requests.memoryauf einen realistischen Wert für die typische Nutzung festgelegt ist. Mit dieser Einstellung kann Kubernetes den Pod auf einem Knoten mit ausreichend Arbeitsspeicher planen. - Arbeitslast horizontal skalieren: Um die Trafficlast zu verteilen und die Arbeitsspeicherauslastung für einzelne Pods zu reduzieren, erhöhen Sie die Anzahl der Replikate. Wenn Sie möchten, dass Kubernetes die Arbeitslast proaktiv skaliert, sollten Sie das horizontale Pod-Autoscaling aktivieren.
- Knoten vertikal skalieren: Wenn viele Pods auf einem Knoten nahe an ihren Limits sind, ist der Knoten selbst möglicherweise zu klein. Wenn Sie die Größe der Knoten erhöhen möchten, migrieren Sie Ihre Arbeitslasten in einen Knotenpool mit mehr Arbeitsspeicher. Wenn Sie möchten, dass Kubernetes die Knoten proaktiv skaliert, sollten Sie das vertikale Pod-Autoscaling aktivieren.
- App optimieren: Überprüfen Sie Ihre App, um Speicherlecks zu identifizieren und zu beheben, und optimieren Sie Code, der bei Traffic-Spitzen große Mengen an Arbeitsspeicher verbraucht.
- Problematische Arbeitslasten löschen: Als letzte Möglichkeit für nicht kritische Arbeitslasten können Sie den Pod löschen, um den Cluster sofort zu entlasten.
Nächste Schritte
Wenn Sie in der Dokumentation keine Lösung für Ihr Problem finden, finden Sie unter Support erhalten weitere Hilfe, einschließlich Ratschlägen zu den folgenden Themen:
- Supportanfrage über Cloud Customer Care stellen
- Support von der Community erhalten, indem Sie Fragen auf StackOverflow stellen und das Tag
google-kubernetes-engineverwenden, um nach ähnlichen Problemen zu suchen. Sie können auch dem#kubernetes-engine-Slack-Kanal beitreten, um weiteren Community-Support zu erhalten. - Probleme oder Feature Requests über den öffentlichen Issue Tracker melden.