Skip to main content

Як виконати rolling update у Docker Swarm?

Rolling-update у Docker Swarm замінює running-task по batch за раз, чекаючи health між batch. Вбудований механізм Swarm реально хороший у цьому, з auto-rollback на failure як first-class фічею.

Теорія

TL;DR

  • docker service update з --image тригер. Swarm замінює task за політикою update_config.
  • Ключові параметри: parallelism (скільки за раз), delay (між batch), monitor (як довго стежити за кожним), failure-action (continue/pause/rollback).
  • Порядок: stop-first (дефолт, короткий gap per task) або start-first (zero-downtime, якщо застосунок підтримує паралельні старий/новий).
  • Rollback одна команда (docker service rollback) або автоматично на failure.
  • Healthcheck на сервісі це те, що робить «failure» виявленим. Без нього Swarm вважає started=healthy.

Update-flow

Сервіси: 6 реплік api:1.0 --update-parallelism=2 --update-delay=30s t=0: [v1.0 v1.0 v1.0 v1.0 v1.0 v1.0] випуск update t=0: [STOP STOP v1.0 v1.0 v1.0 v1.0] stop 2 (або start-first: додатковий v1.1 spawn) t=5: [v1.1 v1.1 v1.0 v1.0 v1.0 v1.0] 2 нових task healthy t=35: [v1.1 v1.1 STOP STOP v1.0 v1.0] delay+30s, наступний batch t=40: [v1.1 v1.1 v1.1 v1.1 v1.0 v1.0] t=70: [v1.1 v1.1 v1.1 v1.1 v1.1 v1.1] готово

Під час update трафік продовжує йти на ті репліки, що healthy.

Імперативна форма (CLI)

bash
docker service update \ --image myorg/api:1.1 \ --update-parallelism 1 \ --update-delay 30s \ --update-monitor 30s \ --update-failure-action rollback \ --update-max-failure-ratio 0.2 \ --update-order start-first \ api

Що робить кожен флаг:

  • --update-parallelism N — замінити N task за раз (дефолт 1).
  • --update-delay 30s — чекати між batch.
  • --update-monitor 30s — стежити за кожним batch на failure стільки.
  • --update-failure-action <continue|pause|rollback> — що робити на failure.
  • --update-max-failure-ratio 0.2 — щонайбільше 20% task можуть впасти перед тригером action.
  • --update-order <stop-first|start-first> — заміна через stop спочатку або start нового спочатку.

Декларативна форма (stack-файл)

yaml
version: '3.9' services: api: image: myorg/api:1.0 deploy: replicas: 6 update_config: parallelism: 1 delay: 30s order: start-first failure_action: rollback monitor: 30s max_failure_ratio: 0.2 rollback_config: parallelism: 2 delay: 5s failure_action: pause
bash
docker stack deploy -c stack.yaml mystack # Редагуй image на 1.1, redeploy → тригерить rolling update з config вище.

Stack-файл це канонічне місце, version-controlled, reviewable.

Health-driven gating

Swarm вирішує «чи цей batch healthy?» через:

  1. Container стартонув успішно (без exit під час monitor-періоду).
  2. Якщо healthcheck визначено, container healthy.
  3. Не більше ніж max_failure_ratio failures у batch.

Без healthcheck Swarm знає лише «процес стартонув». Застосунок, що стартує, але одразу misbehaving, ще рахується як «healthy» для Swarm. Healthcheck критичні для безпечного rolling-update.

Rollback

bash
# Ручний rollback у будь-який час docker service rollback api # Повертає до попереднього image-tag

Або через failure_action: rollback Swarm rollback'ить автоматично, коли failure-ratio перевищено. У комбінації з monitor отримуєш «якщо 1 з 5 у новому batch unhealthy після 30 секунд, roll back усього сервісу» семантику.

start-first vs stop-first

yaml
order: stop-first # дефолт — невеликий gap per task order: start-first # підняти новий поряд зі старим, тоді drain старий

start-first шлях до справжнього zero-downtime, але потребує застосунку, що толерує короткий overlap (дві версії крутяться разом). Для stateless web/API нормально. Для workers зі строгою singleton-семантикою може потребувати code-зміни.

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

Update без healthcheck

yaml
services: api: image: myorg/api # БЕЗ healthcheck → Swarm не може виявити погані версії

Без healthcheck зламаний новий image rolls out на усі репліки до того, як failure стане видимим. Додай healthcheck:, щоб Swarm gate'нути прогрес на реальний app-readiness.

Поставити parallelism надто високим

yaml
update_config: parallelism: 5 # усі 6 реплік одразу

Під час короткого replacement-вікна у тебе дуже мало healthy task. Сплеск load = накопичення. Нижчий parallelism = безпечніше.

Забути rollback_config

Rollback використовує свій окремий блок конфігурації. Якщо ставиш лише update_config, rollback бере дефолти (часто повільніший, ніж хочеш). Визнач rollback_config явно.

Image-tag все ще latest для --rollback

bash
docker service rollback api No previous image to roll back to: same tag

Якщо обидва нові і старі були tagged latest, Swarm не може їх розрізнити. Завжди tag версією (або commit SHA), щоб rollback працював.

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

  • Прод-деплої на Swarm-кластерах — кожен новий image тригерить service update; Swarm обробляє parallelism + monitoring.
  • Staged canary — спочатку deploy 1 з 10 з parallelism=1 і довгим monitor; якщо стабілізується, підніми parallelism для решти.
  • Hotfix-rolloutservice update --image hotfix:1.0 з високим parallelism (швидше) і агресивним monitoring (ловити failures швидко).
  • DB-міграції — ніколи через rolling-update напряму. Спочатку запусти one-off migrator-сервіс, тоді update app-репліки.

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

Q: Що відбувається з in-flight запитами під час task-replacement?


A: Task, scheduled for replacement, отримують SIGTERM і налаштований grace-період (stop_grace_period). Застосунки мають drain in-flight запити перед виходом. У комбінації з routing mesh трафік steer'иться від stopping-task перед SIGTERM.

Q: Чи можу update'нути кілька сервісів разом?


A: Edit stack-файл з новими image для кожного, тоді docker stack deploy -c stack.yaml mystack. Кожен сервіс update'ься незалежно за своїм config; cross-service ordering не отримаєш.

Q: Як Swarm rolling-update відрізняється від K8s rolling-update?


A: Концептуально ідентично. K8s deployment: maxSurge, maxUnavailable ≈ Swarm parallelism і order. K8s readiness-probes ≈ Swarm healthcheck. Та сама модель, інший синтаксис.

Q: Яка різниця між update_config і rollback_config?


A: update_config контролює forward-update (1.0 → 1.1). rollback_config контролює reverse-update (1.1 → 1.0). Часто хочеш повільніший, безпечніший rollback, ніж forward-update.

Q: (Senior) Як спроектувати rolling-update параметри для сервісу, що бере 90 секунд на прогрів?


A: start_period у healthcheck = 120с (дай warmup час перед рахунком failures). update-monitor = 180с (чекай досить довго, щоб побачити реальні failures emerge). parallelism = 1 (повільний rollout, 90с warmup × репліки = загальний update-час). failure_action = rollback. Патерн: monitor-period > start-period > observation, потрібний для стабільності. Швидші rollout ховають warmup-related failures; цей консервативний config їх ловить.

Приклади

Production-якості rollout

yaml
version: '3.9' services: api: image: myorg/api:1.0 deploy: replicas: 6 update_config: parallelism: 2 delay: 30s order: start-first failure_action: rollback monitor: 60s max_failure_ratio: 0.2 rollback_config: parallelism: 2 delay: 10s restart_policy: condition: any healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3000/health"] interval: 10s timeout: 3s retries: 3 start_period: 30s

Deploy з новим image:

bash
sed -i 's/myorg\/api:1.0/myorg\/api:1.1/' stack.yaml docker stack deploy -c stack.yaml mystack docker service ps mystack_api # Дивись, як task замінюються 2 за раз, з 30с gap, monitored 60с кожен.

Manual rollout з імперативними флагами

bash
docker service update \ --image myorg/api:1.1 \ --update-parallelism 1 \ --update-delay 60s \ --update-monitor 120s \ --update-failure-action rollback \ --update-max-failure-ratio 0.0 \ --update-order start-first \ api # Строго: будь-який failure тригерить rollback.

Корисно для one-off tightly-controlled rollout.

Watching rollout

bash
$ watch -n 2 'docker service ps mystack_api --format "table {{.Name}}\t{{.Image}}\t{{.CurrentState}}"' # Live-view, які task якої версії, у якому стані.

Чудово для верифікації, що rollout прогресує як очікувано.

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

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

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

Дочитали статтю?