search
Linux 4 min read

systemd-oomd y Docker limits: lo que nadie te cuenta para proteger tu sistema

Pablo IB

TL;DR: Habilita systemd-oomd — protege tu escritorio matando procesos selectivamente cuando la memoria falla. Si usas Docker, pon límites de memoria a tus containers — sin límite, un container con fuga puede comerse toda la RAM del host.


Todo lo anterior — zram, sysctl, swap por capas — da más margen. Pero si un proceso crece 10 GB por una fuga de memoria, solo hay dos cosas que pueden salvar tu sesión: un OOM killer inteligente y containers con límites.

Este artículo tiene dos partes independientes:

  1. systemd-oomd — para todos, uses o no Docker
  2. Docker limits — solo si usas Docker

systemd-oomd: mata el proceso, no el escritorio

El OOM killer del kernel no es inteligente. Mata lo que más pese, no lo que más convenga. Y si el proceso culpable corre dentro del cgroup de gnome-shell, systemd marca todo el servicio como fallido — gnome-shell muere con él.

systemd-oomd es el userspace OOM killer de systemd. Entiende cgroups y puede matar procesos selectivamente.

Configuración

# Crear configuración
sudo mkdir -p /etc/systemd/oomd.conf.d
sudo tee /etc/systemd/oomd.conf.d/10-defaults.conf << 'EOF'
[OOM]
SwapUsedLimit=90%
DefaultMemoryPressureLimit=60%
DefaultMemoryPressureDurationSec=30s
EOF

# Habilitar
sudo systemctl enable --now systemd-oomd

Qué hace:

  • Si el swap supera 90% de uso, mata procesos para liberar memoria
  • Si un cgroup tiene más del 60% de presión de memoria durante 30 segundos, mata procesos dentro de ese cgroup (no el padre)
  • Si tu IDE se descontrola dentro del cgroup de GNOME, mata la IDE, no el escritorio

Verificar

systemctl status systemd-oomd
# Active: active (running)

Limitación

systemd-oomd no previene el OOM del kernel. Si zram se satura globalmente, el kernel invoca su propio OOM killer antes de que systemd-oomd reaccione. Por eso necesitas las otras capas (zram, sysctl, swap disco).


Docker limits: containers sin límite son una bomba

¿No usas Docker? Puedes saltarte esta sección. Lo anterior (systemd-oomd) ya te protege.

Si usas Docker, probablemente tus containers no tienen límite de memoria:

docker inspect --format '{{.Name}} | Memory={{.HostConfig.Memory}}' $(docker ps -q)

Si todos dicen Memory=0, no hay límite. Un container con fuga de memoria puede comerse toda la RAM del host sin que nada lo pare.

En docker-compose.yml

services:
  postgres:
    image: postgres:16-alpine
    deploy:
      resources:
        limits:
          memory: 2G

Nota sobre memory-swap: define el total máximo de RAM + swap que el container puede usar:

# Container puede usar 2G RAM + 2G swap = 4G total
deploy:
  resources:
    limits:
      memory: 2G
      memory-swap: 4G

# Container limitado a 2G total, sin acceso a swap
deploy:
  resources:
    limits:
      memory: 2G
      memory-swap: 2G

Para containers ya corriendo

Sin recrear el container, puedes aplicar límites temporalmente:

docker update --memory 2g --memory-swap 2g nombre-del-container

Ojo: esto se pierde si el container se recrea. Para hacerlo persistente, actualiza el compose file.

Qué pasa cuando un container supera el límite

Docker mata el proceso dentro del container con OOM kill. El host no se ve afectado. El container aparece como OOMKilled en docker ps -a, y puedes reiniciarlo.

Guía rápida de límites por tipo de servicio

Tipo de servicioLímite recomendadoEjemplos
Base de datos2-4 GBpostgres, mysql
Message broker256-512 MBnats, redis
API / Backend512 MB - 1 GBgotrue, postgrest
Frontend / Studio1 GBsupabase-studio
Utilidad128-256 MBadminer, inbucket

La regla: empieza con 2-3x el uso normal y ajusta:

docker stats --no-stream --format "table {{.Name}}\t{{.MemUsage}}\t{{.MemPerc}}"

Monitorización: comandos útiles

# Estado de zram
zramctl

# Uso de swap
swapon --show

# Memoria total
free -h

# systemd-oomd
systemctl status systemd-oomd

# Sysctl
sysctl vm.swappiness vm.page-cluster vm.watermark_scale_factor

# OOM scores de procesos
ps -eo pid,comm,rss:10,oom_score:8,oom_score_adj:12 --sort=-rss | head -20

Signos de alarma

  • zramctl muestra DATA cercano a DISKSIZE → zram casi lleno
  • Free swap en los logs del kernel es menor a 1 GB → poco margen
  • dmesg | grep -i oom muestra actividad reciente → el sistema sigue bajo presión

Qué NO hacer

No instalar earlyoom Y systemd-oomd a la vez

Ambos son OOM killers en userspace. Si están activos los dos, pueden competir por matar el mismo proceso y causar condiciones de carrera. Usa solo systemd-oomd.

No cambiar OOMPolicy en gnome-shell

La tentación es cambiar OOMPolicy=stop a OOMPolicy=continue. Pero gnome-shell espera que sus procesos hijos funcionen. Si un hijo muere a medio render, el estado puede quedar inconsistente. Mejor prevenir con systemd-oomd.

No confiar solo en sysctl --system

Una regla udev de tu distribución puede reescribir swappiness cada vez que zram cambia de estado. Siempre verifica con cat /proc/sys/vm/swappiness después de cambios.


Artículos de esta serie

  1. Cómo duplicar la RAM de tu Linux con zram y swap comprimida (sin comprar nada)
  2. zram: mitad de RAM, algoritmo zstd y por qué tu distro lo tiene mal configurado
  3. Swappiness 180: el valor que hace funcionar zram (y la regla udev que te lo estaba impidiendo)
  4. RAM → zram → swap en disco: cómo montar un sistema de swap por capas y probarlo con stress-ng
  5. systemd-oomd y Docker limits: lo que nadie te cuenta para proteger tu sistema ← estás aquí

Referencias