Si tus aplicaciones de Google Kubernetes Engine (GKE) experimentan terminaciones de contenedores inesperadas, inestabilidad o errores CrashLoopBackOff
, puede deberse a eventos de falta de memoria (OOM). Los eventos de falta de memoria se producen cuando un contenedor o un nodo se queda sin memoria, lo que provoca que Linux OOM Killer finalice los procesos para recuperar recursos.
Use esta página para identificar si se ha producido un evento de falta de memoria a nivel de contenedor o de nodo, y aplique estrategias de mitigación eficaces para evitar que se repita.
Esta información es importante para los desarrolladores de aplicaciones que deben asegurarse de que sus aplicaciones estén configuradas con solicitudes y límites de memoria adecuados, y de que no tengan fugas de memoria. También es importante para los administradores y operadores de la plataforma que monitorizan el uso de los recursos de los nodos y se aseguran de que el clúster tenga suficiente capacidad de memoria para admitir las cargas de trabajo implementadas. Para obtener más información sobre los roles habituales y las tareas de ejemplo a las que hacemos referencia en el contenido, consulta Roles y tareas habituales de los usuarios de GKE. Google Cloud
Causas habituales de los eventos de falta de memoria
Los eventos de falta de memoria suelen producirse durante picos de carga o de tráfico, cuando el uso de memoria de la aplicación aumenta y alcanza el límite de memoria configurado para el contenedor.
Los siguientes casos pueden provocar un evento de falta de memoria:
- Límite de memoria insuficiente: el ajuste
resources.limits.memory
del manifiesto del pod es demasiado bajo para las demandas de memoria típicas o máximas de la aplicación. - Solicitudes o límites de memoria indefinidos: si no se definen
resources.limits.memory
niresources.requests.memory
, el uso de memoria del contenedor no tendrá límites. - Carga alta o con picos: los picos repentinos y extremos de carga pueden sobrecargar los recursos de un sistema, incluida la memoria, aunque los límites suelan ser adecuados.
- Fuga de memoria: la aplicación puede tener un defecto en el código que provoque que no libere la memoria correctamente.
Los eventos de falta de memoria pueden iniciar un error en cascada, ya que quedan menos contenedores para gestionar el tráfico, lo que aumenta la carga de los contenedores restantes. También se podrían cancelar estos contenedores.
Cómo gestiona Kubernetes los eventos de falta de memoria
El controlador OOM Killer de Linux gestiona todos los eventos OOM. OOM Killer es un proceso del kernel que se activa cuando el sistema tiene poca memoria. Su objetivo es evitar que el sistema falle por completo terminando procesos de forma estratégica para liberar recursos. El kernel usa un sistema de puntuación para seleccionar el proceso que se va a detener, con el objetivo de mantener la estabilidad del sistema y minimizar la pérdida de datos.
En un entorno de Kubernetes, el OOM Killer opera en dos ámbitos diferentes: el grupo de control (cgroup), que afecta a un contenedor, y el sistema, que afecta a todo el nodo.
Eliminación por falta de memoria a nivel de contenedor
Una cancelación por falta de memoria a nivel de contenedor se produce cuando un contenedor intenta superar su límite de memoria predefinido. Kubernetes asigna cada contenedor a un cgroup específico con un límite de memoria estricto. Cuando el uso de memoria de un contenedor alcanza este límite, el kernel primero intenta recuperar memoria dentro de ese cgroup. Si el kernel no puede recuperar suficiente memoria mediante este proceso, se invoca el controlador OOM de cgroup. Termina los procesos de ese cgroup específico para aplicar el límite de recursos.
Cuando el proceso principal de un contenedor se termina de esta forma, Kubernetes observa el evento y marca el estado del contenedor como OOMKilled
. La configuración del pod restartPolicy
determina el resultado:
Always
oOnFailure
: el contenedor se reinicia.Never
: el contenedor no se reinicia y permanece en estado finalizado.
Al aislar el fallo en el contenedor infractor, OOM Killer evita que un solo pod defectuoso bloquee todo el nodo.
Cómo afecta la versión de cgroup al comportamiento de OOM Killer
El comportamiento de la finalización por falta de memoria puede variar significativamente entre las versiones de cgroup. Si no sabes qué versión de cgroup usas, consulta el modo cgroup de los nodos del clúster.
En
cgroup v1
, un evento de falta de memoria en el cgroup de memoria de un contenedor puede provocar un comportamiento impredecible. El proceso OOM Killer puede finalizar cualquier proceso de ese cgroup, incluidos los procesos secundarios que no sean el proceso principal del contenedor (PID 1).Este comportamiento supone un reto importante para Kubernetes. Como Kubernetes monitoriza principalmente el estado del proceso del contenedor principal, no detecta estas finalizaciones parciales por falta de memoria. El proceso del contenedor principal puede seguir ejecutándose aunque se hayan terminado procesos secundarios críticos. Este comportamiento puede provocar fallos sutiles en las aplicaciones que no sean visibles inmediatamente para Kubernetes o los operadores, pero que sí se puedan ver en el registro del sistema del nodo (
journalctl
).cgroup v2
ofrece un comportamiento más predecible de OOM Killer.Para garantizar la integridad de las cargas de trabajo en un entorno cgroup v2, el controlador OOM evita las eliminaciones parciales y asegura uno de estos dos resultados: o bien se terminan todas las tareas pertenecientes a ese cgroup y a sus descendientes (lo que hace que Kubernetes vea el fallo), o bien, si la carga de trabajo no tiene tareas que usen demasiada memoria, se deja intacta y sigue ejecutándose sin terminaciones inesperadas de procesos internos.
En los casos en los que quieras que
cgroup v1
termine un solo proceso, kubelet proporciona la marcasingleProcessOOMKill
paracgroup v2
. Esta marca te ofrece un control más granular, lo que permite finalizar procesos individuales durante un evento de falta de memoria en lugar de todo el cgroup.
Eliminación por falta de memoria a nivel de sistema
Una eliminación por falta de memoria a nivel de sistema es un evento más grave que se produce cuando todo el nodo, no solo un contenedor, se queda sin memoria disponible. Este evento puede producirse si el uso de memoria combinado de todos los procesos (incluidos todos los pods y los daemons del sistema) supera la capacidad del nodo.
Cuando este nodo se queda sin memoria, el proceso OOM Killer global evalúa todos los procesos del nodo y finaliza uno para recuperar memoria para todo el sistema. El proceso seleccionado suele ser de corta duración y usar una gran cantidad de memoria.
Para evitar situaciones graves de falta de memoria, Kubernetes usa la evicción por presión de nodos para gestionar los recursos de los nodos. Este proceso implica expulsar los pods menos críticos de un nodo cuando los recursos, como la memoria o el espacio en disco, se agotan. Si se produce un error de falta de memoria a nivel del sistema, significa que este proceso de desalojo no ha podido liberar memoria lo suficientemente rápido como para evitar el problema.
Si el OOM Killer finaliza el proceso de un contenedor, el efecto suele ser idéntico a una finalización activada por un cgroup: el contenedor se marca como OOMKilled
y se reinicia según su política. Sin embargo, si se finaliza un proceso crítico del sistema (lo cual es poco habitual), el propio nodo podría volverse inestable.
Investigar eventos de falta de memoria
En las siguientes secciones se explica cómo detectar y confirmar un evento de falta de memoria, empezando por las herramientas de Kubernetes más sencillas y pasando a un análisis de registros más detallado.
Comprobar el estado del pod para ver si hay eventos OOM visibles
El primer paso para confirmar un evento de falta de memoria es comprobar si Kubernetes ha observado el evento. Kubernetes observa el evento cuando se cierra el proceso principal del contenedor, que es el comportamiento estándar en los entornos de cgroup v2
.
Comprueba el estado del Pod:
kubectl describe pod POD_NAME
Sustituye
POD_NAME
por el nombre del pod que quieras investigar.Si se ha producido un evento OOM visible, el resultado será similar al siguiente:
... 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 ve OOMKilled
en el campo Reason
, significa que ha confirmado el evento. Un
Exit Code
de 137
también indica que se ha finalizado un proceso por falta de memoria. Si el campo Reason
tiene un valor diferente o el pod sigue ejecutándose a pesar de los errores de la aplicación, ve a la siguiente sección para investigar más a fondo.
Buscar registros de eventos OOM invisibles
Kubernetes no detecta la finalización por falta de memoria si se finaliza un proceso secundario, pero el proceso del contenedor principal sigue ejecutándose (una situación habitual en entornos cgroup v1
). Debes buscar en los registros del nodo para encontrar pruebas de estos eventos.
Para encontrar los errores de falta de memoria invisibles, usa el Explorador de registros:
En la Google Cloud consola, ve a Explorador de registros.
En el panel de consultas, introduce una de las siguientes consultas:
Si ya tienes un pod que crees que ha experimentado un evento OOM, consulta ese pod específico:
resource.type="k8s_node" jsonPayload.MESSAGE:(("POD_NAME" AND "ContainerDied") OR "TaskOOM event") resource.labels.cluster_name="CLUSTER_NAME"
Haz los cambios siguientes:
POD_NAME
: el nombre del pod que quieres consultar.CLUSTER_NAME
: el nombre del clúster al que pertenece el pod.
Para descubrir qué pods o nodos han experimentado un evento OOM, consulta todas las cargas de trabajo de GKE:
resource.type="k8s_node" jsonPayload.MESSAGE:("ContainerDied" OR "TaskOOM event") resource.labels.cluster_name="CLUSTER_NAME"
Haz clic en Realizar una consulta.
En el resultado, busca eventos de falta de memoria buscando entradas de registro que contengan la cadena
TaskOOM
.Opcional: Si has buscado eventos de falta de memoria en todas las cargas de trabajo de GKE y quieres identificar el pod específico que ha experimentado los eventos de falta de memoria, sigue estos pasos:
- Anota el ID de contenedor asociado a cada evento.
Identifica las detenciones de contenedores buscando entradas de registro que contengan la cadena
.ContainerDied
y que se hayan producido poco después de los eventos de falta de memoria. Busca el ID de contenedor del evento de falta de memoria y la líneaContainerDied
correspondiente.Después de encontrar la coincidencia de
container IDs
, la líneaContainerDied
suele incluir el nombre del pod asociado al contenedor que ha fallado. Este pod se ha visto afectado por el evento OOM.
Usar journalctl para obtener información en tiempo real
Si necesitas analizar tu sistema en tiempo real, usa los comandos journalctl
.
Conéctate al nodo mediante SSH:
gcloud compute ssh NODE_NAME --location ZONE
Haz los cambios siguientes:
NODE_NAME
: el nombre del nodo que quieras examinar.ZONE
: la zona de Compute Engine a la que pertenece tu nodo.
En el shell, consulta los mensajes del kernel del registro del sistema del nodo:
journalctl -k
Analiza el resultado para distinguir el tipo de evento:
- Eliminación a nivel de contenedor: la entrada de registro contiene términos como
memory cgroup
,mem_cgroup
omemcg
, que indican que se ha aplicado un límite de cgroup. - Eliminación a nivel de sistema: la entrada del registro es un mensaje general
como
Out of memory: Killed process...
sin mencionar un cgroup.
- Eliminación a nivel de contenedor: la entrada de registro contiene términos como
Resolver eventos de falta de memoria
Para resolver un evento de falta de memoria, prueba las siguientes soluciones:
- Aumentar los límites de memoria: esta es la solución más directa. Edita el Pod
manifest para proporcionar un valor de
resources.limits.memory
más alto que se adapte al pico de uso de la aplicación. Para obtener más información sobre cómo definir límites, consulta el artículo Gestión de recursos para pods y contenedores de la documentación de Kubernetes. - Añadir o ajustar solicitudes de memoria: en el manifiesto del pod, comprueba que el campo
resources.requests.memory
tenga un valor realista para el uso habitual. Este ajuste ayuda a Kubernetes a programar el pod en un nodo con suficiente memoria. - Escalar horizontalmente la carga de trabajo: para distribuir la carga de tráfico y reducir la presión de memoria en un solo pod, aumenta el número de réplicas. Para que Kubernetes escale la carga de trabajo de forma proactiva, puedes habilitar el autoescalado de pods horizontal.
- Escalar verticalmente los nodos: si muchos pods de un nodo están cerca de sus límites, es posible que el nodo sea demasiado pequeño. Para aumentar el tamaño de los nodos, migra tus cargas de trabajo a un grupo de nodos con más memoria. Para que Kubernetes escale los nodos de forma proactiva, puedes habilitar el autoescalado de pods vertical.
- Optimiza tu aplicación: revisa tu aplicación para identificar y resolver fugas de memoria, así como para optimizar el código que consume grandes cantidades de memoria durante los picos de tráfico.
- Eliminar cargas de trabajo problemáticas: como último recurso para cargas de trabajo no críticas, elimina el pod para aliviar inmediatamente la presión sobre el clúster.
Siguientes pasos
Si no encuentras una solución a tu problema en la documentación, consulta la sección Obtener asistencia para obtener más ayuda, incluidos consejos sobre los siguientes temas:
- Abrir un caso de asistencia poniéndose en contacto con el equipo de Atención al Cliente de Cloud.
- Obtener asistencia de la comunidad haciendo preguntas en Stack Overflow
y usando la etiqueta
google-kubernetes-engine
para buscar problemas similares. También puedes unirte al#kubernetes-engine
canal de Slack para obtener más ayuda de la comunidad. - Abrir errores o solicitudes de funciones mediante el seguimiento de problemas público.