Cette page vous aide à résoudre les problèmes liés aux événements de mémoire insuffisante (OOM) dans Google Kubernetes Engine (GKE). Apprenez à identifier les causes courantes des événements OOM, à faire la distinction entre les occurrences au niveau du conteneur et au niveau du nœud, et à appliquer des solutions.
Cette page s'adresse aux développeurs d'applications qui souhaitent vérifier que leurs applications sont correctement déployées, ainsi qu'aux administrateurs et opérateurs de plate-forme qui souhaitent comprendre la cause première des événements OOM et vérifier la configuration de la plate-forme. Pour en savoir plus sur les rôles courants et les exemples de tâches que nous citons dans le contenu Google Cloud , consultez Rôles utilisateur et tâches courantes de l'utilisateur dans GKE Enterprise.
Causes courantes des événements OOM
Les événements OOM se produisent généralement lors de pics de charge ou de trafic, lorsque l'utilisation de la mémoire de l'application augmente considérablement et atteint la limite de mémoire configurée pour le conteneur.
Les scénarios suivants peuvent entraîner un événement OOM :
- Limite de mémoire insuffisante : le paramètre
resources.limits.memory
dans le fichier manifeste du pod est trop bas pour les besoins de mémoire typiques ou maximaux de l'application. - Demandes ou limites de mémoire non définies : si
resources.limits.memory
etresources.requests.memory
ne sont pas définis, l'utilisation de la mémoire du conteneur est illimitée. - Charge élevée ou irrégulière : des pics de charge soudains et extrêmes peuvent submerger les ressources d'un système, y compris la mémoire, même si les limites sont généralement suffisantes.
- Fuite de mémoire : l'application peut présenter un défaut de code qui l'empêche de libérer correctement la mémoire.
Les événements OOM peuvent déclencher une défaillance en cascade, car il reste moins de conteneurs pour gérer le trafic, ce qui augmente la charge sur les conteneurs restants. Ces conteneurs peuvent alors également être arrêtés.
Comment Kubernetes gère les événements OOM
Le programme OOM Killer de Linux gère chaque événement OOM. Le tueur OOM est un processus de noyau qui s'active lorsque le système manque de mémoire critique. Son objectif est d'empêcher un plantage complet du système en arrêtant stratégiquement les processus pour libérer des ressources. Le noyau utilise un système de notation pour sélectionner le processus à arrêter, dans le but de préserver la stabilité du système et de minimiser la perte de données.
Dans un environnement Kubernetes, le processus OOM Killer fonctionne à deux niveaux différents : le groupe de contrôle (cgroup), qui affecte un conteneur, et le système, qui affecte l'ensemble du nœud.
Arrêt OOM au niveau du conteneur
Un arrêt OOM au niveau du conteneur se produit lorsqu'un conteneur tente de dépasser sa limite de mémoire prédéfinie. Kubernetes attribue chaque conteneur à un cgroup spécifique avec une limite de mémoire stricte. Lorsque l'utilisation de la mémoire d'un conteneur atteint cette limite, le noyau tente d'abord de récupérer de la mémoire dans ce cgroup. Si le noyau ne parvient pas à récupérer suffisamment de mémoire à l'aide de ce processus, le cgroup OOM Killer est appelé. Il met fin aux processus au sein de ce cgroup spécifique pour appliquer la limite de ressources.
Lorsque le processus principal d'un conteneur est arrêté de cette manière, Kubernetes observe l'événement et marque l'état du conteneur comme OOMKilled
. Le restartPolicy
configuré du pod détermine ensuite le résultat :
Always
ouOnFailure
: le conteneur est redémarré.Never
: le conteneur n'est pas redémarré et reste à l'état terminé.
En isolant la défaillance au conteneur incriminé, le processus OOM Killer empêche un seul pod défectueux de planter l'ensemble du nœud.
Impact de la version cgroup sur le comportement du tueur OOM
Le comportement de l'arrêt OOM peut varier considérablement entre les versions de cgroup. Si vous ne savez pas quelle version de cgroup vous utilisez, vérifiez le mode cgroup des nœuds du cluster.
Dans
cgroup v1
, un événement OOM dans le cgroup de mémoire d'un conteneur peut entraîner un comportement imprévisible. Le tueur OOM peut mettre fin à n'importe quel processus de ce cgroup, y compris les processus enfants qui ne sont pas le processus principal du conteneur (PID 1).Ce comportement pose un problème majeur pour Kubernetes. Étant donné que Kubernetes surveille principalement l'état du processus de conteneur principal, il n'a pas connaissance de ces arrêts OOM "partiels". Le processus de conteneur principal peut continuer à s'exécuter, même si des processus enfants critiques ont été arrêtés. Ce comportement peut entraîner des défaillances subtiles des applications qui ne sont pas immédiatement visibles par Kubernetes ni par les opérateurs, mais qui sont toujours visibles dans le journal système du nœud (
journalctl
).cgroup v2
offre un comportement plus prévisible du tueur OOM.Pour garantir l'intégrité des charges de travail dans un environnement cgroup v2, le killer OOM empêche les arrêts partiels et garantit l'un des deux résultats suivants : soit toutes les tâches appartenant à ce cgroup et à ses descendants sont arrêtées (ce qui rend l'échec visible pour Kubernetes), soit, lorsque la charge de travail n'a pas de tâches utilisant trop de mémoire, la charge de travail est laissée intacte et continue de s'exécuter sans arrêt inattendu de processus internes.
Pour les scénarios dans lesquels vous souhaitez que
cgroup v1
se comporte comme un arrêt d'un seul processus, kubelet fournit l'indicateursingleProcessOOMKill
pourcgroup v2
. Cet indicateur vous offre un contrôle plus précis, en vous permettant d'arrêter des processus individuels lors d'un événement OOM, plutôt que l'ensemble du cgroup.
Arrêt OOM au niveau du système
Un arrêt OOM au niveau du système est un événement plus grave qui se produit lorsque l'ensemble du nœud, et pas seulement un seul conteneur, manque de mémoire disponible. Cet événement peut se produire si l'utilisation combinée de la mémoire de tous les processus (y compris tous les pods et les daemons système) dépasse la capacité du nœud.
Lorsque ce nœud manque de mémoire, le robot tueur OOM global évalue tous les processus sur le nœud et en arrête un pour récupérer de la mémoire pour l'ensemble du système. Le processus sélectionné est généralement de courte durée et utilise une grande quantité de mémoire.
Pour éviter les situations graves d'OOM, Kubernetes utilise l'éviction par pression sur les nœuds pour gérer les ressources des nœuds. Ce processus consiste à évincer les pods moins critiques d'un nœud lorsque les ressources, telles que la mémoire ou l'espace disque, deviennent extrêmement faibles. Un arrêt OOM au niveau du système indique que ce processus d'éviction n'a pas pu libérer de la mémoire assez rapidement pour éviter le problème.
Si le processus d'un conteneur est arrêté par le tueur OOM, l'effet est généralement identique à celui d'un arrêt déclenché par un cgroup : le conteneur est marqué OOMKilled
et redémarré en fonction de sa règle. Toutefois, si un processus système critique est arrêté (ce qui est rare), le nœud lui-même peut devenir instable.
Examiner les événements OOM
Les sections suivantes vous aident à détecter et à confirmer un événement OOM, en commençant par les outils Kubernetes les plus simples et en passant à une analyse plus détaillée des journaux.
Vérifier l'état du pod pour les événements OOM visibles
La première étape pour confirmer un événement OOM consiste à vérifier si Kubernetes l'a observé. Kubernetes observe l'événement lorsque le processus principal du conteneur est arrêté, ce qui est un comportement standard dans les environnements cgroup v2
.
Inspectez l'état du pod :
kubectl describe pod POD_NAME
Remplacez
POD_NAME
par le nom du pod que vous souhaitez examiner.Si un événement OOM visible s'est produit, le résultat est semblable à ce qui suit :
... 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 ...
Si OOMKilled
s'affiche dans le champ Reason
, cela signifie que vous avez confirmé l'événement. Un Exit Code
de type 137
indique également un arrêt pour mémoire insuffisante. Si le champ Reason
a une valeur différente ou si le pod est toujours en cours d'exécution malgré les erreurs d'application, passez à la section suivante pour examiner le problème plus en détail.
Rechercher les événements OOM invisibles dans les journaux
Un arrêt OOM est "invisible" pour Kubernetes si un processus enfant est arrêté, mais que le processus de conteneur principal continue de s'exécuter (un scénario courant dans les environnements cgroup v1
). Vous devez rechercher dans les journaux du nœud des preuves de ces événements.
Pour trouver les erreurs OOM invisibles, utilisez l'explorateur de journaux :
Dans la console Google Cloud , accédez à l'explorateur de journaux.
Dans le volet "Requête", saisissez l'une des requêtes suivantes :
Si vous disposez déjà d'un pod qui, selon vous, a rencontré un événement OOM, interrogez ce pod spécifique :
resource.type="k8s_node" jsonPayload.MESSAGE:(("POD_NAME" AND "ContainerDied") OR "TaskOOM event") resource.labels.cluster_name="CLUSTER_NAME"
Remplacez les éléments suivants :
POD_NAME
: nom du pod que vous souhaitez interroger.CLUSTER_NAME
: nom du cluster auquel appartient le pod.
Pour identifier les pods ou les nœuds qui ont rencontré un événement OOM, interrogez toutes les charges de travail GKE :
resource.type="k8s_node" jsonPayload.MESSAGE:("ContainerDied" OR "TaskOOM event") resource.labels.cluster_name="CLUSTER_NAME"
Cliquez sur Exécuter la requête.
Dans le résultat, recherchez les événements OOM en recherchant les entrées de journal contenant la chaîne
TaskOOM
.Facultatif : Si vous avez recherché des événements OOM pour toutes les charges de travail GKE et que vous souhaitez identifier le pod spécifique qui a rencontré les événements OOM, procédez comme suit :
- Pour chaque événement, notez l'ID du conteneur qui lui est associé.
Identifiez les arrêts de conteneur en recherchant les entrées de journal contenant la chaîne
ContainerDied
et qui se sont produites peu de temps après les événements OOM. Faites correspondre l'ID de conteneur de l'événement OOM à la ligneContainerDied
correspondante.Une fois que vous avez trouvé le
container IDs
, la ligneContainerDied
inclut généralement le nom du pod associé au conteneur défaillant. Ce pod a été affecté par l'événement OOM.
Utiliser journalctl pour obtenir des informations en temps réel
Si vous devez effectuer une analyse en temps réel de votre système, utilisez les commandes journalctl
.
Connectez-vous au nœud à l'aide de SSH :
gcloud compute ssh NODE_NAME --location ZONE
Remplacez les éléments suivants :
NODE_NAME
: nom du nœud que vous souhaitez examiner.ZONE
: zone Compute Engine à laquelle appartient votre nœud.
Dans le shell, explorez les messages du noyau à partir du journal système du nœud :
journalctl -k
Analysez le résultat pour distinguer le type d'événement :
- Arrêt au niveau du conteneur : l'entrée de journal contient des termes tels que
memory cgroup
,mem_cgroup
oumemcg
, qui indiquent qu'une limite de cgroup a été appliquée. - Arrêt au niveau du système : l'entrée de journal est un message général tel que
Out of memory: Killed process...
sans mentionner de cgroup.
- Arrêt au niveau du conteneur : l'entrée de journal contient des termes tels que
Résoudre les événements OOM
Pour résoudre un événement OOM, essayez les solutions suivantes :
- Augmenter les limites de mémoire : il s'agit de la solution la plus directe. Modifiez le fichier manifeste du pod pour fournir une valeur
resources.limits.memory
plus élevée qui s'adapte à l'utilisation maximale de l'application. Pour en savoir plus sur la définition de limites, consultez Gestion des ressources pour les pods et les conteneurs dans la documentation Kubernetes. - Ajouter ou ajuster les demandes de mémoire : dans le fichier manifeste du pod, vérifiez que le champ
resources.requests.memory
est défini sur une valeur réaliste pour une utilisation typique. Ce paramètre permet à Kubernetes de planifier le pod sur un nœud disposant de suffisamment de mémoire. - Faites évoluer la charge de travail horizontalement : pour répartir la charge de trafic et réduire la pression sur la mémoire d'un pod unique, augmentez le nombre de réplicas. Pour que Kubernetes adapte de manière proactive la charge de travail, envisagez d'activer l'autoscaling horizontal des pods.
- Faites évoluer les nœuds verticalement : si de nombreux pods sur un nœud sont proches de leurs limites, le nœud lui-même peut être trop petit. Pour augmenter la taille des nœuds, migrez vos charges de travail vers un pool de nœuds disposant de plus de mémoire. Pour que Kubernetes mette à l'échelle les nœuds de manière proactive, envisagez d'activer l'autoscaling vertical des pods.
- Optimisez votre application : examinez votre application pour identifier et résoudre les fuites de mémoire, et optimisez le code qui consomme de grandes quantités de mémoire lors des pics de trafic.
- Supprimez les charges de travail problématiques : en dernier recours pour les charges de travail non critiques, supprimez le pod pour soulager immédiatement la pression sur le cluster.
Étapes suivantes
Si vous ne trouvez pas de solution à votre problème dans la documentation, consultez Obtenir de l'aide pour obtenir une assistance supplémentaire, y compris des conseils sur les sujets suivants :
- Ouvrez une demande d'assistance en contactant le service client Google Cloud.
- Obtenir de l'aide de la communauté en posant des questions sur Stack Overflow et en utilisant le tag
google-kubernetes-engine
pour rechercher des problèmes similaires. Vous pouvez également rejoindre le canal Slack#kubernetes-engine
pour obtenir de l'aide auprès de la communauté. - Signaler des bugs ou demander des fonctionnalités à l'aide de l'outil public de suivi des problèmes.