Ответ
Чтобы Node.js-приложение оставалось доступным пользователям во время обновления, я использую стратегии, которые позволяют запустить новую версию до отключения старой.
Основные стратегии и их реализация в Node.js-окружении:
-
Blue-Green Deployment:
- Суть: Разворачиваются два идентичных окружения — «Blue» (текущая версия) и «Green» (новая версия). Весь трафик идёт на Blue.
- Деплой: Новая версия разворачивается в Green. После успешного запуска и health-чеков трафик с балансировщика нагрузки (Nginx, HAProxy, облачный LB) мгновенно переключается на Green.
- Откат: В случае проблем — переключение обратно на Blue занимает секунды.
-
Canary Releases:
- Суть: Новая версия разворачивается для небольшого процента пользователей (например, 5%), затем доля постепенно увеличивается.
- Реализация: Используются возможности балансировщиков (например, веса в Nginx
weight) или feature flags на уровне приложения.# Пример конфигурации Nginx для canary upstream backend { server old_app:3000 weight=95; server new_app:3000 weight=5; }
-
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-колонки).