Blue-green релизы — это схема обновления, при которой у вас всегда есть две версии сервиса: старая (blue) и новая (green). Трафик в один момент обслуживает только одна из них, а переключение делается быстро и контролируемо. Поэтому обновлять сервисы на VPS без простоя становится проще: вы не “останавливаете и запускаете”, а подготавливаете green и затем меняете маршрут.

На практике схема выглядит так: поднимаете green в той же инфраструктуре (обычно на других портах или с отдельными рабочими каталогами), прогоняете проверки, убеждаетесь, что сервис отвечает корректно, и только после этого переводите входящий трафик. Если что-то пошло не так, откат сводится к обратному переключению на blue.

Ключевые элементы blue-green:

  • две независимые среды исполнения (blue и green);
  • единая точка входа (reverse proxy или балансировщик);
  • проверка готовности green (health checks, smoke-тесты);
  • атомарное переключение маршрута;
  • быстрый rollback и очистка после стабилизации.

Ниже разберём, как собрать эту схему на VPS, где обычно нет готовых managed-балансировщиков уровня облака, но есть достаточно гибкости для аккуратного переключения.

Архитектура на VPS: две версии рядом и единая точка входа

Чтобы обновлять сервисы без простоя, важно отделить “деплой” от “маршрутизации”. Деплой должен создавать новую версию и держать её готовой, а маршрутизация должна уметь быстро переключать, куда идти запросам.

Обычно на VPS используют один из вариантов входа:

  • Nginx как reverse proxy с двумя upstream и переключением на стороне конфигурации;
  • Traefik или HAProxy с отдельными backend-цепочками для blue и green;
  • балансировщик на уровне контейнерной платформы (если вы используете Docker Compose/Swarm), но переключение всё равно должно быть управляемым.

Главная идея: green и blue должны быть одинаково доступны из точки входа, но различаться по “выводу наружу”. На уровне Nginx это проще всего сделать через два upstream-имени и выбрать активный.

Минимальная схема:

  • сервис-версия blue слушает порт A (или имеет отдельный container);
  • сервис-версия green слушает порт B;
  • Nginx слушает 80/443 и проксирует на выбранный upstream;
  • переключение меняет upstream-таргет без долгой паузы.

Чтобы переключение было действительно быстрым, избегайте сценариев вида “перезагрузить Nginx целиком и ждать пока он поднимётся”. Вместо этого применяйте перезапуск без потери соединений (в Nginx это решается корректными директивами и характером обновления конфигурации) или используйте механизм динамических обновлений, если он уместен в вашей связке.

Подготовка инфраструктуры на VPS под blue-green

Перед первым релизом стоит один раз привести систему к состоянию, где переключение трафика не требует “разборки всего на части”. Обычно проблемы всплывают там, где сервисы имеют зависимость от состояния окружения, которое обновляется вместе с кодом.

Что нужно сделать переключаемым

Под переключение должны попадать только те части, которые относятся к приложению:

  • исполняемый код (артефакты, контейнеры, systemd service с разными именами);
  • конфигурация приложения для конкретной версии;
  • порт/endpoint внутри VPS, куда проксирует вход.

А вот “сквозные” компоненты лучше держать стабильными:

  • домен/сертификаты TLS;
  • внешний порт 80/443 на VPS;
  • reverse proxy как единая точка входа;
  • общие секреты, которые можно безопасно подать в обе версии.

Если вы привязываете домен к конкретному backend напрямую через отдельные DNS-записи на каждый релиз, задержки из-за TTL могут нивелировать эффект “без простоя”. Поэтому на VPS чаще выбирают переключение на уровне proxy.

Требования к приложению

Blue-green работает лучше всего, когда новое и старое версии сервиса не ломают друг друга на этапе перехода. Это означает:

  • совместимость контракта API для клиентов (старый клиент не должен внезапно получить 500 из-за обновлённого формата);
  • идемпотентность обработчиков там, где возможны повторы запросов (например, при ретраях клиента или балансировщика);
  • устойчивость к различиям времени старта (green может быть готов позже, и proxy должен уметь не пускать трафик до готовности).

Для конфигурации удобнее использовать принцип “один и тот же шаблон, разные значения”. Например, переменные окружения для blue и green задаются одинаково по схеме, но с разным набором портов, путей к логам и идентификаторов экземпляров.

Стейт: сессии, файлы, очереди

На VPS чаще всего “внезапные простои” связаны не с кодом, а со стейтом:

  • HTTP-сессии, хранящиеся локально на диске приложения;
  • файлы (загрузка документов) на локальном диске контейнера;
  • кэш и session store, привязанный к конкретному инстансу.

Решения обычно такие:

  • сессии держать в общем хранилище (Redis) или использовать stateless-авторизацию (токены);
  • файловые данные выносить в отдельное хранилище (NFS, S3-совместимое, объектное хранилище) или хотя бы разделять по путям так, чтобы обе версии читали одни и те же файлы;
  • очереди и фоновые воркеры управлять через очереди (RabbitMQ/Redis streams) так, чтобы обе версии могли работать безопасно и не делали дублей критичных задач.

Если ваш сервис сильно зависит от локального диска и локальных “памятных” данных, blue-green всё равно возможен, но придётся заранее продумать перенос или синхронизацию.

Миграции базы без простоя: expand/contract и совместимость версий

Обновление без простоя часто упирается в базу данных. Если вы запускаете миграции в момент, когда часть трафика уже уходит на green, то старая версия не должна “умирать” из-за изменения схемы, а новая версия должна понимать как минимум текущее состояние данных.

Практичный подход для blue-green — стратегия expand/contract:

  • expand: расширяете схему так, чтобы старый код продолжал работать;
  • contract: после переключения и стабилизации убираете старое, когда и старые клиенты уже не нужны.

Expand: добавить, не ломая старое

Расширяющий шаг обычно выглядит как:

  • добавление новых колонок (nullable поначалу);
  • создание новых таблиц/индексов, которые не требуют немедленного изменения старого кода;
  • добавление новых объектов, которые новая версия сможет использовать, а старая продолжит игнорировать.

Если миграция требует изменения существующих колонок на несовместимый тип — это почти всегда красный флаг для blue-green. Такие преобразования делают через этапы: сначала добавляют новый формат, потом переводят записи, и только потом удаляют старое.

Contract: убирать после переключения

Сужающий шаг выполняется позже:

  • после того как green обслуживает трафик, а вы убедились, что данные заполняются корректно;
  • после того как вы подтвердили, что откат невозможен или вы готовы откатываться без использования “убранной” функциональности.

Contract может включать:

  • удаление старых колонок/таблиц;
  • отключение старых путей чтения;
  • чистку индексов, которые больше не нужны.

Важно, что удаление старого — самая опасная операция. Если вы сделаете contract слишком рано, rollback станет сложным или даже невозможным.

Типичные ошибки при миграциях

Самые частые проблемы в blue-green:

  • “сразу поменяли колонку и переписали тип” — старый код падает;
  • “удалили старое чтение” до того, как green полностью прижился;
  • “миграцию и переключение сделали в одном шаге без проверок” — при ошибке вы не можете откатиться быстро;
  • отсутствие совместимости на уровне данных при изменении логики (например, новая версия ожидает новые значения, но старая версия их ещё не пишет).

Мини-правило: если на этапе переключения обе версии могут существовать параллельно, то схема и данные должны быть совместимы минимум между blue и green на время перехода.

Разворачиваем окружение Green рядом с Blue

Когда схема готова, приступаем к деплою green. Здесь важна дисциплина: green должен быть поднят так, чтобы его можно было быстро проверить и, в случае проблем, не влиять на пользователей.

Изоляция версий

На VPS обычно проще всего изолировать версии так:

  • разные порты (например, 8080 для blue и 8081 для green);
  • разные systemd unit имена (service-blue и service-green);
  • разные docker compose проекты или container names, но единый reverse proxy.

Цель — чтобы обе версии могли жить одновременно. Если вы используете контейнеры, не подменяйте один и тот же контейнер на лету. Создайте новый контейнер green и держите blue как есть.

Health checks и readiness: без них переключение рискованно

Nginx/Traefik сами по себе не всегда знают, готов ли backend принимать запросы. Поэтому у вас должны быть health checks:

  • endpoint для readiness (например, /healthz или /readyz);
  • проверка не только “процесс жив”, но и “зависимости доступны” (БД, очередь, внешние сервисы — по контексту).

Для blue-green полезна раздельность:

  • liveness: процесс работает;
  • readiness: запросы можно принимать.

Если readiness учитывает БД и миграции ещё не завершены или зависимость недоступна, green не должен получать трафик. Это снижает вероятность “простоит из-за неготовности”, которую обычно сложно отследить.

Smoke-тесты перед переключением

До переключения трафика прогоните минимум:

  • базовый запрос к endpoint, который покрывает основные маршруты;
  • проверка авторизации (если есть);
  • проверка одного-двух критичных операций (например, чтение сущности и создание без побочных эффектов или с управляемыми тестовыми данными).

Smoke-тесты должны быть быстрыми и автоматизируемыми. Если тесты занимают слишком много времени, они начинают влиять на весь релизный цикл и превращаются в “узкое место”.

Переключение трафика: сделать “одним действием” и без потерь

Самая важная часть blue-green — не сам деплой, а управляемое переключение маршрута. В идеале оно занимает секунды и не ломает текущие соединения.

Вариант 1: Nginx с двумя upstream и переключателем

Примерно так выглядит конфигурация с двумя upstream:

«`nginx upstream app_blue { server 127.0.0.1:8080; keepalive 32; }

upstream app_green { server 127.0.0.1:8081; keepalive 32; }

server { listen 80; server_name example.com;

location / { proxyhttpversion 1.1; proxysetheader Host $host; proxysetheader X-Forwarded-For $proxyaddxforwardedfor; proxysetheader X-Forwarded-Proto $scheme;

proxyconnecttimeout 5s; proxyreadtimeout 30s;

set $backend app_blue; # по умолчанию proxy_pass http://$backend; } } «`

Если вы хотите переключать backend без “долгой паузы”, обычно делают так:

  • храните в конфиге переменную/мапу, управляемую отдельным include-файлом;
  • обновляете include и делаете reload Nginx с правильной стратегией.

Например, через карту: «`nginx map $active_backend $backend { default app_blue; green app_green; } «`

А $active_backend вы задаёте через переменную, которую меняете перед релизом (или через генерацию конфигурации). На практике часто делают генерацию всего server-блока из шаблона в рамках CI/CD.

Чтобы соединения не “рвались”, учитывайте нюансы:

  • keep-alive: proxy продолжит использовать соединения к backend, но после переключения новые запросы пойдут в green;
  • таймауты: выставляйте реалистичные proxyreadtimeout под ваш сервис;
  • поведение текущих запросов: если клиент уже держит long-poll/stream, то “мгновенное выключение” backend может проявиться как обрыв. В таких сценариях уместны graceful shutdown и слив запросов.

Вариант 2: Traefik или HAProxy с правилами маршрутизации

В Traefik часто удобно переключать сервисы через маршруты/labels и менять активный набор в конфигурации. HAProxy позволяет включать backend и выключать его с контролем drain.

Смысл тот же: активный backend должен меняться быстро, а отключаемый backend — принимать новые запросы некоторое время, чтобы текущие успели завершиться.

Вариант 3: DNS-переключение — когда это оправдано

DNS тоже может быть способом сделать blue-green, но на VPS он часто усложняет жизнь:

  • TTL может привести к тому, что часть клиентов продолжит ходить на старую версию дольше, чем вы планировали;
  • кэш у резолверов и браузеров добавляет вариативность.

DNS оправдан, когда:

  • вы полностью контролируете TTL и клиенты нормально переживают неоднородность;
  • у вас нет стабильной инфраструктуры reverse proxy, которую можно быстро переключать.

Для большинства задач на VPS надежнее переключать маршрут на уровне proxy.

Управление keep-alive и сливом запросов

Даже при правильном маршруте есть “крайние случаи”:

  • клиент удерживает соединение дольше, чем рассчитано;
  • green поднялся, но принимает трафик медленно из-за прогрева кэшей;
  • при откате на blue старые соединения могут вести себя непредсказуемо.

Практика:

  • используйте graceful shutdown при остановке версии, чтобы backend корректно завершал запросы;
  • если у вас long-running запросы, убедитесь, что proxy не рубит их слишком агрессивно;
  • в health checks включайте “готовность”, чтобы не гонять трафик по полуподнятой green.

Резервный план: откат и контроль после переключения

Blue-green хорош тем, что rollback — это обычно обратное переключение на blue. Но только если вы заранее подготовили условия.

Какие метрики смотреть сразу после переключения

Сразу после смены маршрута полезно следить:

  • ошибки 4xx/5xx по основным endpoint;
  • рост задержек (p95/p99 или хотя бы среднее + хвосты);
  • ошибки зависимостей (БД, очередь, внешние API);
  • загрузка ресурсов на VPS (CPU/RAM/диски) — иногда зелёная версия просто тяжелее;
  • поведенческие метрики: время обработки ключевых операций, количество ретраев, размер очередей.

Сигналы должны быть привязаны к релизу: сравнивайте с baseline. Если вы не ведёте метрики, хотя бы добавьте временный лог-уровень и корреляцию релизного идентификатора.

Как подготовить быстрый rollback

Rollback должен занимать минуты, а не время на разбор “что сломалось”. Для этого:

  • переключатель backend должен быть тем же инструментом, что и при roll-forward;
  • blue не трогается на этапе деплоя green (не останавливайте его раньше времени);
  • конфигурация green и blue должна быть отделена, чтобы откат не требовал возвращать секреты, порты, файлы “вручную”.

Также стоит иметь сценарий “быстро выключить green” на уровне proxy. Если green перестаёт отвечать корректно, но process жив, proxy всё равно должен перестать проксировать запросы на него.

Очистка старой среды и политика хранения

После того как вы убедились, что green работает стабильно, можно:

  • оставить blue ещё некоторое время на случай “второй волны” проблем;
  • удалить ресурсы blue (старые контейнеры, директории, временные файлы) по вашей политике.

Обычно важнее не “всё удалить сразу”, а обеспечить возможность быстрого отката в коротком окне. Но и держать бесконечно две версии не стоит: это усложняет диагностику и увеличивает риск “случайной оплаты за лишнее”.

Автоматизация в CI/CD: pipeline для blue-green

Чтобы blue-green не превращался в релизы “по ручным чеклистам”, его стоит собрать в pipeline. Это особенно важно на VPS, где вы быстро скатываетесь в скрипты “на сервере”.

Стадии пайплайна

Хороший пайплайн обычно выглядит так:

  • сборка артефакта (образ контейнера или пакет);
  • деплой green в отдельную “параллельную” среду;
  • применение конфигурации green (env, secrets, порты);
  • ожидание readiness (health checks);
  • smoke-тесты;
  • переключение трафика на green;
  • пост-проверки и наблюдение;
  • optional: перевод на contract-миграции и очистка старой среды.

Секрет в том, что переключение должно происходить только после формальной готовности green. Если в pipeline нет явного шага readiness и smoke-тестов, вы получаете “почти blue-green” — с риском ошибок на проде.

Согласование миграций и переключения

Миграции делайте предсказуемо:

  • expand-миграции — до переключения или во время деплоя green, но так, чтобы blue продолжал работать;
  • contract-миграции — после успешного периода наблюдения на green.

Если у вас миграции требуют длительных блокировок, то лучше вынести их в отдельные запуски в заранее согласованное время. Blue-green не отменяет стоимость операций над данными, он только позволяет не останавливать приложение.

Минимизируем ручные расхождения

На VPS частая причина проблем — “вчера всё работало, потому что кто-то вручную правил конфиг”. Чтобы избежать этого:

  • храните шаблоны конфигураций в репозитории;
  • генерируйте итоговые конфиги по стандартному шаблону;
  • публикуйте один релизный идентификатор и используйте его в логах обеих версий.

Когда расхождения исчезают, диагностика после переключения становится значительно проще.

Чек-лист перед переключением трафика

Перед тем как сделать переключение на green, убедитесь, что вы закрыли основные источники отказов. Ниже минимальный набор проверок, который можно встроить в pipeline.

Минимальный набор проверок

  • Green запущен и слушает нужный порт/endpoint.
  • Health checks readiness проходят стабильно (а не только “один раз успешно”).
  • Смоу-тесты на критичные endpoint проходят.
  • Зависимости доступны: БД, очередь, внешние сервисы (в том объёме, который вы считаете критичным).
  • Конфигурация green не отличается от ожидаемой схемы (переменные окружения, feature flags, режимы).
  • Expand-миграции выполнены так, чтобы blue не ломался (если они нужны).
  • Переключатель backend готов к работе: вы умеете быстро вернуть трафик на blue.

Что проверить в конфигурации и секретах

  • Сертификаты TLS и SNI не изменяются при релизе (если они завязаны на proxy).
  • Секреты поданы и для blue, и для green (или вы не меняете их в момент переключения).
  • Порты не конфликтуют и firewall пропускает соединения между proxy и backend.
  • Логи зелёной версии доступны для диагностики (и вы не перепутали директории/права).
  • Если используются очереди/воркеры, они не “перетягивают” задания без учёта версионности.

Частые проблемы и как их предотвратить

Blue-green кажется прямым решением, пока на проде не всплывают нюансы. Ниже — самые типичные ошибки и способы снизить риск.

Несовместимость контрактов API

Если новая версия изменила формат ответов или поведение endpoint, клиенты могут получить ошибки даже при корректном переключении. Особенно это заметно, если фронтенд/интеграции не деплоятся синхронно.

Как предотвратить:

  • сохраняйте обратную совместимость на период перехода;
  • версионируйте API при необходимости;
  • используйте feature flags, чтобы включать новую логику постепенно.

Гонка миграций и зависимость от версии данных

Классика: вы переключили на green, а новая версия ожидает данные в формате, который не успел появиться. В результате часть функциональности деградирует или падает.

Как предотвратить:

  • делайте expand так, чтобы старые данные оставались пригодными;
  • запускайте backfill (если нужен) до включения логики, которая его требует;
  • в новой версии делайте чтение совместимым с обоими состояниями данных на время перехода.

Очереди и фоновые обработчики

С фоновой обработкой легко получить дубли: обе версии воркера могут забирать одни и те же задания, если нет механизмов дедупликации/идемпотентности.

Как предотвратить:

  • встраивать идемпотентность на уровне обработчиков;
  • использовать lease/ack механизмы очереди правильно;
  • при необходимости ограничивать активность green для фоновых воркеров отдельным переключателем.

Важно: если вы включаете обработчики сразу после деплоя green, они начнут работать одновременно с blue. Это не всегда плохо, но нужно понимать последствия для бизнес-логики.

Сессии и кэш

Если сессии хранятся в памяти процесса, то переключение может вызвать “разлогин” или частичные сбои. То же касается in-memory кэшей, если они влияют на доступность данных.

Как предотвратить:

  • выносить сессии в общее хранилище;
  • избегать кэшей, которые меняют поведение без повторного заполнения;
  • валидировать поведение авторизации и восстановления сессий до переключения.

Если кэш влияет на безопасность (например, проверка прав), убедитесь, что новая версия не возвращает некорректные результаты при пустом/разогретом кэше.

Заключение: внедрите blue-green как процесс, а не как разовый трюк

Blue-green релизы помогают обновлять сервисы на VPS без простоя, потому что разделяют деплой и переключение трафика. Вы поднимаете green параллельно, проверяете readiness и качество, и только затем переводите клиентов на новую версию. Если что-то пошло не так, rollback — это обратное переключение на blue.

Чтобы внедрение сработало с первого раза, сфокусируйтесь на трёх вещах: готовность green по health checks, совместимость миграций (expand/contract) и управляемость переключения на уровне reverse proxy. После этого blue-green перестаёт быть “идеей” и становится повторяемым процессом в вашей CI/CD.

Соберите минимальный pipeline под вашу текущую схему (деплой двух версий, readiness, переключение, rollback), проведите 1-2 релиза в тестовом контуре и только потом переносите подход на прод. Тогда обновления на VPS станут предсказуемыми, а простои — редким исключением, а не нормой.