Restart loop — состояние, при котором контейнер запускается, завершается с ошибкой и сразу стартует снова, повторяя цикл бесконечно. В выводе
Команда
Более детальную информацию даёт
Exit-код сразу сужает круг поиска:
Логи — основной источник информации о причине падения. Docker перехватывает STDOUT и STDERR процесса и сохраняет их через logging driver.
Если контейнер перезапускается каждые несколько секунд,
При использовании нестандартного logging driver (например,
Контейнер существует, пока работает его PID 1. Если основной процесс выполнил задачу и вышел, контейнер останавливается. При restart policy
Типичный случай: скрипт инициализации без foreground-процесса.
Ядро Linux убивает процесс, когда контейнер превышает лимит памяти. Проверить:
Если вывод
Образ собран на одной базе, а запускается на другой, или multi-stage build не скопировал зависимости. Логи покажут
Проверка:
Приложение стартует, читает конфиг, обнаруживает неверный параметр и выходит с кодом 1. Частые примеры:
Контейнер пытается подключиться к БД, Redis или другому сервису, который ещё не готов. Без retry-логики процесс падает. Решение — healthcheck и depends_on с условием
Docker предоставляет restart policy через флаг
Важные нюансы из документации Docker:
Изменить политику для уже созданного контейнера:
Отключить перезапуск, чтобы остановить loop и провести диагностику:
Поток событий Docker в реальном времени показывает, что происходит с контейнером:
Вывод фиксирует события
Если контейнер упирается в лимиты CPU или памяти, он может работать нестабильно. Посмотреть текущие ограничения:
Статистику потребления в реальном времени:
Если память близка к лимиту, а
Чтобы исследовать файловую систему упавшего контейнера без его перезапуска:
Для более глубокой отладки можно переопределить entrypoint:
Это позволяет вручную запустить проблемную команду и увидеть ошибку в интерактивном режиме.
Установка
Игнорирование healthcheck. Без healthcheck Docker считает контейнер «работающим», даже если приложение внутри уже не отвечает. Добавьте
Смешивание restart policy и внешнего process manager. Документация Docker прямо не рекомендует комбинировать restart policy с systemd-юнитами или supervisor для одного и того же контейнера — это создаёт конфликты.
Отсутствие логирования. Если logging driver не настроен или логи ротируются слишком агрессивно, в момент падения контейнера вы не увидите причину.
docker ps такой контейнер отображается со статусом Restarting или быстро переключается между Up и Exited. Проблема не в самом Docker, а в том, что процесс внутри контейнера не может работать стабильно.Первый шаг: определить exit-код и статус
Команда
docker ps показывает текущее состояние, но для диагностики нужен последний exit-код:
Bash:
docker ps -a --filter "name=mycontainer" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
Более детальную информацию даёт
docker inspect:
Bash:
docker inspect --format='{{.State.ExitCode}} {{.State.OOMKilled}} {{.State.Error}}' mycontainer
Exit-код сразу сужает круг поиска:
| Код | Типичная причина |
|---|---|
| 0 | Процесс завершился штатно — контейнер не рассчитан на длительную работу |
| 1 | Ошибка приложения (исключение, неверная конфигурация) |
| 2 | Ошибка shell-скрипта или misuse команды |
| 126 | Файл найден, но не является исполняемым |
| 127 | Команда или бинарник не найдены |
| 137 | SIGKILL — чаще всего OOM-kill |
| 139 | SIGSEGV — segmentation fault |
| 143 | SIGTERM — graceful shutdown по таймауту |
Чтение логов контейнера
Логи — основной источник информации о причине падения. Docker перехватывает STDOUT и STDERR процесса и сохраняет их через logging driver.
Bash:
## Последние 100 строк
docker logs --tail 100 mycontainer
## С временными метками
docker logs --timestamps mycontainer
## Непрерывное чтение (аналог tail -f)
docker logs --follow mycontainer
## Логи за последний час
docker logs --since 1h mycontainer
Если контейнер перезапускается каждые несколько секунд,
--follow покажет вывод каждого цикла. Обратите внимание на повторяющиеся сообщения об ошибках: они указывают на конкретную причину.При использовании нестандартного logging driver (например,
json-file с ограничениями или syslog) убедитесь, что логи вообще пишутся. Проверить активный driver можно через docker inspect:
Bash:
docker inspect --format='{{.HostConfig.LogConfig.Type}}' mycontainer
Частые причины restart loop
Процесс завершается штатно (exit 0)
Контейнер существует, пока работает его PID 1. Если основной процесс выполнил задачу и вышел, контейнер останавливается. При restart policy
always или unless-stopped Docker немедленно перезапустит его — и цикл повторится.Типичный случай: скрипт инициализации без foreground-процесса.
Код:
## Плохо: скрипт отработал и вышел
CMD ["/init.sh"]
## Хорошо: процесс остаётся на переднем плане
CMD ["nginx", "-g", "daemon off;"]
OOM-kill (exit 137)
Ядро Linux убивает процесс, когда контейнер превышает лимит памяти. Проверить:
Bash:
docker inspect --format='{{.State.OOMKilled}}' mycontainer
Если вывод
true, нужно либо увеличить лимит памяти (--memory), либо оптимизировать потребление внутри приложения. На хосте событие также фиксируется в dmesg:
Bash:
dmesg | grep -i "oom\|killed process"
Отсутствующий бинарник или библиотека (exit 127 / 126)
Образ собран на одной базе, а запускается на другой, или multi-stage build не скопировал зависимости. Логи покажут
not found или permission denied.Проверка:
Bash:
docker run --rm --entrypoint /bin/sh myimage -c "which myapp && ldd /usr/bin/myapp"
Ошибка конфигурации приложения
Приложение стартует, читает конфиг, обнаруживает неверный параметр и выходит с кодом 1. Частые примеры:
- Неверный формат переменных окружения
- Недоступная база данных или брокер сообщений на момент старта
- Ошибка в YAML/TOML-конфиге
Зависимость от внешнего сервиса
Контейнер пытается подключиться к БД, Redis или другому сервису, который ещё не готов. Без retry-логики процесс падает. Решение — healthcheck и depends_on с условием
service_healthy (в Docker Compose), либо retry-логика в самом приложении.Как работают restart policy
Docker предоставляет restart policy через флаг
--restart при создании контейнера. Доступные значения:| Политика | Поведение |
|---|---|
no | Не перезапускать (по умолчанию) |
on-failure[:N] | Перезапускать только при ненулевом exit-коде, опционально до N попыток |
always | Перезапускать при любом завершении, включая ручную остановку после рестарта демона |
unless-stopped | Как always, но не перезапускать, если контейнер был остановлен вручную |
Важные нюансы из документации Docker:
- Правило 10 секунд. Restart policy вступает в силу только после того, как контейнер проработал минимум 10 секунд. Если процесс падает сразу, Docker не входит в бесконечный цикл перезапусков — контейнер остаётся в статусе
Exited.
- Ручная остановка. Если вы выполнили
docker stop, restart policy игнорируется до перезапуска демона Docker или явногоdocker start.
Изменить политику для уже созданного контейнера:
Bash:
docker update --restart unless-stopped mycontainer
Отключить перезапуск, чтобы остановить loop и провести диагностику:
Bash:
docker update --restart no mycontainer
docker stop mycontainer
Диагностика через docker events
Поток событий Docker в реальном времени показывает, что происходит с контейнером:
Bash:
docker events --filter container=mycontainer
Вывод фиксирует события
die, restart, start, kill с временными метками. Если между die и start проходит менее секунды — это подтверждение restart loop.Проверка resource limits
Если контейнер упирается в лимиты CPU или памяти, он может работать нестабильно. Посмотреть текущие ограничения:
Bash:
docker inspect --format='Memory: {{.HostConfig.Memory}}, CPUs: {{.HostConfig.NanoCpus}}' mycontainer
Статистику потребления в реальном времени:
Bash:
docker stats mycontainer --no-stream
Если память близка к лимиту, а
OOMKilled равен true — проблема подтверждена.Временная остановка loop для отладки
Чтобы исследовать файловую систему упавшего контейнера без его перезапуска:
Bash:
## Остановить и убрать restart policy
docker update --restart no mycontainer
docker stop mycontainer
## Создать новый контейнер из того же образа с shell
docker run --rm -it myimage /bin/sh
## Или примонтировать файловую систему остановленного контейнера
docker export mycontainer > /tmp/container_fs.tar
Для более глубокой отладки можно переопределить entrypoint:
Bash:
docker run --rm -it --entrypoint /bin/sh myimage
Это позволяет вручную запустить проблемную команду и увидеть ошибку в интерактивном режиме.
Типичные ошибки при исправлении
Установка
--restart always без понимания причины. Это маскирует проблему: контейнер продолжает падать, но Docker упорно его перезапускает, расходуя ресурсы.Игнорирование healthcheck. Без healthcheck Docker считает контейнер «работающим», даже если приложение внутри уже не отвечает. Добавьте
HEALTHCHECK в Dockerfile или healthcheck в Compose-файл.Смешивание restart policy и внешнего process manager. Документация Docker прямо не рекомендует комбинировать restart policy с systemd-юнитами или supervisor для одного и того же контейнера — это создаёт конфликты.
Отсутствие логирования. Если logging driver не настроен или логи ротируются слишком агрессивно, в момент падения контейнера вы не увидите причину.
Чек-лист диагностики
docker ps -a— зафиксировать статус и количество рестартов.
docker inspect— получить exit-код, флаг OOMKilled, текст ошибки.
docker logs --tail 200— прочитать вывод приложения перед падением.
docker events --filter container=...— убедиться, что цикл действительно происходит.
docker stats— проверить потребление памяти и CPU относительно лимитов.
- При необходимости — отключить restart policy, запустить контейнер с shell и воспроизвести ошибку вручную.
- После исправления — вернуть подходящую restart policy (
unless-stoppedдля продакшена,on-failure:3для задач с ограниченным числом попыток).
