Docker Compose: Service exited with code 137 — Причины и решение
Механизм завершения SIGKILL и работа подсистемы Linux OOM Killer
Ошибка Service exited with code 137 означает, что процесс PID 1 внутри контейнера был принудительно завершен системным сигналом SIGKILL (Сигнал 9). По стандарту POSIX, код завершения вычисляется как 128 + номер сигнала (128 + 9 = 137). В большинстве случаев инициатором отправки SIGKILL выступает подсистема ядра Linux Out-Of-Memory (OOM) Killer из-за превышения жесткого лимита памяти, установленного в параметрах контейнера (deploy.resources.limits.memory), либо из-за полного исчерпания свободной оперативной памяти на самом хост-сервере.
Бизнес-риски:
Внезапное падение production-сервисов в моменты пиковых нагрузок, потеря несохраненных транзакций в оперативной памяти (Redis, Memcached), повреждение кэшей.
Таблица анализа признаков завершения процесса с кодом 137
| Источник сигнала SIGKILL | Причина инициализации | Где фиксируется событие |
|---|---|---|
| Linux Kernel OOM Killer | Превышение лимита cgroup memory.max | dmesg -T / /var/log/messages / docker inspect |
| Host Global OOM | Полная нехватка RAM на физическом сервере | Системный журнал ядра (Out of memory: Kill process) |
| Ручной/Автоматический docker stop | Таймаут graceful shutdown (SIGTERM -> SIGKILL) | Логи Docker Daemon dockerd |
Пошаговое расследование OOM-падений и балансировка памяти
Сценарий 1: Проверка флага OOMKilled через Docker Inspect
Убедитесь, что причиной завершения был именно механизм OOM Killer ядра Linux:
# Проверка точной причины остановки контейнера
docker inspect <container_name_or_id> --format='OOMKilled: {{.State.OOMKilled}}, ExitCode: {{.State.ExitCode}}'
# Результат 'OOMKilled: true' подтверждает нехватку памяти.Сценарий 2: Поиск событий OOM Killer в системных логах хоста
Проанализируйте лог ядра для выявления объемов утилизации памяти в момент падения:
# Поиск записей OOM killer в системном буфере ядра
dmesg -T | grep -i -E 'oom[-_]killer|killed process'
# В journalctl:
journalctl -k --grep='Out of memory' --since '1 hour ago'Сценарий 3: Оптимизация лимитов памяти в docker-compose.yml
Выделите сервису достаточный объем памяти и настройте параметры резервирования:
services:
web-app:
image: myheavy-app:latest
deploy:
resources:
limits:
# Увеличение жесткого лимита памяти
memory: 2048M
reservations:
# Гарантированный объем памяти для контейнера
memory: 512M
# Увеличение таймаута на graceful shutdown:
stop_grace_period: 30sТиповые ошибки администраторов
- Запуск Java-приложений без параметров MaxRAMPercentage: JVM по умолчанию может пытаться занять больше памяти, чем выделено контейнеру в cgroups, что немедленно вызывает SIGKILL 137.
- Отсутствие Swap на хостовом сервере: При кратковременных спайках нагрузки отсутствие swap приводит к немедленному срабатыванию OOM Killer вместо временного замедления.
ITSTM проведет профилирование потребления памяти приложениями, оптимизирует настройки JVM/Node.js и ликвидирует утечки RAM.
Частые вопросы (FAQ)
Может ли команда docker stop вызывать Exit Code 137?
Да. Если приложение не успевает завершиться по сигналу SIGTERM за отведенное время (по умолчанию 10 секунд), Docker отправляет принудительный SIGKILL.
Как настроить Java (JVM) внутри Docker для предотвращения OOM 137?
Используйте флаги JVM: -XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0, чтобы среда не выходила за пределы лимита памяти контейнера.
Поможет ли директива restart: always при падении 137?
Контейнер перезапустится, но если нагрузка или утечка памяти сохраняются, он войдет в бесконечный цикл падений (CrashLoop).
Как мониторить потребление памяти контейнерами в реальном времени?
Используйте команду docker stats или настройте экспорт метрик через Prometheus cAdvisor.