Ваш контейнер внезапно остановился, а в логах docker inspect вы видите зловещий «OOMKilled»: true и код выхода 137? Не паникуйте. Это одна из самых частых проблем в Docker, и она всегда имеет конкретную техническую причину.
Код 137 означает, что контейнер был убит системой принудительно (SIGKILL). В 99% случаев это делает ядро Linux через механизм OOM Killer, когда контейнер превышает выделенный лимит памяти.
Что именно означает код 137?
Формула проста: 128 + 9 = 137.
- 128 — базовый код выхода для сигналов
- 9 — номер сигнала SIGKILL (принудительное завершение)
Когда вы видите этот код, система буквально говорит: «Этот процесс съел слишком много RAM, и я его уничтожила, чтобы спасти хост».
Шаг 1: Диагностика — подтвердите OOMKilled
Прежде чем увеличивать память, убедитесь, что причина именно в ней.
# Проверьте статус последнего запуска контейнера
docker inspect --format='{{.State.OOMKilled}}' <container_name>
# Если вывод "true" — это точно нехватка памяти
# Если "false" — ищите другую причину (см. раздел ниже)
Шаг 2: Увеличение лимитов памяти
Самое очевидное решение. Но важно сделать это правильно.
Для docker run:
# Выделяем 2GB RAM + 1GB swap
docker run -m 2g --memory-swap 3g my_image
Для docker-compose.yml:
services:
app:
image: my_image
deploy:
resources:
limits:
memory: 2G
reservations:
memory: 1G
Важно: Всегда оставляйте запас 20-30% от реального потребления приложения. Если приложение ест 1.8GB, ставьте лимит минимум 2.5GB.
Шаг 3: Поиск утечек памяти
Если увеличение лимита помогает лишь временно, значит в приложении утечка памяти.
Мониторинг в реальном времени:
# Смотрим потребление памяти контейнером
docker stats <container_name>
# Или более детально через cgroups
cat /sys/fs/cgroup/memory/docker/<container_id>/memory.usage_in_bytes
Для PHP-приложений (WordPress/Laravel):
- Проверьте
memory_limitв php.ini - Используйте Xdebug Profiler для поиска утечек
- Очистите кэш OPcache
Для Node.js:
# Увеличьте heap size явно
node --max-old-space-size=2048 app.js
Шаг 4: Проверьте хост-машину
Иногда контейнер невиновен. Если на хосте закончилась RAM, OOM Killer выбирает жертву случайно (обычно самый прожорливый процесс).
# Проверьте общую память хоста
free -h
# Посмотрите, кто убил контейнер в системных логах
dmesg | grep -i "killed process"
journalctl -xe | grep -i oom
Другие причины кода 137 (не OOM)
Если OOMKilled: false, но код всё равно 137:
- Ручной docker kill — кто-то или скрипт отправил SIGKILL
- Systemd/AppArmor — политики безопасности убивают процесс
- Orchestrator — Kubernetes/Docker Swarm перезапускает контейнер из-за liveness probe
Чек-лист профилактики
- Всегда задавайте
--memoryи--memory-swap - Настройте алерты на потребление RAM (Prometheus/Grafana)
- Используйте health checks вместо бесконечных рестартов
- Регулярно обновляйте образы (фиксы утечек)
- Тестируйте нагрузку перед продом (
stress-ng)
Что делать, если проблема не решается?
Можно ли отключить OOM Killer?
Технически да (oom_score_adj=-1000), но никогда так не делайте. Лучше пусть упадёт один контейнер, чем зависнет весь сервер.
Почему контейнер падает только ночью?
Вероятно, запускается cron-задача (бэкап, индексация, очистка), которая потребляет больше памяти, чем дневная нагрузка.
Как отличить утечку от нормальной нагрузки?
Утечка — это монотонный рост памяти без падения после GC. Нормальная нагрузка — пики и спады. Смотрите график docker stats за 24 часа.
В статье про Docker добавьте ссылку на первую: «Если вы используете Docker для WordPress и столкнулись с белым экраном, читайте наше полное руководство по WSOD