Как минимизировать время простоя (downtime) приложения Node.js во время деплоя?

«Как минимизировать время простоя (downtime) приложения Node.js во время деплоя?» — вопрос из категории DevOps, который задают на 26% собеседований Node.js Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Чтобы Node.js-приложение оставалось доступным пользователям во время обновления, я использую стратегии, которые позволяют запустить новую версию до отключения старой.

Основные стратегии и их реализация в Node.js-окружении:

  1. Blue-Green Deployment:

    • Суть: Разворачиваются два идентичных окружения — «Blue» (текущая версия) и «Green» (новая версия). Весь трафик идёт на Blue.
    • Деплой: Новая версия разворачивается в Green. После успешного запуска и health-чеков трафик с балансировщика нагрузки (Nginx, HAProxy, облачный LB) мгновенно переключается на Green.
    • Откат: В случае проблем — переключение обратно на Blue занимает секунды.
  2. Canary Releases:

    • Суть: Новая версия разворачивается для небольшого процента пользователей (например, 5%), затем доля постепенно увеличивается.
    • Реализация: Используются возможности балансировщиков (например, веса в Nginx weight) или feature flags на уровне приложения.
      # Пример конфигурации Nginx для canary
      upstream backend {
      server old_app:3000 weight=95;
      server new_app:3000 weight=5;
      }
  3. Rolling Update (в оркестраторах, например, Kubernetes):

    • Суть: Новые поды (контейнеры) с обновлённым приложением создаются по одному/несколько, а старые удаляются после их готовности.
    • Настройка: В манифесте Kubernetes задаются strategy.type: RollingUpdate и параметры maxUnavailable (сколько подов может быть недоступно) и maxSurge (сколько дополнительных подов можно создать).

Технические практики для Node.js приложения:

  • Graceful Shutdown: Приложение должно корректно завершать работу, дожидаясь завершения текущих запросов.
    process.on('SIGTERM', () => {
      server.close(() => {
        console.log('Server closed');
        db.disconnect(() => process.exit(0));
      });
    });
  • Health Checks: Добавление эндпоинтов /health и /ready для проверки балансировщиком состояния приложения и его зависимостей (БД, кэш).
  • Миграции БД: Выполняются до переключения трафика на новую версию и должны быть обратно совместимы со старой версией кода (например, добавление nullable-колонки).