Текст и данные · Инструкция
Docker restart on-failure: как ограничить число перезапусков
Параметр Docker restart on-failure полезен там, где бесконечный цикл перезапусков скрывает реальную ошибку и забивает.
Короткий ответ
Как настроить --restart=on-failure:N в Docker, изменить policy у работающего контейнера, проверить рестарты и не перепутать restart policy с healthcheck.
Что означает on-failure и когда он срабатывает
Docker считает failure завершение основного процесса контейнера с ненулевым кодом. При --restart=on-failure демон пытается запустить контейнер снова; если указать --restart=on-failure:5, после серии неудачных рестартов Docker прекратит дальнейшие попытки. Важное отличие от always: on-failure не поднимает контейнер после обычного exit 0 и не запускает его автоматически только потому, что перезапустился Docker daemon. Поэтому этот режим хорошо подходит для batch-задач и сервисов, где ненулевой код действительно означает ошибку, а нормальное завершение должно оставаться завершением. Если процесс сам ловит исключение, пишет ошибку и продолжает жить, policy также не увидит отказа. Логику выхода приложения нужно проектировать так, чтобы критический сбой завершал PID 1 осмысленным кодом.
Совет: Проверьте exit code после остановки через docker inspect. Если приложение всегда возвращает 0 даже при аварии, on-failure не поможет.
Настройка ограничения рестартов для нового контейнера
- Выберите число попыток. Для диагностики обычно лучше конечный лимит, например 3–10, чем бесконечные циклы.
- Запустите контейнер: docker run -d --name app --restart=on-failure:5 your-image.
- Убедитесь, что policy записалась: docker inspect -f "{{.HostConfig.RestartPolicy.Name}} {{.HostConfig.RestartPolicy.MaximumRetryCount}}" app.
- Имитируйте контролируемую ошибку приложения с ненулевым exit code и наблюдайте docker ps и docker events.
- После остановки попыток посмотрите docker inspect и docker logs, устраните причину, затем запустите контейнер вручную.
Предупреждение: Не тестируйте отказ на единственном экземпляре критичного сервиса в рабочее время: ограничение рестартов специально может оставить контейнер остановленным.
Как изменить policy у уже созданного контейнера
Пересобирать образ ради restart policy не нужно. Для уже созданного контейнера Docker поддерживает docker update --restart=on-failure:5 app. Это меняет конфигурацию контейнера без пересоздания image. После команды проверьте HostConfig.RestartPolicy через docker inspect. Если у вас Compose, держите настройку в compose.yaml, иначе ручной docker update легко потерять при следующем docker compose up с пересозданием. В обычном Compose используется service-level restart, например restart: "on-failure:5" там, где синтаксис и версия Compose это поддерживают; не смешивайте случайно это с deploy.restart_policy, который относится к другой модели конфигурации. Главный принцип — policy должна быть описана в том источнике конфигурации, которым вы реально управляете жизненным циклом контейнера, а не существовать только как разовая команда в истории shell.
Важно: После ручного docker update синхронизируйте декларативный compose-файл, иначе следующий recreate может вернуть старое поведение.
Почему рестарты происходят с задержкой и что значит «успешный запуск»
Docker не перезапускает аварийный контейнер с одинаковой паузой бесконечно быстро. В CLI reference описана увеличивающаяся задержка: она начинается примерно со 100 мс и удваивается до верхнего предела, чтобы не устроить шторм рестартов. Если контейнер после запуска работает не менее 10 секунд, задержка сбрасывается к исходному значению. Отдельно в правилах restart policy указано, что политика начинает нормально действовать после того, как контейнер считается успешно запущенным — он должен оставаться up как минимум 10 секунд. Это важный edge case для образов, которые мгновенно падают из-за неверного ENTRYPOINT, отсутствующей переменной или ошибки доступа к файлу: вместо попытки «лечить» это большим max-retries сначала смотрят stdout/stderr и команду запуска.
Предупреждение: Большое N не исправляет ошибку конфигурации. Если пять запусков подряд падают одинаково за доли секунды, десять тысяч повторов лишь откладывают диагностику.
on-failure, always и unless-stopped — не одно и то же
- on-failure:N. Да, до лимита N. Нет. Не как механизм on-failure. Остается остановленным
- always. Да. Да. Да. Не рестартует до daemon restart или ручного старта
- unless-stopped. Да. Да. Да, если ранее не остановлен. Остается остановленным
Совет: Выбирайте policy по смыслу процесса: «перезапусти только аварию» и «держи сервис всегда поднятым» — разные требования.
Restart policy не заменяет healthcheck и внешнее наблюдение
Контейнер может быть в состоянии Up, пока HTTP-сервис внутри него уже не отвечает, пул соединений завис или приложение попало в внутренний deadlock. В таком случае restart policy не получает события exit и ничего не предпринимает. Healthcheck решает другую задачу: выполняет проверку и помечает контейнер healthy/unhealthy, но в обычном Docker сам по себе статус unhealthy тоже не означает автоматический restart. Если нужна реакция на деградацию живого процесса, продумайте orchestration или внешний мониторинг, а также корректное завершение приложения при невосстановимой ошибке. Для диагностики серии падений смотрите docker logs, restart count и docker events. Самая надежная схема — ограниченный on-failure для процесса с корректными exit codes плюс наблюдаемость, которая сообщает оператору, что лимит исчерпан.
Важно: Если контейнер «здоров» только по факту существования PID 1, вы измеряете не то. Разделяйте процессный restart и проверку готовности сервиса.
Как проверить on-failure до запуска в продакшене
Проверять on-failure лучше на специально созданном тестовом контейнере, где вы контролируете код выхода. Сценарий должен включать как минимум три случая: процесс завершается с exit 0, процесс завершается с ненулевым кодом и контейнер останавливается вручную. В первом случае on-failure не должен запускать его снова; во втором должен сработать до заданного max-retries; ручная остановка не должна превращаться в бесконечную борьбу с daemon. После каждого сценария смотрите не только docker ps, но и HostConfig.RestartPolicy, State.ExitCode и RestartCount через docker inspect. Это особенно полезно, когда wrapper-скрипт внутри image маскирует реальную ошибку и всегда возвращает 0: внешне приложение «сломалось», но для Docker завершилось успешно, поэтому policy молчит. Также не стоит подбирать N как случайное большое число. Если сервис падает сразу из-за отсутствующего секрета или неверной переменной, дополнительные сотни попыток не лечат причину и быстро засоряют журналы. Если же кратковременный внешний сбой действительно может исчезнуть сам, конечный лимит дает приложению несколько шансов, а затем оставляет состояние стабильным для диагностики. В Compose после теста сравните декларативную настройку с docker inspect уже созданного контейнера. Это ловит типичную ошибку, когда policy поправили вручную через docker update, но забыли внести то же изменение в compose.yaml: при следующем recreate контейнер получает старое значение. И помните, что restart policy реагирует на завершение процесса, а не на то, что HTTP endpoint стал медленным или healthcheck получил статус unhealthy. Отдельно проверьте поведение после перезапуска самого Docker daemon, потому что on-failure принципиально отличается от always и unless-stopped: официальный Docker Docs прямо указывает, что on-failure не запускает контейнер только из-за рестарта daemon. Если сервис обязан подниматься после перезагрузки сервера независимо от причины предыдущей остановки, on-failure может быть не тем режимом. Такой тест стоит проводить до релиза, а не после первого обслуживания хоста, когда выясняется, что контейнер остался остановленным.
Мини-проверка перед продом
- Приложение возвращает ненулевой exit code при критической ошибке.
- MaximumRetryCount задан конечным числом и соответствует допустимому времени простоя.
- Логи переживают несколько рестартов и их можно прочитать до ротации.
- Compose/infra-конфигурация совпадает с фактическим docker inspect.
- Есть отдельный healthcheck или внешний мониторинг доступности, если сервис долгоживущий.
Что учитывать
Выберите число попыток. Для диагностики обычно лучше конечный лимит, например 3–10, чем бесконечные циклы.,Запустите контейнер: docker run -d --name app --restart=on-failure:5 your-image.,Убедитесь, что policy записалась: docker inspect -f "{{.HostConfig.RestartPolicy.Name}} {{.HostConfig.RestartPolicy.MaximumRetryCount}}" app.,Имитируйте контролируемую ошибку приложения с ненулевым exit code и наблюдайте docker ps и docker events.,После остановки попыток посмотрите docker inspect и docker…
Источники и проверка
Фактическая часть сверена по первичным источникам (в т.ч. Start containers automatically). Пример и формулировки — редакция N1RO на 2026-09-20.