Развертывание и релиз: почему ваш новый код еще не дошел до пользователей
Вы только что завершили развертывание. Пайплайн зеленый, артефакт на production-сервере, команда готова считать задачу выполненной. Но когда вы проверяете приложение, пользователи по-прежнему видят старую версию. На их стороне ничего не изменилось.
Этот момент сбивает с толку многие команды. Вы сделали все правильно. Код на месте. Сервер запускает новый бинарник. Так почему же пользователи не получают обновление?
Ответ прост: развертывание и релиз — это два разных понятия. И понимание этой разницы меняет подход к поставке программного обеспечения.
Развертывание означает, что код на сервере
Развертывание (deployment) — это процесс размещения новой версии приложения на сервере. Артефакт покидает реестр, копируется в целевую среду, и сервер начинает его выполнение. Если вы развернули на production, новая версия физически присутствует на production-серверах.
Вот и все. Развертывание — это техническое действие. Оно ничего не говорит о том, могут ли пользователи фактически использовать новую версию.
Представьте это так: вы загрузили новый фильм в проектор в кинотеатре. Пленка заряжена, катушки готовы, проектор включен. Но фильм еще не начался. Зрители все еще смотрят предыдущую ленту.
Следующая диаграмма показывает временную шкалу и поток трафика между старой и новой версиями во время развертывания, релиза и canary-релиза:
Релиз означает, что пользователи получают новую версию
Релиз (release) — это момент, когда новая версия начинает обслуживать реальный пользовательский трафик. Трафик — это запросы, поступающие от пользователей к вашему приложению. Пока трафик по-прежнему направляется на старую версию, пользователи не почувствуют никакого эффекта от нового кода, лежащего на сервере.
Новая версия есть. Она работает. Но она простаивает. Никто к ней не обращается.
Релиз — это когда вы переключаете вывеску с "скоро в прокате" на "сейчас в кино". Проектор начинает крутить пленку, и зрители видят новый фильм.
Зачем их разделять?
Если можно развернуть и выпустить релиз одновременно, зачем их разделять? Потому что разделение дает вам контроль.
Когда развертывание и релиз — это одно и то же действие, каждое развертывание становится азартной игрой. Вы пушите код, пользователи сразу его видят, и если что-то ломается, проблему испытывают все. Нет буфера между "мы это разместили" и "пользователи это видят".
Когда вы их разделяете, у вас появляется окно возможностей. Вы можете:
- Развернуть новую версию и оставить ее в покое.
- Мониторить ее поведение без влияния на пользователей.
- Убедиться, что она корректно запускается, подключается к базам данных и обрабатывает внутренние запросы.
- Исправить проблемы до того, как их заметит хоть один пользователь.
Это окно — ваша страховочная сеть. Оно превращает развертывание из мероприятия с высокими ставками в рутинную операцию.
Как разделить развертывание и релиз
Самый простой метод — использовать балансировщик нагрузки или обратный прокси. Вот как это работает:
- Разверните новую версию на сервере рядом со старой версией.
- Настройте балансировщик так, чтобы весь пользовательский трафик направлялся на старую версию.
- Новая версия работает, но не получает ни одного внешнего запроса.
- Когда будете готовы, обновите конфигурацию балансировщика, чтобы направлять трафик на новую версию.
Это изменение конфигурации и есть ваш релиз. Оно может произойти через секунды после развертывания или через часы. Время зависит от вас.
Вот практический пример с использованием гипотетического CLI балансировщика для переключения трафика:
# Развернуть новую версию рядом со старой
# (предполагается, что обе уже запущены на сервере)
# Проверить текущее распределение трафика
trafficctl get-weight myapp
# Вывод: myapp-v1: 100%, myapp-v2: 0%
# Направить 10% трафика на новую версию (canary)
trafficctl set-weight myapp-v2 10%
# После мониторинга направить весь трафик на новую версию
trafficctl set-weight myapp-v2 100%
# Откат при необходимости: мгновенно перенаправить весь трафик обратно на старую версию
trafficctl set-weight myapp-v1 100%
Canary-релизы: постепенное развертывание
Более тонкий подход — canary-релиз. Вместо того чтобы переключать весь трафик сразу, вы сначала направляете небольшой процент пользователей на новую версию.
Скажем, у вас тысяча пользователей. Вы начинаете с направления пятидесяти из них на новую версию. Если через пять минут все выглядит хорошо, вы увеличиваете до двухсот. Затем до пятисот. Затем до всех.
Этот подход ограничивает радиус поражения. Если в новой версии есть баг, его испытают только пятьдесят человек вместо тысячи. Вы ловите проблемы на ранней стадии с минимальным ущербом.
Canary-релизы хорошо работают и с feature flags. Вы можете развернуть код, скрытый за флагом, включить его для небольшой группы, понаблюдать за результатами и постепенно расширять аудиторию.
Откат без повторного развертывания
Разделение также упрощает откат. Если вы выпустили плохую версию, вам не нужно переразвертывать старую. Старая версия все еще на сервере, все еще работает и все еще может обрабатывать трафик.
Вы просто меняете конфигурацию балансировщика обратно. Трафик переключается на старую версию. Пользователи снова на стабильной почве в течение секунд.
Сравните это с подходом, где развертывание и релиз объединены. Там откат означает:
- Поиск старого артефакта.
- Его повторное развертывание.
- Ожидание перезапуска сервера.
- Надежду, что сам откат не вызовет проблем.
Этот процесс занимает минуты в лучшем случае, а часто и дольше. В течение этого времени пользователи обращаются к сломанному приложению.
Кто решает, когда выпускать релиз?
Развертывание — это техническое решение. Ваш CI/CD-пайплайн может выполнять его автоматически. Но релиз часто вовлекает заинтересованные стороны из продукта или бизнеса.
Продуктовая команда знает, готова ли функция для пользователей. Они могут захотеть сначала протестировать ее внутри, провести A/B-тест или отложить релиз по маркетинговым причинам. Они понимают влияние на пользователей так, как не может пайплайн развертывания.
Это не значит, что каждый релиз требует совещания. Для рутинных обновлений вы можете автоматизировать релиз после короткого периода наблюдения. Но для значительных изменений решение о релизе должно приниматься людьми, понимающими бизнес-контекст.
Практический чек-лист для вашего следующего релиза
Прежде чем выпустить новую версию пользователям, пройдитесь по этим пунктам:
- Новая версия работает на production хотя бы несколько минут без ошибок?
- Логи показывают нормальное поведение?
- Есть ли способ перенаправить трафик обратно на старую версию в случае необходимости?
- Кто-то подтвердил, что функция готова с продуктовой точки зрения?
- Окно релиза выбрано так, чтобы минимизировать влияние на пользователей?
- Знаете ли вы, к кому обращаться, если после релиза что-то пойдет не так?
Этот список намеренно короткий. Излишнее усложнение процесса релиза приводит к пропуску шагов. Держите его простым и действительно проходите по нему каждый раз.
Главный вывод
Развертывание и релиз — это не одно и то же. Развертывание — это размещение кода на сервере. Релиз — это предоставление доступа к нему пользователям. Отношение к ним как к отдельным действиям дает вам контроль над рисками, скоростью отката и пользовательским опытом.
В следующий раз, когда ваш пайплайн станет зеленым, спросите себя: вы только что развернули или действительно выпустили релиз? Ответ определяет, получают ли ваши пользователи обновление или все еще ждут начала фильма.