Что нам стоит стэйдж построить? Часть 1

Я работаю в Купибилете год. Прошлой весной фронтенд-команда состояла из 3 разработчиков. Периодически приходилось и приходится проверять результат: работает ли это решение, аккуратно ли свёрстано, не сломалось ли что-то.

Можно делать это и локально: застэшил или закоммитил свои изменения, склонировал ветку, перешел в нее, запустил, проверил, вернулся к своему коду. Но, во-первых, это утомительно. Сейчас у нас 7 разработчиков, следовательно, кол-во фич и веток, больше в 1.5–2 раза. Во-вторых, совсем не годится в случае, если наработки проверяются еще кем-то, скажем, дизайнером.

В таких ситуациях на помощь приходит staging.


Что это такое?

Стэйджинг (staging) — это окружение, которое является точной копией вашего продакшн сервера. Допустимы минимальные отличия, но идеальные условия — полная идентичность.

Он служит для тестирования продукта . Правильный стэйджинг существует отдельно от продакшена.

Как было раньше?

У нас в компании было понятие «дев» (от development). Девы были публичными и внутренними. Публичные были доступны по поддоменам вида foobar.kupibilet.ru, деплоились ручками девопсом и использовались только в случаях, когда нужно было что-то показать партнёрам и другим людям со стороны.

Локальные же использовались для тестирования, были доступны только внутри VPN и размещались на офисном сервере. Каждый разработчик имел свой поддомен вида username.domain.local и мог самостоятельно деплоить на него.

И это неплохо работало. Но ровно до того момента, когда скорость разработки превысила скорость тестирования. Начали появляться проблемы вида «Антон, а задеплой пожалуйста ветку X, Костя протестит, а потом верни ветку Y, я посмотрю». Разработчику приходилось жонглировать ветками.

Как должно быть?

Я довольно быстро пришел к выводу, что деплой на стэйджинг должен быть встроен в CI (Continuous Integration). Каждая ветка должна деплоиться и обновляться без участия разработчика.

В голову пришло 2 варианта:

  1. префикс в URL — your-domain.com/branch-name;
  2. уникальный поддомен — branch-name.your-domain.com.

Мне показалось, что префикс реализовать проще: нужно было всего лишь указать basename в history. А если у вас не SPA, то просто запрефиксовать все ссылки. По непонятным причинам этот способ не работал. И это хорошо. Почему? Он противоречит принципу «так же, как и на продакшене». Да и сломать что-то с путями можно.

Правильная реализация

Я составил список хотелок:

  1. доступ по HTTPS;
  2. каждая ветка располагается на собственном поддомене вида branch-name.your-domain.com;
  3. удалять файлы после мерджа или закрытия пул-реквеста

HTTPS

Это проще всего. Внутри компании мы используем самоподписанный сертификат, а на продакшене у нас wildcard уже был. Беглый поиск в гугле выдает цену от $65 за сертификат. Как вариант, можно попробовать генерировать сертификат Let’s Encrypt для каждого поддомена, но это будет являться точкой отказа, скажется на скорости деплоя и конфиг nginx будет сложнее.

Деплой

Основной принцип: каждая ветка попадает в свою собственную директорию и доступна по поддомену, который соотвествует названию ветки. К примеру, ветка new-main-page будет располагаться в /srv/www/project/new-main-page. А доступна по адресу new-main-page.project.com

Как деплоить — дело ваше. Используйте что хотите. Хоть rsync. Мы используем shipit и свой форк shipit-deploy (это, кстати, обёртка над rsync, а результат очень похож на работу capistrano).

Команда может выглядеть примерно так:

rsync -a ~/dir1 username@remote_host:destination_directory

Помните, мы будем запускать это всё на CI. Это означает, что название ветки должно определяться автоматически. Эта информация обычно находится в Environment Variables. У Travis CI это TRAVIS_BRANCH, у Gitlab CI_COMMIT_REF_NAME либо CI_COMMIT_REF_SLUG (см. документацию CI).

Так же нам нужно знать текущую директорию: тут нам поможет TRAVIS_BUILD_DIR в Travis CI, CI_PROJECT_DIR в Gitlab.

Используем полученную информацию:

rsync -a $CI_PROJECT_DIR username@remote_host:/srv/www/project/$CI_COMMIT_REF_SLUG

Получаем следущий результат:

Список директорий

Настраиваем nginx

Задача nginx: вычленить из URL название ветки и отдать файлы из нужной директории.

Это можно сделать так:

Пример конфигурации nginx

Удаление старых веток

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

rm -rf /srv/www/project/$CI_COMMIT_REF_SLUG

Заключение

Если у вас статика, то всё довольно просто. 2–3 команды и один конфиг nginx позволят сэкономить уйму времени и оптимизировать процесс тестирования.

Ну а если в вашем случае всё не так просто, скажем, вам нужно стартовать сервер, то веселье только начинается. Но об этом в следующей статье.

Полезные ссылки