OOM-Ereignisse beheben

Wenn bei Ihren Google Kubernetes Engine-Anwendungen (GKE) unerwartete Containerbeendigungen, Instabilität oder CrashLoopBackOff-Fehler auftreten, kann dies an Arbeitsspeichermangel-Ereignissen (Out of Memory, OOM) liegen. OOM-Ereignisse treten auf, wenn der Arbeitsspeicher eines Containers oder Knotens nicht mehr ausreicht. In diesem Fall beendet der Linux-OOM-Killer Prozesse, um Ressourcen freizugeben.

Auf dieser Seite erfahren Sie, ob ein OOM-Ereignis auf Container- oder Knotenebene aufgetreten ist, und wie Sie wirksame Abhilfemaßnahmen anwenden können, um ein erneutes Auftreten zu verhindern.

Diese Informationen sind wichtig für Anwendungsentwickler, die sicherstellen müssen, dass ihre Anwendungen mit entsprechenden Arbeitsspeicheranfragen und ‑limits konfiguriert sind und keine Arbeitsspeicherlecks aufweisen. Sie sind auch wichtig für Plattformadministratoren und ‑operatoren, die die Ressourcennutzung von Knoten überwachen und sicherstellen, dass der Cluster über ausreichend Arbeitsspeicherkapazitä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 den 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 Arbeitsspeichernutzung der App ansteigt und das für den Container konfigurierte Arbeitsspeicherlimit erreicht.

Die folgenden Szenarien können ein OOM-Ereignis verursachen:

  • Unzureichendes Arbeitsspeicherlimit: Die Einstellung resources.limits.memory im Manifest des Pods ist zu niedrig für den typischen oder maximalen Arbeitsspeicherbedarf der App.
  • Nicht definierte Arbeitsspeicheranfragen oder ‑limits: Wenn sowohl resources.limits.memory als auch resources.requests.memory nicht definiert sind, 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 ausreichend sind.
  • Speicherleck: Die App hat möglicherweise einen Codefehler, der dazu führt, dass der Arbeitsspeicher nicht ordnungsgemäß freigegeben wird.

OOM-Ereignisse können eine Kaskade von Fehlern auslösen, da weniger Container zur Verarbeitung des Traffics zur Verfügung stehen und die Last auf die verbleibenden Container steigt. Diese Container werden dann möglicherweise auch beendet.

Umgang von Kubernetes mit OOM-Ereignissen

Der Linux-OOM-Killer verarbeitet jedes OOM-Ereignis. Der OOM-Killer ist ein Kernelprozess, der aktiviert wird, wenn der Arbeitsspeicher des Systems kritisch niedrig ist. Er soll einen vollständigen Systemabsturz verhindern, indem er strategisch Prozesse beendet, 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 (Control Group, cgroup), die einen Container betrifft, und dem System, das den gesamten Knoten betrifft.

OOM-Beendigung auf Containerebene

Eine OOM-Beendigung auf Containerebene tritt auf, wenn ein Container versucht, sein vordefiniertes Arbeitsspeicherlimit zu überschreiten. Kubernetes weist jedem Container eine bestimmte cgroup mit einem festen Arbeitsspeicherlimit zu. Wenn die Arbeitsspeichernutzung eines Containers dieses Limit erreicht, versucht der Kernel zuerst, Arbeitsspeicher innerhalb dieser cgroup freizugeben. Wenn der Kernel mit diesem Prozess nicht genügend Arbeitsspeicher freigeben kann, wird der OOM-Killer der cgroup aufgerufen. Er beendet Prozesse innerhalb dieser bestimmten 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:

  • Always oder OnFailure: Der Container wird neu gestartet.
  • Never: Der Container wird nicht neu gestartet und bleibt im beendeten Zustand.

Indem der Fehler auf den fehlerhaften Container beschränkt wird, verhindert der OOM-Killer, dass ein einzelner fehlerhafter Pod den gesamten Knoten zum Absturz bringt.

Auswirkungen der cgroup-Version auf das Verhalten des OOM-Killers

Das Verhalten bei der OOM-Beendigung kann sich zwischen den cgroup-Versionen erheblich unterscheiden. Wenn Sie nicht sicher sind, welche cgroup-Version Sie verwenden, prüfen Sie den cgroup-Modus der Clusterknoten.

  • In cgroup v1 kann ein OOM-Ereignis innerhalb der Arbeitsspeicher-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 sind (PID 1).

    Dieses Verhalten stellt eine erhebliche Herausforderung für Kubernetes dar. Da Kubernetes in erster Linie den Status des Hauptprozesses des Containers überwacht, werden diese „teilweisen“ OOM-Beendigungen nicht erkannt. Der Hauptprozess des Containers 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 Systemprotokoll des Knotens (journalctl) zu sehen sind.

  • cgroup v2 bietet ein besser vorhersagbares Verhalten des OOM-Killers.

    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 beendet, die zu dieser cgroup und ihren Nachfolgern gehören (sodass der Fehler für Kubernetes sichtbar ist), oder wenn die Arbeitslast keine Aufgaben hat, die zu viel Arbeitsspeicher verwenden, bleibt die Arbeitslast unverändert und wird ohne unerwartete interne Prozessbeendigungen weiter ausgeführt.

    Für Szenarien, in denen Sie das cgroup v1-Verhalten der Beendigung eines einzelnen Prozesses wünschen, bietet das Kubelet das Flag singleProcessOOMKill für cgroup v2. Dieses Flag bietet eine detailliertere Steuerung und ermöglicht die Beendigung einzelner Prozesse während eines OOM-Ereignisses anstelle der gesamten cgroup.

OOM-Beendigung auf Systemebene

Eine OOM-Beendigung auf Systemebene ist ein schwerwiegenderes Ereignis, das auftritt, wenn der Arbeitsspeicher des gesamten Knotens und nicht nur eines einzelnen Containers nicht mehr ausreicht. Dieses Ereignis kann auftreten, wenn die kombinierte Arbeitsspeichernutzung aller Prozesse (einschließlich aller Pods und System-Daemons) die Kapazität des Knotens überschreitet.

Wenn der Arbeitsspeicher dieses Knotens nicht mehr ausreicht, 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 verwendet viel Arbeitsspeicher.

Um schwerwiegende OOM-Situationen zu vermeiden, verwendet Kubernetes die Knotenentfernung aufgrund von Ressourcenmangel eviction , um Knotenressourcen zu verwalten. Bei diesem Prozess werden weniger kritische Pods von einem Knoten entfernt, wenn Ressourcen wie Arbeitsspeicher oder Speicherplatz kritisch niedrig werden. Eine OOM-Beendigung auf Systemebene zeigt an, dass bei diesem Entfernungsprozess nicht schnell genug Arbeitsspeicher freigegeben werden konnte, um das Problem zu verhindern.

Wenn der OOM-Killer den Prozess eines Containers beendet, ist die Wirkung in der Regel identisch mit einer durch eine cgroup ausgelösten Beendigung: 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 können. Wir beginnen 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. Das ist das Standardverhalten in cgroup v2-Umgebungen.

  • Pod-Status prüfen:

    kubectl describe pod POD_NAME
    

    Ersetzen Sie POD_NAME durch den Namen des Pods, den Sie sich prüfen möchten.

    Wenn ein sichtbares OOM-Ereignis aufgetreten ist, sieht die Ausgabe 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 von 137 weist ebenfalls auf eine OOM-Beendigung hin. Wenn das Feld Reason einen anderen Wert hat oder der Pod trotz App-Fehlern noch ausgeführt wird, fahren Sie mit dem nächsten Abschnitt fort, um weitere Untersuchungen durchzuführen.

Logs nach unsichtbaren OOM-Ereignissen durchsuchen

Eine OOM-Beendigung ist für Kubernetes „unsichtbar“, wenn ein untergeordneter Prozess beendet wird, der Hauptprozess des Containers jedoch weiter ausgeführt wird (ein häufiges Szenario in cgroup v1-Umgebungen). Sie müssen die Logs des Knotens durchsuchen, um Beweise für diese Ereignisse zu finden.

So finden Sie unsichtbare OOM-Beendigungen mit dem Log-Explorer:

  1. Rufen Sie in der Google Cloud Console den Log-Explorer auf.

    Zum Log-Explorer

  2. Geben Sie im Bereich „Abfrage“ eine der folgenden Abfragen ein:

    • Wenn Sie bereits einen Pod haben, bei dem Sie vermuten, dass 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"
      
  3. Klicken Sie auf Abfrage ausführen.

  4. Suchen Sie in der Ausgabe nach OOM-Ereignissen, indem Sie nach Logeinträgen suchen, die die String TaskOOM enthalten.

  5. 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:

    1. Notieren Sie sich für jedes Ereignis die Container-ID, die damit verknüpft ist.
    2. Suchen Sie nach Logeinträgen, die die String ContainerDied enthalten und kurz nach den OOM-Ereignissen aufgetreten sind, um Containerbeendigungen zu identifizieren. Vergleichen Sie die Container-ID aus dem OOM-Ereignis mit der entsprechenden ContainerDied-Zeile.

    3. Nachdem Sie die container IDs zugeordnet haben, enthält die ContainerDied Zeile in der Regel den Pod-Namen, der mit dem fehlerhaften Container verknüpft ist. Dieser Pod war von dem OOM-Ereignis betroffen.

`journalctl` für Echtzeitinformationen verwenden

Wenn Sie eine Echtzeitanalyse Ihres Systems durchführen müssen, verwenden Sie journalctl-Befehle.

  1. Stellen Sie eine SSH-Verbindung zum Knoten her:

    gcloud compute ssh NODE_NAME --location ZONE
    

    Ersetzen Sie Folgendes:

    • NODE_NAME: Der Name des Knotens, den Sie untersuchen möchten.
    • ZONE: Die Compute Engine-Zone, zu der Ihr Knoten gehört.
  2. Sehen Sie sich in der Shell die Kernelmeldungen aus dem Systemprotokoll des Knotens an:

    journalctl -k
    
  3. Analysieren Sie die Ausgabe, um den Ereignistyp zu unterscheiden:

    • Beendigung auf Containerebene: Der Logeintrag enthält Begriffe wie memory cgroup, mem_cgroup, oder memcg, die darauf hinweisen, dass ein cgroup-Limit durchgesetzt wurde.
    • Beendigung auf Systemebene: Der Logeintrag ist eine allgemeine Meldung wie Out of memory: Killed process... ohne Erwähnung einer cgroup.

OOM-Ereignisse beheben

Versuchen Sie die folgenden Lösungen, um ein OOM-Ereignis zu beheben:

  • Arbeitsspeicherlimits erhöhen: Dies ist die direkteste Lösung. Bearbeiten Sie das Pod-Manifest, um einen höheren Wert für resources.limits.memory anzugeben, der der maximalen Nutzung der App entspricht. Weitere Informationen zum Festlegen von Limits finden Sie Ressourcenverwaltung für Pods und Container in der Kubernetes-Dokumentation.
  • Arbeitsspeicheranfragen hinzufügen oder anpassen: Prüfen Sie im Manifest des Pods, ob das Feld resources.requests.memory auf 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: Erhöhen Sie die Anzahl der Replikate, um die Trafficlast zu verteilen und den Arbeitsspeicherdruck auf einzelne Pods zu verringern. Wenn Kubernetes die Arbeitslast proaktiv skalieren soll, ziehen Sie in Betracht, horizontales Pod-Autoscaling zu aktivieren.
  • Knoten vertikal skalieren: Wenn viele Pods auf einem Knoten ihre Limits fast erreichen, ist der Knoten möglicherweise zu klein. Migrieren Sie Ihre Arbeitslasten zu einem Knotenpool mit mehr Arbeitsspeicher, um die Größe der Knoten zu erhöhen, migrate your workloads to a node pool with more memory. Wenn Kubernetes die Knoten proaktiv skalieren soll, aktivieren Sie das vertikale Pod-Autoscaling.
  • App optimieren: Überprüfen Sie Ihre App, um Arbeitsspeicher lecks zu erkennen und zu beheben, und optimieren Sie Code, der bei Trafficspitzen 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 Druck auf den Cluster sofort zu verringern.

Nächste Schritte