Политики перезапуска контейнеров Docker

Практическая настройка restart policy в Docker и Docker Compose: no, always, unless-stopped, on-failure и проверка поведения контейнеров.

Контейнер может завершиться из-за ошибки приложения, перезапуска Docker daemon или перезагрузки сервера. Политика перезапуска определяет, должен ли Docker автоматически запустить такой контейнер снова.

В этой инструкции рассматриваются только restart policy в Docker и Docker Compose: доступные режимы, настройка, проверка и типичные ошибки.

Проверено на: Ubuntu Server 24.04 LTS и Docker Engine
Уровень сложности: начальный
Время выполнения: около 15 минут
Требуемый доступ: пользователь с доступом к Docker

Что будет рассмотрено

После выполнения инструкции можно будет:

  • выбрать подходящую политику перезапуска;
  • настроить её через docker run;
  • использовать restart policy в Docker Compose;
  • изменить политику существующего контейнера;
  • проверить автоматический запуск после сбоя;
  • отличать always от unless-stopped;
  • диагностировать контейнеры, которые постоянно перезапускаются.

Доступные политики

Docker поддерживает четыре основных режима:

no
on-failure
always
unless-stopped

no

Автоматический перезапуск отключён.

Это поведение используется по умолчанию.

no

Подходит для:

  • разовых задач;
  • тестовых контейнеров;
  • ручного запуска;
  • команд, которые должны завершиться после выполнения.

on-failure

Контейнер перезапускается только при завершении с ненулевым кодом.

on-failure

Можно ограничить количество попыток:

on-failure:5

Подходит для:

  • batch-задач;
  • обработчиков очередей;
  • сервисов, где необходимо ограничить число повторных запусков.

always

Docker пытается запускать контейнер всегда:

  • после аварийного завершения;
  • после перезапуска Docker daemon;
  • после перезагрузки сервера;
  • после ручной остановки контейнер останется остановленным только до перезапуска Docker daemon.

unless-stopped

Контейнер автоматически запускается:

  • после сбоя;
  • после перезапуска Docker daemon;
  • после перезагрузки сервера.

Но если контейнер был остановлен вручную, Docker не запускает его снова автоматически.

Для большинства постоянных сервисов это наиболее предсказуемый вариант.

Проверка текущей политики

Для конкретного контейнера:

docker inspect   --format '{{.HostConfig.RestartPolicy.Name}}'   CONTAINER_NAME

Полный объект:

docker inspect   --format '{{json .HostConfig.RestartPolicy}}'   CONTAINER_NAME

Пример результата:

{"Name":"unless-stopped","MaximumRetryCount":0}

Запуск контейнера без автоперезапуска

docker run -d   --name restart-no   --restart no   nginx:alpine

Проверьте:

docker inspect   --format '{{.HostConfig.RestartPolicy.Name}}'   restart-no

Ожидаемый результат:

no

Настройка unless-stopped

docker run -d   --name restart-unless-stopped   --restart unless-stopped   nginx:alpine

Проверьте:

docker inspect   --format '{{.HostConfig.RestartPolicy.Name}}'   restart-unless-stopped

Настройка always

docker run -d   --name restart-always   --restart always   nginx:alpine

Проверьте:

docker inspect   --format '{{.HostConfig.RestartPolicy.Name}}'   restart-always

Настройка on-failure

Создайте контейнер, который завершится с ошибкой:

docker run -d   --name restart-on-failure   --restart on-failure:3   alpine   sh -c 'exit 1'

Проверьте состояние:

docker ps -a   --filter name=restart-on-failure

Посмотрите количество перезапусков:

docker inspect   --format '{{.RestartCount}}'   restart-on-failure

Ожидается не более трёх повторных запусков.

Код завершения контейнера

Проверить код завершения:

docker inspect   --format '{{.State.ExitCode}}'   CONTAINER_NAME

Значение:

0

означает штатное завершение.

Ненулевое значение означает ошибку и может активировать политику on-failure.

Использование в Docker Compose

Пример:

services:
  web:
    image: nginx:alpine
    restart: unless-stopped
    ports:
      - "8080:80"

Проверьте конфигурацию:

docker compose config

Запустите:

docker compose up -d

Проверьте политику:

docker inspect   --format '{{.HostConfig.RestartPolicy.Name}}'   CONTAINER_NAME

Пример с on-failure в Compose

services:
  worker:
    image: alpine
    command:
      - sh
      - -c
      - exit 1
    restart: on-failure:5

Проверьте:

docker compose up -d

Посмотрите состояние:

docker compose ps -a

Изменение политики существующего контейнера

Политику можно изменить без пересоздания:

docker update   --restart unless-stopped   CONTAINER_NAME

Проверьте:

docker inspect   --format '{{.HostConfig.RestartPolicy.Name}}'   CONTAINER_NAME

Отключить автоперезапуск:

docker update   --restart no   CONTAINER_NAME

Проверка поведения после сбоя

Запустите контейнер:

docker run -d   --name restart-test   --restart unless-stopped   alpine   sh -c 'while true; do sleep 3600; done'

Проверьте PID основного процесса:

docker inspect   --format '{{.State.Pid}}'   restart-test

Завершите процесс внутри контейнера:

docker exec restart-test   sh -c 'kill 1'

Подождите несколько секунд и проверьте:

docker ps   --filter name=restart-test

Посмотрите количество перезапусков:

docker inspect   --format '{{.RestartCount}}'   restart-test

Проверка после перезапуска Docker daemon

Проверьте исходное состояние:

docker ps

Перезапустите Docker:

sudo systemctl restart docker

Проверьте контейнеры:

docker ps

Контейнеры с always и unless-stopped должны снова запуститься, если они не были остановлены вручную.

Проверка после перезагрузки сервера

Перед перезагрузкой:

docker ps   --format 'table {{.Names}}	{{.Status}}'

Перезагрузите сервер:

sudo reboot

После входа:

docker ps   --format 'table {{.Names}}	{{.Status}}'

Проверьте политику:

docker inspect   --format '{{.HostConfig.RestartPolicy.Name}}'   CONTAINER_NAME

Разница между always и unless-stopped

Рассмотрим ручную остановку:

docker stop CONTAINER_NAME

Для unless-stopped:

  • контейнер останется остановленным;
  • не будет автоматически запущен после перезапуска Docker daemon.

Для always:

  • после ручной остановки контейнер не запускается немедленно;
  • после следующего перезапуска Docker daemon он может быть запущен снова.

Поэтому для обычных постоянных сервисов часто выбирают:

unless-stopped

Что restart policy не делает

Политика перезапуска не заменяет:

  • healthcheck;
  • мониторинг;
  • исправление причины сбоя;
  • ограничение ресурсов;
  • сбор логов;
  • резервное копирование.

Контейнер может иметь статус running, но приложение внутри него может быть неисправно.

Постоянный restart loop

Если процесс сразу завершается, контейнер может постоянно перезапускаться.

Проверьте:

docker ps -a

Посмотрите статус:

docker inspect   --format '{{.State.Status}} {{.State.ExitCode}} {{.RestartCount}}'   CONTAINER_NAME

Посмотрите логи:

docker logs   --tail 100   CONTAINER_NAME

Для Compose:

docker compose logs   --tail=100   SERVICE_NAME

Временное отключение restart loop

Отключите политику:

docker update   --restart no   CONTAINER_NAME

Остановите контейнер:

docker stop CONTAINER_NAME

После исправления конфигурации верните политику:

docker update   --restart unless-stopped   CONTAINER_NAME

Пересоздание контейнера через Compose

Если политика изменена в compose.yaml, примените:

docker compose up -d

Для гарантированного пересоздания:

docker compose up -d --force-recreate

Проверьте:

docker compose ps

Проверка всех контейнеров

Вывести имена и политики:

for container in $(docker ps -aq); do
  docker inspect     --format '{{.Name}} {{.HostConfig.RestartPolicy.Name}}'     "$container"
done

Убрать начальный символ /:

for container in $(docker ps -aq); do
  docker inspect     --format '{{trimPrefix "/" .Name}} {{.HostConfig.RestartPolicy.Name}}'     "$container"
done

Если установлен jq, можно использовать:

docker inspect $(docker ps -aq) |
jq -r '.[] |
  [.Name[1:], .HostConfig.RestartPolicy.Name] |
  @tsv'

Рекомендуемый выбор

Для постоянного веб-сервиса:

restart: unless-stopped

Для worker с ограничением попыток:

restart: on-failure:5

Для разовой команды:

restart: "no"

Для системного сервиса, который должен запускаться после каждого перезапуска Docker daemon:

restart: always

Почему no лучше брать в кавычки в YAML

В YAML значение:

restart: no

может быть интерпретировано как логическое значение.

Безопасный вариант:

restart: "no"

Типичные проблемы

Контейнер не запускается после перезагрузки

Проверьте политику:

docker inspect   --format '{{.HostConfig.RestartPolicy.Name}}'   CONTAINER_NAME

Проверьте Docker:

systemctl status docker --no-pager

Проверьте журнал:

sudo journalctl -u docker -b --no-pager

unless-stopped не запустил контейнер

Возможно, контейнер был остановлен вручную до перезагрузки.

Запустите его:

docker start CONTAINER_NAME

Контейнер постоянно перезапускается

Проверьте:

docker logs --tail 100 CONTAINER_NAME

Отключите restart policy на время диагностики:

docker update --restart no CONTAINER_NAME

on-failure не перезапускает контейнер

Проверьте код завершения:

docker inspect   --format '{{.State.ExitCode}}'   CONTAINER_NAME

Если код равен 0, завершение считается успешным.

Изменения Compose не применились

Проверьте итоговую конфигурацию:

docker compose config

Пересоздайте контейнер:

docker compose up -d --force-recreate

Быстрый набор команд

Проверить политику:

docker inspect   --format '{{.HostConfig.RestartPolicy.Name}}'   CONTAINER_NAME

Изменить на unless-stopped:

docker update   --restart unless-stopped   CONTAINER_NAME

Отключить:

docker update   --restart no   CONTAINER_NAME

Проверить число перезапусков:

docker inspect   --format '{{.RestartCount}}'   CONTAINER_NAME

Посмотреть логи:

docker logs   --tail 100   CONTAINER_NAME

Удаление тестовых контейнеров

docker rm -f   restart-no   restart-unless-stopped   restart-always   restart-on-failure   restart-test   2>/dev/null

Итог

После выполнения инструкции:

  • рассмотрены все основные restart policy;
  • настроены no, on-failure, always и unless-stopped;
  • проверено поведение после сбоя;
  • изменена политика существующего контейнера;
  • показано использование в Docker Compose;
  • разобран постоянный цикл перезапуска;
  • объяснена разница между always и unless-stopped.

Для большинства постоянно работающих контейнеров разумным базовым выбором является unless-stopped, но окончательная политика зависит от назначения сервиса.

← Предыдущая статья Healthcheck в Docker Compose Следующая статья → Безопасная очистка Docker от неиспользуемых данных