Как мы внедрили zero-downtime деплой с Nginx и Docker: кейс DevOps-команды

Всё началось с одного сообщения: «А почему сайт лежал ночью почти минуту?». На проде выкатили микрофикс — фронт сдох, Nginx поймал 502, мониторинг заорал. Да, всего минута. Но у нас финтех, SLA, и CTO уже закатывал рукава.

Так я занялся zero-downtime деплоем.

Как мы внедрили zero-downtime деплой с Nginx и Docker: кейс DevOps-команды

Контекст: что мы вообще деплоим

Немного про приложение. Это микросервис, отвечающий за расчёт кредитных скорингов в нашей финтех-платформе. Он получает заявку, парсит данные клиента (доходы, возраст, кредитную историю), запускает ML-модель и возвращает скоринговый балл в формате JSON.

Всё на Node.js (NestJS + TypeORM), база — PostgreSQL. Приложение довольно чувствительное к отклонениям: если не ответит за 2 секунды — фронт отваливает, клиент видит ошибку.

Именно на нём были ночные 502. Даже 10 секунд простоя — это десятки потерянных заявок и потенциальный минус к доверию.

Зачем вообще нужен zero-downtime

Если ты когда-либо деплоил вживую, знаешь, как это выглядит:

  • Дёргаем docker-compose pull && up -d;
  • Старый контейнер гаснет, пока новый скачивается;
  • За это время — пустота, ошибки, 502.

И это не баг — это обычное поведение. Просто никто не позаботился сделать деплой бесшовным.

Для нас важны были:

  • минимальный даунтайм (идеально — ноль);
  • rollback в случае фейла;
  • деплой без дергания балансировщика вручную.

Что мы решили использовать

Мы работаем в Docker. У нас есть docker-compose и CI (GitHub Actions). Решили не прыгать в Kubernetes — всё-таки это не кластер.

Итого:

  • Docker + docker-compose;
  • Nginx как реверс-прокси;
  • два backend-сервиса (актуальный и обновляемый);
  • GitHub Actions — CI/CD pipeline.

Паттерн — классический Blue/Green deployment:

Архитектура

Упрощённо:

Как мы внедрили zero-downtime деплой с Nginx и Docker: кейс DevOps-команды

Конфиг Nginx (упрощён):

Как мы внедрили zero-downtime деплой с Nginx и Docker: кейс DevOps-команды

Чтобы переключиться: меняем приоритет в upstream, пересобираем Nginx, он переключает трафик.

CI/CD pipeline

GitHub Actions делает всё:

  1. Билдит docker-образ;
  2. Тегирует как green;
  3. Деплоит app_green;
  4. Прогоняет health-check;
  5. Меняет конфиг Nginx (переключает на green);
  6. Рестартит Nginx;
  7. Убивает app_blue.

Пример deploy.yml:

Как мы внедрили zero-downtime деплой с Nginx и Docker: кейс DevOps-команды

Подводные камни

1. Медленный healthcheck

curl /healthz может сработать, а сервис ещё не прогрет. Решили:

  • добавить sleep 10;
  • проверять ответ на бизнес-метрику (не просто 200, а status: ok).

2. Nginx не сразу переключает

После docker restart Nginx может держать кеш. Помогло:

  • proxy_cache_bypass в конфиг;
  • resolver прописать явно, если имена контейнеров меняются.

3. Сбои при одновременном деплое

CI мог запускаться параллельно. Добавили concurrency в GitHub Actions:

Как мы внедрили zero-downtime деплой с Nginx и Docker: кейс DevOps-команды

Что получилось

Теперь при каждом пуше в main:

  • поднимается green;
  • проверяется /healthz;
  • Nginx переключается;
  • blue удаляется.

Деплой занимает 30–45 секунд. Ни одного 502 за 2 недели.

Советы

  • Делай health-check настоящим: не просто 200, а с логикой.
  • Всегда держи старый backend до конца.
  • Автоматизируй rollback (в проде всё ломается).
  • Не забудь про concurrency в CI.

Что дальше

Следующий шаг — Canary: будем прокидывать 10% трафика на новую версию и следить за ошибками.

А пока — zero-downtime работает. Даже ночью. Даже на проде.

Хочешь попробовать деплой или поработать с Nginx в боевых условиях — заходи на GigaDevOps Platform. Там можно развернуть контейнер, отловить баг и сделать rollout — прямо в браузере.

Также присоединяйтесь к сообществу DevOps-инженеров в Telegram, чтобы погружаться в профессию в удобном формате.

Как мы внедрили zero-downtime деплой с Nginx и Docker: кейс DevOps-команды
3
2
11 комментариев