Preview Environments
Эфемерные окружения для каждого PR — как это меняет процесс ревью
Code review по скриншотам
Стандартный процесс code review в большинстве команд выглядит так: разработчик открывает pull request, ревьюер читает diff, пытается мысленно представить, как изменения будут работать, оставляет комментарии. Через пару итераций PR мёрджится. Проблема в том, что чтение diff это анализ кода в вакууме: ревьюер видит строки, но не видит результат. Для бэкенда ещё терпимо, можно проверить логику по коду. Для фронтенда, изменений в API, миграций базы данных или интеграций между сервисами чтение diff не даёт полной картины.
Некоторые команды пытаются решить проблему скриншотами: разработчик делает скриншот нового UI и прикладывает к PR. Но скриншот не интерактивен. На нём не видно, как работает анимация, что происходит при ресайзе окна, как ведёт себя форма при невалидном вводе. Другие команды просят ревьюера чекаутить ветку и запускать проект на своей машине. На это уходит время, конфигурация окружения может отличаться, и половина ревьюеров честно признается, что пропускает этот шаг.
Что такое preview environments
Preview environment (он же ephemeral environment, deploy preview, review app) это изолированное окружение приложения, которое CI/CD создаёт для каждого pull request. Разработчик пушит изменения в ветку и открывает PR. Пайплайн разворачивает приложение с этими изменениями на отдельном URL, например pr-142.preview.yourapp.dev, и ссылка появляется в PR.
Preview environments ускоряют онбординг: новый разработчик видит результат своего первого PR в работающем окружении, а не в diff. Жизненный цикл preview environment привязан к PR: окружение создаётся при открытии, обновляется при каждом пуше в ветку и уничтожается при мёрдже или закрытии. Эфемерная инфраструктура. Не стоит денег, когда не используется, и не требует ручного управления.
Как это меняет процесс ревью
Ревьюер открывает PR, видит ссылку на preview, кликает и получает работающее приложение с изменениями автора. Для фронтенда это значит: ревьюер проверяет UI на разных разрешениях, тестирует пользовательские сценарии, находит баги, которые в diff невидимы. Для бэкенда: отправляет реальный запрос к API и смотрит ответ, проверяет, что миграция отработала корректно, убеждается, что новый endpoint возвращает правильный формат.
Product-менеджеры и дизайнеры получают доступ к изменениям до мёрджа. Они дают фидбек по UX, ловят несоответствие макету, предлагают правки, пока код ещё свежий в голове разработчика. QA-инженеры начинают тестирование параллельно с code review, а не ждут деплоя в staging. Обнаружение багов сдвигается влево по pipeline и сокращает цикл обратной связи с дней до часов.
Инструменты
Kubernetes: namespace per PR
Если команда уже работает с Kubernetes, самый гибкий вариант — Argo CD с Pull Request Generator из ApplicationSet controller. При появлении нового PR Argo CD создаёт Application, разворачивает код из ветки PR в отдельный namespace, а при закрытии PR удаляет Application и чистит ресурсы. Работает с GitHub, GitLab, Bitbucket.
Этот подход требует настройки, но даёт полный контроль над инфраструктурой: не ограничен фронтендом, подходит для любых приложений. Вы контролируете, где крутятся данные и куда идёт трафик. Никакой зависимости от внешних платформ.
Альтернативы в экосистеме Kubernetes: Okteto разворачивает per-branch окружения с namespace isolation, включая базы данных и очереди. Bunnyshell поддерживает Docker Compose и Kubernetes и создаёт полную копию окружения для каждого PR.
Docker Compose: без Kubernetes
Для команд без Kubernetes подходит Docker Compose. CI-пайплайн собирает образы из ветки PR, поднимает docker compose up на сервере (или пуле серверов), пробрасывает URL через nginx reverse proxy. При закрытии PR пайплайн вызывает docker compose down и чистит volumes.
Схема простая: один сервер, docker compose с переменными окружения для номера PR, nginx конфиг с wildcard доменом. На практике этого хватает для команд до 20-30 разработчиков. Traefik упрощает маршрутизацию, если нужен автоматический TLS и service discovery.
GitLab Review Apps
В России GitLab self-hosted стоит на каждом втором сервере. Review Apps в GitLab CI/CD создают preview environment для каждого merge request. Конфигурация живёт в .gitlab-ci.yml: описываете environment с динамическим именем, задаёте on_stop action для cleanup, и GitLab отображает ссылку на окружение в merge request.
Работает с любым бэкендом: Kubernetes, Docker, виртуалки. GitLab Agent for Kubernetes упрощает деплой в кластер. Для простых случаев хватает shell executor и docker compose на раннере.
Managed-платформы (глобальные)
Для фронтенда и статических сайтов Vercel и Netlify дают preview deployments из коробки: подключаете Git-репозиторий, и каждый PR получает preview URL без настройки CI/CD. Cloudflare Pages предлагает аналогичную функциональность. Эти сервисы популярны за рубежом, но могут создавать проблемы с оплатой и доступом из России.
Базы данных и состояние
Самая сложная часть preview environments это управление состоянием. Статический фронтенд развернуть в изоляции легко, но когда приложению нужна база данных с тестовыми данными, очереди сообщений и внешние зависимости, задача усложняется.
Три подхода к решению. Первый: разделяемый staging-бэкенд. Preview environment фронтенда подключается к общему staging API. Работает для UI-изменений, но не помогает при изменениях в бэкенде или базе данных. Второй: snapshot базы данных. При создании preview environment CI копирует структуру и тестовые данные из seed-файла или снапшота. Neon (serverless Postgres) позволяет создавать ветки базы данных за секунды, каждый PR получает свою копию БД с данными из main. Третий: полная изоляция через контейнеры. Каждый preview environment включает все зависимости в Docker Compose или Kubernetes pod, что даёт максимальную независимость, но увеличивает стоимость и время создания окружения.
Trade-offs
Стоимость инфраструктуры. Каждый preview environment это вычислительные ресурсы. При активной разработке с десятками открытых PR счёт за инфраструктуру растёт. Как с этим жить: автоматическое выключение окружений, которые не использовали больше часа, spot-инстансы, лимит на количество одновременных preview environments.
Время создания. Если развёртывание preview environment занимает 20 минут, разработчики будут ждать и терять контекст. Цель: 2-5 минут для фронтенда, 5-10 минут для full-stack окружений. Кэширование Docker-образов, pre-built базовые образы и параллелизация шагов пайплайна помогают уложиться в эти рамки.
Безопасность данных. Preview environments не должны содержать production-данные. Используйте синтетические данные или анонимизированные снапшоты. Доступ к preview URL стоит ограничить аутентификацией, чтобы случайный человек с ссылкой не видел вашу внутреннюю разработку.
С чего начать
Если у вас GitLab self-hosted, начните с Review Apps. Если Kubernetes, поставьте Argo CD с ApplicationSet и Pull Request Generator. Если нет ни того ни другого, Docker Compose на CI-раннере с nginx reverse proxy закроет задачу за пару дней. В каждом случае первый эффект виден сразу: ревьюеры начинают находить баги, которые раньше доживали до staging, а product-менеджеры перестают спрашивать «можно посмотреть на это до релиза?». Ответ теперь это ссылка в PR.