Skip to main content

Що таке restart policy і які варіанти існують?

Docker restart policy автоматизує resilience container. Crash? Daemon рестартує. Host reboot? Container повертається. Чотири опції trade-off контроль vs автоматизація по-різному, обирай за тим, що хочеш, щоб container переживав.

Теорія

TL;DR

  • --restart=<policy> на docker run (або restart: <policy> у Compose) ставить політику.
  • Чотири значення: no, on-failure[:N], always, unless-stopped.
  • Прод-дефолт: unless-stopped, переживає crash і host reboot, поважає ручний stop.
  • Дефолт, якщо не вказано: no, container виходить і лишається exited.
  • Restart-policy спрацьовує на exit container, незалежно від того, чи exit чистий (0) чи ні. Фільтр по коду це те, що додає on-failure.

Чотири політики

ПолітикаНа exit (будь-який код)На exit код 0Після host-rebootПоважає ручний stop
no (дефолт)нінініn/a
on-failure[:N]так, якщо код != 0, до N разівніні (не переживає reboot)так
alwaysтактактакні (рестартує навіть після stop)
unless-stoppedтактактак (якщо було running)так

no — дефолт

bash
docker run myapp # Crash → exited. Лишається exited. # Host reboot → container не повертається.

Нормально для одноразових команд (docker run --rm для CI-job). Неправильно для будь-якого сервісу, що має крутитися.

on-failure[:N] — рестарт на crash до N разів

bash
docker run --restart=on-failure myjob # необмежено retry на non-zero exit docker run --restart=on-failure:5 myjob # макс 5 retry

Бери для batch-job, що мають retry на transient failure, але врешті здаватися. Host-reboot їх не повертає (вони job, не service).

always — рестарт незважаючи ні на що

bash
docker run --restart=always mysvc # Crash, чистий exit, host reboot → daemon його повертає кожного разу. # Навіть після `docker stop` daemon його рестартує.

Назва буквальна: ЗАВЖДИ. Включно після ручного stop, щоб реально зупинити, маєш зробити docker rm. Дивує; зазвичай хочеш unless-stopped.

unless-stopped — прод-дефолт

bash
docker run --restart=unless-stopped mysvc # Crash → restart. Host reboot → restart. Ручний `docker stop` → ЛИШАЄТЬСЯ зупинений.

Правильна політика для 95% довгоживучих сервісів. Daemon рестартує на failure або reboot; поважає твій намір, коли ти зупиняєш вручну.

Як взаємодіє з daemon

  • На exit container: daemon перевіряє політику і вирішує, чи рестартувати.
  • На рестарт daemon (systemctl restart docker): container з always і unless-stopped (що були running до рестарту) повертаються. on-failure НІ, він per-exit only.
  • На host reboot: те саме, що рестарт daemon.
  • Daemon використовує експоненційний backoff між retry: 100мс, 200мс, 400мс, ... до cap. Запобігає hot-loop crash-шторму.

Compose-синтаксис

yaml
services: api: image: myapp restart: unless-stopped # найпоширеніше worker: image: myworker restart: on-failure # job-style oneoff: image: alpine command: echo hi restart: "no" # one-shot

Нота: "no" у YAML треба брати у лапки, інакше YAML парсить як boolean false.

Типові помилки

Забути поставити політику на довгоживучий сервіс

bash
# НЕПРАВИЛЬНО: дефолт "no"; container не переживає host reboot docker run -d --name api -p 80:80 myapp # ПРАВИЛЬНО docker run -d --name api -p 80:80 --restart=unless-stopped myapp

Це найпоширеніша operations-помилка на single-host деплоях. Container працює, ідеш додому, host рестартується вночі, сервіс down і телефон дзвонить.

Брати always і дивуватися, що ручний stop не тримається

bash
$ docker run -d --name api --restart=always myapp $ docker stop api $ docker ps # api повернувся

always буквально означає завжди. Бери unless-stopped, якщо хочеш, щоб ручний stop поважався.

Crash-loop без фільтра exit-коду

bash
# Container exit з кодом 0, але ти хочеш рестарт тільки на failure docker run --restart=always myjob # Рестартує вічно, навіть на чистих exit. Скоріш за все не те, що хочеш. # Краще: docker run --restart=on-failure myjob

Забути, що on-failure не переживає reboot

Якщо container paused або running, коли ти reboot'аєш, on-failure його не повертає. Бери unless-stopped, якщо потрібне виживання reboot.

Restart policy + healthcheck

Docker restart-policy реагує на exit процесу, не на unhealthy healthcheck. Unhealthy container, що не вийшов, не рестартується Docker. Щоб діяти на healthcheck:

  • Swarm замінює unhealthy task новими (налаштовується).
  • Compose з condition: service_healthy лише gate'ує startup, не runtime-рестарт.
  • Звичайний Docker: external watchdog (autoheal-container, кастомний скрипт) може docker restart на основі health-статусу.
bash
# willfarrell/autoheal: моніторить і auto-restart unhealthy container docker run -d \ --name autoheal \ -v /var/run/docker.sock:/var/run/docker.sock \ -e AUTOHEAL_CONTAINER_LABEL=autoheal \ willfarrell/autoheal docker run -d --label=autoheal=true --health-cmd="..." myapp

Реальне застосування

  • Прод single-host сервіси: unless-stopped всюди, майже без винятків.
  • CI / build container: без restart-policy (дефолт no). Крутяться, виходять, лишаються exited.
  • Background-worker: on-failure:N, щоб transient-краши retry, а permanently-broken job урешті здавалося.
  • Критична інфраструктура (host від нього залежить): іноді always виправдане, наприклад, security-агент, що має бути up незважаючи на.

Питання для поглиблення

Q: Яка різниця між always і unless-stopped?


A: always рестартує навіть після ручного docker stop. unless-stopped ні. Обидва переживають crash і host reboot; різниця в тому, чи поважається твій намір (docker stop).

Q: Чи застосовується restart-policy, якщо я docker rm container?


A: Ні, як видалено, нема чого рестартувати. Політики оперують на існуючих container.

Q: Як побачити, яка політика у container?


A: docker inspect <name> --format '{{.HostConfig.RestartPolicy.Name}}'. Повертає always, unless-stopped, on-failure або порожнє для no.

Q: Чи --restart застосовується у Swarm-сервісі?


A: Ні. Swarm-сервіси беруть restart_policy: у deploy-config (з condition: any|on-failure|none, delay, max_attempts). Флаг --restart для standalone-container.

Q: (Senior) Коли НЕ варто використовувати restart-policy взагалі?


A: Коли щось інше відповідальне за life-cycle container. K8s-pod керується kubelet, Docker restart-policy нерелевантна всередині K8s-pod (і ігнорується). Те саме для systemd-managed container через docker run --rm з unit. Правило: один restart-authority per container; обери оркестрацію, що володіє ним.

Приклади

Production-style сервіс з кількома шарами resilience

bash
$ docker run -d \ --name api \ --restart=unless-stopped \ -p 3000:3000 \ -v api_data:/data \ --health-cmd='curl -f http://localhost:3000/health || exit 1' \ --health-interval=30s \ --memory=512m \ myapp:1.0
  • Crash процесу → daemon рестартує через політику.
  • Host reboot → container повертається.
  • Ручний docker stop → лишається зупиненим (ти знаєш, що зробив).
  • Healthcheck робить статус видимим для моніторингу + reverse proxy.

Compose: різні політики per service

yaml
services: api: image: myapp restart: unless-stopped worker: image: myworker restart: on-failure # batch retry migrator: image: mymigrator restart: "no" # one-shot, не рестартити profiles: [migrate] # opt-in profile

Різні форми роботи, різні політики. Migrator має крутитися раз і лишатися exited.

Cap retry, щоб запобігти нескінченних циклів

bash
$ docker run -d --name flaky --restart=on-failure:3 myjob # Після 3 non-zero exit daemon припиняє пробувати. $ docker ps -a --filter name=flaky --format '{{.Status}}' Exited (1) 5 seconds ago # фінальний стан, без retry

on-failure:N це safety-net для job, що можуть падати назавжди. Без cap daemon retry'їть нескінченно.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.