Pod de Kubernetes terminado por OOMKilled por exceso de memoria
|

OOMKilled en Kubernetes: que es y como solucionarlo

OOMKilled es uno de esos errores que aparecen de repente en produccion y pueden dejar servicios caidos sin aviso. El nombre lo dice todo: Out Of Memory Killed. El kernel del sistema mato tu proceso porque se quedo sin memoria. En Kubernetes ocurre cuando un contenedor supera el limite de memoria definido en su spec. En este post te explico como diagnosticarlo y como solucionarlo. Si no tienes claro como funcionan los pods, repasa primero el post de Pods, Deployments y Services.

Que significa OOMKilled en Kubernetes

Cuando un contenedor supera el limite de memoria definido en su spec, el kernel de Linux activa el OOM Killer y termina el proceso. Kubernetes registra el estado como OOMKilled y, dependiendo de la restartPolicy, lo reinicia o no.

kubectl get pods
NAME          READY   STATUS      RESTARTS   AGE
mi-app-xyz    0/1     OOMKilled   3          5m

O puede aparecer como CrashLoopBackOff si lleva varios reinicios

Paso 1: Confirmar que es OOMKilled

kubectl describe pod mi-app-xyz

Busca en la seccion Containers - Last State:
Last State: Terminated
  Reason: OOMKilled
  Exit Code: 137

Exit code 137 = 128 + 9 (SIGKILL)
Siempre indica que el proceso fue terminado por el kernel

El exit code 137 es la firma del OOMKilled. Si ves ese codigo de salida, es memoria, no hay duda.

Paso 2: Ver cuanta memoria usaba el contenedor

kubectl top pods
NAME          CPU(cores)   MEMORY(bytes)
mi-app-xyz    50m          480Mi

kubectl top pods --containers

kubectl describe pod mi-app-xyz | grep -A 3 Limits
Limits:
  memory: 512Mi
  cpu: 500m

Causas mas comunes de OOMKilled en Kubernetes

Causa 1: El limite de memoria es demasiado bajo

La causa mas habitual. Se definio un limite conservador que la aplicacion supera bajo carga real. La regla general: el limite debe ser al menos un 20-30% mayor que el uso maximo observado.

Causa 2: Memory leak en la aplicacion

La aplicacion consume cada vez mas memoria hasta superar el limite. Se distingue porque la memoria sube de forma continua incluso sin carga, y el pod se reinicia cada pocas horas.

Causa 3: Picos de memoria bajo carga alta

La aplicacion funciona bien normalmente pero bajo carga alta tiene picos que superan el limite. Tipico en apps que hacen procesamiento en memoria: parseo de JSONs grandes, generacion de informes, etc.

Causa 4: Sin limite definido

Si no defines resources.limits.memory, el contenedor puede usar toda la memoria del nodo. El OOM Killer del kernel actua a nivel de nodo y puede matar cualquier proceso, no solo el contenedor culpable.

Soluciones para OOMKilled en Kubernetes

Solucion 1: Aumentar el limite de memoria

spec:
  containers:
  - name: mi-app
    resources:
      requests:
        memory: 256Mi
        cpu: 100m
      limits:
        memory: 512Mi
        cpu: 500m

kubectl apply -f deployment.yaml

O directamente:
kubectl set resources deployment mi-app --containers=mi-app --limits=memory=512Mi

Solucion 2: Ajustar requests vs limits correctamente

  • requests: la memoria que Kubernetes reserva en el nodo. Influye en el scheduling.
  • limits: el maximo que puede usar el contenedor. Si lo supera, OOMKilled.

Buena practica: limit = 2x request para apps con picos. Para apps mas predecibles: limit = 1.5x request. Nunca pongas limit igual a request si la app tiene picos.

Solucion 3: VPA para ajuste automatico

El Vertical Pod Autoscaler analiza el uso real y ajusta los requests y limits automaticamente:

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: mi-app-vpa
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: mi-app
  updatePolicy:
    updateMode: Auto

kubectl describe vpa mi-app-vpa

Solucion 4: Investigar y corregir memory leaks

  • Revisar conexiones a base de datos que no se cierran
  • Revisar listeners o handlers que no se limpian
  • Usar herramientas de profiling: pprof para Go, heapdump para Node.js, jmap para Java
  • Revisar caches en memoria sin limite de tamaño

Como monitorizar memoria para prevenir OOMKilled

Alerta Prometheus cuando el uso supera el 80% del limite:
container_memory_working_set_bytes
  / on(pod, container)
kube_pod_container_resource_limits{resource="memory"}
> 0.8

Ver uso de memoria ordenado:
kubectl top pods -n mi-namespace --sort-by=memory

Ver eventos OOMKilled en el cluster:
kubectl get events --field-selector reason=OOMKilling

Tabla resumen de diagnostico

SintomaCausaSolucion
Exit code 137, uso cerca del limiteLimite demasiado bajoSubir memory limit
Memoria sube sin parar, reinicio cada horasMemory leakCorregir en la aplicacion
OOMKilled solo bajo carga altaPicos de memoriaSubir limit o reducir concurrencia
OOMKilled sin limit definidoSin limits.memoryDefinir siempre limits.memory

Conclusion

OOMKilled siempre tiene una causa concreta. El 80% de los casos son limite demasiado bajo o memory leak. Con kubectl describe pod y kubectl top pods tienes suficiente para diagnosticarlo en minutos. Define siempre resources.requests y resources.limits en tus contenedores — sin ellos Kubernetes no puede gestionar la memoria correctamente.

Si tu pod ademas aparece como CrashLoopBackOff revisa el post sobre CrashLoopBackOff en Kubernetes. Tienes alguna causa de OOMKilled que no aparece aqui? Cuentamela en los comentarios.

¡No te pierdas los próximos posts!

¡No hacemos spam! Lee nuestra política de privacidad para obtener más información.

Publicaciones Similares

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *