Выбор способа развертывания новой версии без поломок
Вы только что закончили новую фичу. Код прошел все проверки, тесты зеленые, артефакт готов. Теперь главный вопрос: как выкатить новую версию на сервер, не разозлив пользователей?
Самый простой ответ — остановить сервер, заменить файлы и запустить снова. Это нормально работает, если вашим приложением пользуется горстка людей, которые знают о предстоящем простое. Но для всего, что обслуживает реальных пользователей, такой подход ломается сразу. Люди видят страницы с ошибками. Запросы падают. Доверие улетучивается.
Основная проблема в том, что нужно доставить новый код в продакшн, пока старый код еще обслуживает трафик. Нельзя просто заменить всё сразу. Нужна стратегия, которая позволит перейти от одной версии к другой без прерывания сервиса.
Есть три распространенные стратегии: rolling update, blue/green deployment и canary deployment. Каждая решает одну и ту же проблему по-своему, и каждая подходит для разных ситуаций.
Rolling Update: замена по одному серверу
Rolling update — самая популярная стратегия. Идея проста: вместо замены всех серверов сразу, вы заменяете их по одному или небольшими группами.
Представьте, у вас десять серверов с приложением. При rolling update вы отключаете два сервера, устанавливаете на них новую версию и возвращаете их в строй. Как только эти два работают на новой версии, вы переходите к следующим двум. Повторяете, пока все десять серверов не будут на новой версии.
Большое преимущество — не нужны дополнительные серверы. Вы используете ту же инфраструктуру. Затраты минимальны, потому что не нужно выделять дублирующие окружения.
Вот как выглядит rolling update в манифесте Deployment для Kubernetes:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 10
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
spec:
containers:
- name: app
image: my-app:2.0.0
Эта конфигурация гарантирует, что за раз создается только один новый Pod (maxSurge: 1), и ни один старый Pod не удаляется, пока новый не будет готов (maxUnavailable: 0). Обновление идет pod за pod'ом, сервис остается доступным на всем протяжении.
Но есть нюанс. Во время обновления одновременно работают две версии вашего приложения. Одни пользователи попадают на старую версию, другие — на новую. Если контракт API изменился между версиями, запросы могут упасть. Пользователь может отправить запрос, который обработает старый сервер, но формат ответа уже изменился. Или новый сервер ожидает поле, которое старый клиент не отправляет.
Rolling update хорошо работает, когда изменения обратно совместимы. Если вы добавляете поле, а не удаляете. Если расширяете API, а не меняете его сигнатуру. Если изменения схемы базы данных аддитивны, а не деструктивны. Для небольших безопасных изменений rolling update эффективен и прост.
Blue/Green Deployment: два полных окружения
Blue/green deployment использует другой подход. Вы поддерживаете два идентичных окружения. Назовем их blue и green. В любой момент времени только одно из них обслуживает живой трафик. Другое простаивает или работает на предыдущей версии.
Вот как это работает. Ваши пользователи сейчас обращаются к окружению blue. Вы развертываете новую версию в окружении green. Как только green полностью готов и вы проверили, что он работает, вы переключаете трафик. Все пользователи теперь попадают на green. Если что-то пошло не так, вы переключаетесь обратно на blue. Откат мгновенный.
Эта стратегия безопаснее, потому что версии никогда не смешиваются. Пользователи переходят с одной полной версии на другую. Нет периода, когда половина серверов работает на старом коде, а половина — на новом. Переход чистый.
Оборотная сторона — стоимость. Вам нужно вдвое больше ресурсов. Два полных окружения, каждое с той же емкостью, работающие одновременно. Для небольших приложений это может быть приемлемо. Для крупных — затраты могут быть значительными.
Blue/green идеален для критических приложений, где недоступность недопустима, а откат должен быть быстрым. Если вы развертываете крупное изменение, миграцию базы данных или что-то, что затрагивает многие части системы, blue/green дает вам страховочную сетку.
Canary Deployment: тест на небольшой группе
Canary deployment похож на rolling update, но более осторожен. Вместо замены серверов группами, вы начинаете с очень маленького процента. Возможно, 5% ваших серверов получают новую версию. Остальные остаются на старой.
Вы наблюдаете за этой маленькой группой какое-то время. Если уровень ошибок остается нормальным, время отклика в порядке, и никто не сообщает о проблемах, вы увеличиваете процент. Может быть, до 20%. Потом до 50%. Потом до 100%.
Идея в том, чтобы ограничить радиус поражения. Если в новой версии есть баг, его испытает лишь небольшая часть пользователей. Вы ловите проблему до того, как она превратится в полноценный сбой.
Canary deployment требует хорошего мониторинга. Нужно знать, как выглядит норма. Нужны дашборды, показывающие уровень ошибок, задержки и пропускную способность в реальном времени. Без такой видимости вы летите вслепую. Вы не узнаете, здорова ли канарейка или нет.
Эта стратегия хорошо подходит, когда вы хотите проверить изменение в продакшне, прежде чем внедрять его полностью. Она особенно полезна для изменений производительности, новых алгоритмов или всего, где поведение под реальным трафиком неопределенно.
Выбор правильной стратегии
Не существует единственной лучшей стратегии. Каждая подходит для разных ситуаций.
Следующая блок-схема поможет решить, какая стратегия подходит для вашей ситуации.
Rolling update — выбор по умолчанию для большинства команд. Он эффективен по ресурсам и хорошо подходит для рутинных изменений. Используйте его, когда ваши изменения обратно совместимы и вам не нужен мгновенный откат.
Blue/green — самый безопасный выбор. Используйте его для критических развертываний, крупных изменений версий или когда нужно откатиться немедленно. Будьте готовы платить за дополнительную инфраструктуру.
Canary — самый осторожный. Используйте его, когда хотите наблюдать за влиянием изменения перед полным внедрением. Он требует хорошего мониторинга и процесса принятия решения о том, когда увеличивать процент.
Многие команды начинают с rolling update и переходят на blue/green или canary по мере того, как их приложение становится более критичным, а база пользователей растет. Стратегия, которую вы выбираете сегодня, не обязательно должна быть той, что вы будете использовать всегда.
Практический чек-лист перед выбором
- Изменение обратно совместимо? Если да, rolling update подходит.
- Нужен мгновенный откат? Если да, blue/green безопаснее.
- Есть мониторинг в реальном времени? Если нет, canary рискован.
- Можете позволить себе двойную инфраструктуру? Если нет, избегайте blue/green.
- Хотите протестировать под реальным трафиком? Если да, canary дает такую возможность.
Что важнее всего
Стратегия — не самая сложная часть. Сложная часть — понимание поведения вашего приложения во время перехода. Выдерживает ли оно одновременную работу двух версий? Терпит ли кратковременный период смешанных контрактов API? Есть ли у вас observability для обнаружения проблем до того, как о них сообщат пользователи?
Выберите стратегию, которая соответствует вашему уровню риска и бюджету на инфраструктуру. Затем протестируйте ее. Не только в стейджинге, но и в продакшне с реальными паттернами трафика. Первый раз, когда вы делаете blue/green switch или canary rollout, делайте это во время низкого трафика. Смотрите на метрики. Узнайте, как выглядит норма.
Развертывание — это не про перемещение битов из одного места в другое. Это про то, чтобы ваши пользователи были довольны, пока вы улучшаете продукт. Правильная стратегия делает это возможным. Неправильная — делает это болезненным.