Разворачивание Rails-приложения через Gitlab CI/CD и Capistrano
Rails auto deploy via Gitlab CI/CD and Capistrano
Описание
В инструкции показано, как настроить автоматическое разворачивание приложения Ruby On Rails через Gitlab CI/CD используя Capistrano с сохранением возможности запускать Capistrano локально. Разворачивание будет автоматически запускаться при публикации изменений в рабочую ветку конкретного окружения, после окончания будет отправлено уведомление в Slack.
Перед выполнением
Инструкция предполагает, что у вас:
- Настроен облачный сервер под управлением Ubuntu с не-root пользователем с sudo правами и доступом по SSH.
- Есть GitLab-репозиторий с Rails-приложением, в котором настроено разворачивание через Capistrano.
- Скрипты Capistrano добавлены в репозиторий. Если ранее они у вас игнорировались git’ом, то перед их добавлением убедитесь, что все приватные данные вынесены в переменные окружения.
Алгоритм
Инструкция включает следующие шаги:
- Установка и регистрация GitLab Runner’а. Это программное обеспечение будет запускать CI/CD на сервере GitLab.
- Настройка подключения по SSH со стороны GitLab, чтобы процесс автоматического разворачивания мог производить удаленное подключение к серверу.
- Настройка переменных GitLab CI/CD, с помощью которых CI/CD получит доступ к приватной информации, которая отсутствует в репозитории.
- Создание файла .gitlab-ci.yml, в котором будет будет описан алгоритм выполнения автоматического разворачивания.
- Настройка уведомлений в Slack об окончании разворачивания.
Если у вас кроме Production сервера имеется Staging окружение, то рекомендуется настроить CI/CD сначала для него, а затем повторить необходимые пункты инструкции для Production.
Установка и регистрация GitLab Runner’а
Runner, это приложение, которое работает на сервере GitLab и исполняет операции CI/CD. Если у вас уже настроен Runner, то данный пункт инструкции можно пропустить.
Для начала установите саму программу Runner на сервер по этой инструкции:
Далее необходимо зарегистрировать новый экземпляр Runner’а, в котором будет исполняться CI/CD. Таких Runner’ов можно создавать несколько под разные нужды. Зарегистрируйте Runner на Linux с тегом ruby, работающий под executor’ом docker по этой инструкции:
Настройка подключения по SSH со стороны GitLab
GitLab CI/CD во время выполнения инструкций будет подключаться по SSH к облачному серверу. Необходимо настроить доступ.
Подключитесь к серверу по SSH и создайте новую пару ключей. Для этого выполните команду:
ssh-keygen -t rsa -b 2048
Пароль необходимо оставить пустым. Когда система задаст вопросы “Enter passphrase (empty for no passphrase)” и “Enter same passphrase again”, то нажимайте Enter.
Скопируйте публичную часть ключа в файл ~/.ssh/authorized_keys, выполнив команду:
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
Выведите на экран и скопируйте приватную часть ключа:
cat ~/.ssh/id_rsa
Далее необходимо добавить приватную часть ключа в переменную GitLab CI/CD — он имеет доступ к этим переменным и может использовать их значения в процессе выполнения. Откройте проект на GitLab и зайдите в пункт меню Settings -> CI/CD:
Разверните раздел Variables:
В поле Key введите значение SSH_PRIVATE_KEY
, в поле Value вставьте приватную часть ключа.
В поле Scope можно настраивать область видимости переменной в зависимости от окружения, в котором разворачивается приложение. Для этого напечатайте его название в текстовом поле и нажмите “Create wildcard <ENVIRONMENT>
”.
В результате должно получиться так:
Сохраните изменения, нажав кнопку Save variables:
Подробнее про переменные Gitlab CI/CD можно узнать здесь.
Далее необходимо добавить публичную часть ключа в настройки репозитория Project -> Settings -> Repository в качестве Deploy Key, что даст доступ к репозиторию от имени сервера через SSH:
Выведите на экран и скопируйте публичную часть ключа:
cat ~/.ssh/id_rsa.pub
Необходим только доступ на чтение, поэтому галочку Write access allowed отмечать не нужно.
После добавления ключа удостоверьтесь, что сервер имеет доступ к репозиторию. Для этого склонируйте его:
git clone git@gitlab.example.com:<GROUP>/project-sample.git
На вопрос “Are you sure you want to continue connecting (yes/no)?” отвечайте yes, чтобы добавить GitLab в список известных хостов. После проверки созданную папку можно удалить:
rm -rf project-sample/
Настройка переменных GitLab CI/CD
В проекте могут быть файлы, которые не добавлены в репозиторий посредством .gitignore и имеют свои собственные версии для разных окружений.
Предположим, что это файлы .env, Procfile и config/database.yml, версии которых для разных окружений хранятся в папке shared/<ENVIRONMENT>/ и копируются на сервер через Capistrano в момент выполнения разворачивания.
Нужно предоставить доступ к этим файлам для CI/CD. Для этого откройте окно управления переменными, в поле Type выберите File, а в поле Value вставьте контент файла:
Укажите следующие имена для файлов:
- .env —
DOT_ENV
- Procfile —
PROCFILE
- config/database.yml —
DATABASE_YML
Далее для CI/CD нужно указать данные для подключения к серверу. Предположим, что скрипт Capistrano получает их из переменных окружения DEPLOY_USER
, DEPLOY_PASSWORD
, SERVER_ADDRESS
, SSH_PORT
, которые описаны в специальном файле .deploy.<ENVIRONMENT>.env. Добавьте соответствующие переменные в CI/CD с типом Variable.
Создание файла .gitlab-ci.yml
Чтобы настроить CI/CD для проекта, необходимо создать в корневом каталоге файл .gitlab-ci.yml. Файл должен присутствовать в ветке master. Переключитесь в неё:
git checkout master
Скопируйте себе следующий файл .gitlab-ci.yml:
Данный файл настраивает GitLab CI/CD на выполнение следующих действий:
- Выполнение
bundle install
, чтобы запустить Capistrano. - Настройка подключения по SSH.
- Копирование файлов из переменных GitLab CI/CD в нужную для Capistrano папку.
- Создание файла с переменными окружения для Capistrano на основе переменных GitLab CI/CD.
- Запуск Capistrano.
В файле встречаются два типа блоков: без точки в начале имени и с точкой. Блоки без точек — это прямые инструкции для CI/CD. Блоки с точкой — это вспомогательные блоки кода, на которые можно ссылаться из основных блоков:
- В виде якорей через связку
&
—*
. Аналог определения и вызова функций в языках программирования. - В виде ключа
extends
— Аналог наследования в языках программирования.
Более детально ознакомиться с форматом файла можно здесь. Ниже приведено описание ключей из файла:
image
— Снимок Docker, на основе которого будет создан Docker-контейнер для выполнения CI/CD. Замените версию ruby на ту, которая используется в вашем проекте.stages
— описывает последовательность шагов, которые нужно выполнить. В данном случае производится только автоматическое разворачивание, поэтому шаг всего один —deploy
. Названия для шагов можно выдавать любые, они не фиксированы. Далее в файле будет описана реализация шагов.cache
— настраивает кэш Runner’а. По умолчанию при каждом новом запуске CI/CD вы получаете чистый Docker-контейнер, а значит,bundle install
будет заново устанавливать все Gem’ы. Кэш позволяет сохранить их между запусками CI/CD. С помощью ключаkey
настроено, чтобы каждая ветка репозитория имела свой собственный кэш.before_script
— скрипт, который нужно выполнить перед каждым шагом. Может быть объявлен глобально, а может для каждого шага в отдельности. В данном случае настроено, чтобы перед каждым шагом выполнялсяbundle install
..init-ssh-script
— вспомогательный блок кода для настройки SSH-подключения по открытому ключу..init-shared-script
— вспомогательный блок кода для копирования файлов из переменных CI/CD в папку с проектом, где они будут видны скрипту Capistrano..init-capistrano-env-script
— вспомогательный блок кода для создания файла с переменными окружения для подключения к серверу..run-capistrano-script
— вспомогательный блок кода для запуска Capistrano..capistrano
— вспомогательный блок кода для общего описания шагаdeploy
. В нём с помощью ключаstage
указан шаг CI/CD. Ключtags
указывает, на каком Runner’е запустить CI/CD. Ключonly.variables
указывает, какие переменные должны быть настроены в CI/CD, иначе шаг не запустится. Ключscript
, это основной код шага, где и запускается Capistrano.capistrano:<ENVIRONMENT>
— конкретная реализация шагаdeploy
для конкретного окружения. В данном примере реализация написана для Production и Staging окружений. Ключextends
указывает, на основе какого блока создан этот шаг. Ключonly.refs
ограничивает запуск CI/CD для конкретных веток. Ветка, для которой выполняется скрипт, доступна в нём под переменной$CI_COMMIT_REF_SLUG
. Ключenvironment
указывает имя окружения, которое доступно в скрипте через специальную переменную$CI_ENVIRONMENT_NAME
.
Дальнейший ход событий зависит от того, для каких окружений настроены переменные CI/CD. Если они настроены для Production, то при первой публикации изменений в ветку master запустится автоматическое разворачивание. Если они настроены только для другого окружения, например Staging, то CI/CD запустится только при публикации изменений в соответствующую ветку.
Зафиксируйте изменения в ветке и опубликуйте её на GitLab:
git add -A
git commit -m "Added file .gitlab-ci.yml"
git push origin master
Посмотреть выполнение CI/CD можно в пункте меню GitLab’a CI/CD->Pipelines:
Надпись running указывает на то, что в данный момент выполняется процесс CI/CD. Если нажмете на неё, то откроется более детальный интерфейс, в котором видно все этапы, описанные в файле .gitlab-ci.yml:
При нажатии на конкретный этап можно посмотреть логи его выполнения. Если всё сделано правильно, то в самом конце вы увидите сообщение об успехе:
Настройка уведомлений в Slack
В GitLab’е можно включить различные уведомления в Slack, но без возможности настройки текста сообщений. Обойти это ограничение можно, если вручную вызвать API-запрос на отправку сообщения в Slack.
Для начала добавьте интеграцию входящего вебхука: https://my.slack.com/services/new/incoming-webhook.
Выберите канал по-умолчанию для отправки сообщений и нажмите кнопку Add Incoming WebHooks integration:
После этого откроется экран, на котором нужно скопировать значение Webhook URL. На этой же странице вы можете настроить имя пользователя, который будет писать сообщение в Slack, его аватарку и описание:
Заполните 2 новых переменных в GitLab CI/CD без указания Scope:
SLACK_CHANNEL_NAME
— имя канала, в который необходимо присылать уведомления по проекту. Если будете отправлять личные сообщения, то имя нужно начинать с символа@
.SLACK_WEBHOOK
— полученный URL вебхука.
Создайте в корне проекта скрипт для отправки сообщения в Slack с названием gitlab_ci_slack_notification.sh и следующим содержанием:
Сделайте файл исполняемым:
chmod +x gitlab_ci_slack_notification.sh
Доработайте файл .gitlab-ci.yml. Добавьте в stages два новых пункта — notify_success и notify_failure, их реализации и запуск для конкретных окружений:
Теперь, после выполнения разворачивания, в Slack будет отправлено сообщение со статусом выполнения операции.