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

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

Коментарі

Ще немає коментарів