Траблшутинг ошибки Exit Code 137 (OOMKilled) в Docker: профилирование cgroups
- Контейнер внезапно останавливается с кодом завершения
Exit Code 137. - В выводе
docker inspect <id>параметрOOMKilledравенtrue. - В логах
dmesgфиксируется сообщениеMemory cgroup out of memory: Killed process. - Высокое потребление памяти приложениями на Java (JVM), Node.js или Python при пиковых нагрузках.
1. Проверка факта срабатывания OOM Killer
docker inspect <container_name> --format='{{.State.ExitCode}} OOMKilled={{.State.OOMKilled}}'2. Анализ реального потребления памяти через cgroups
Для cgroups v2:
CID=$(docker inspect --format='{{.Id}}' <container_name>)
cat /sys/fs/cgroup/system.slice/docker-${CID}.scope/memory.current
cat /sys/fs/cgroup/system.slice/docker-${CID}.scope/memory.eventsДля cgroups v1:
cat /sys/fs/cgroup/memory/docker/${CID}/memory.usage_in_bytes
cat /sys/fs/cgroup/memory/docker/${CID}/memory.failcnt3. Мониторинг в реальном времени
docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}"4. Корректировка лимитов памяти
Задайте жесткий лимит (hard limit) и выделите пространство под swap:
docker run -d --name app_service --memory="2g" --memory-swap="3g" --memory-reservation="1.5g" my_image:latest5. Тюнинг JVM для работы внутри контейнеров
Добавьте флаги управления памятью в Dockerfile / Entrypoint:
ENV JAVA_OPTS="-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0" Частые вопросы (FAQ)
Почему код завершения именно 137?
Код 137 вычисляется по формуле 128 + N, где N — номер сигнала, убившего процесс. В случае OOM Killer ядро Linux отправляет сигнал SIGKILL (сигнал 9), поэтому 128 + 9 = 137.
В чем разница между --memory и --memory-reservation?
--memory задает жесткий предел (Hard Limit), при превышении которого процесс немедленно уничтожается. --memory-reservation задает мягкий предел (Soft Limit), который активируется только тогда, когда на хосте начинает заканчиваться память.