Що таке 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 — дефолт
docker run myapp
# Crash → exited. Лишається exited.
# Host reboot → container не повертається.Нормально для одноразових команд (docker run --rm для CI-job). Неправильно для будь-якого сервісу, що має крутитися.
on-failure[:N] — рестарт на crash до N разів
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 — рестарт незважаючи ні на що
docker run --restart=always mysvc
# Crash, чистий exit, host reboot → daemon його повертає кожного разу.
# Навіть після `docker stop` daemon його рестартує.Назва буквальна: ЗАВЖДИ. Включно після ручного stop, щоб реально зупинити, маєш зробити docker rm. Дивує; зазвичай хочеш unless-stopped.
unless-stopped — прод-дефолт
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-синтаксис
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.
Типові помилки
Забути поставити політику на довгоживучий сервіс
# НЕПРАВИЛЬНО: дефолт "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 не тримається
$ docker run -d --name api --restart=always myapp
$ docker stop api
$ docker ps # api повернувсяalways буквально означає завжди. Бери unless-stopped, якщо хочеш, щоб ручний stop поважався.
Crash-loop без фільтра exit-коду
# 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-статусу.
# 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
$ 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
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, щоб запобігти нескінченних циклів
$ 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 # фінальний стан, без retryon-failure:N це safety-net для job, що можуть падати назавжди. Без cap daemon retry'їть нескінченно.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.