Как мы настраиваем непрерывную доставку с помощью Bitbucket Pipelines, Heroku, Rails 5.2 и Webpacker.
Наша конечная цель
В настоящее время мы внедряем в нашем приложении подход непрерывной доставки. Существует множество отличных примеров использования конвейеров битбакетов. Однако найти конкретные примеры для нашего стека было непросто. Итак, вот что мы планировали и что сделали. Мы используем:
- Рельсы 5.2
- Webpacker 3.5.5
Rails Webpacker поставляется с Yarn и работает в среде Node. В нашем приложении есть тесты в Rails и тесты в JavaScript. В нашем процессе непрерывной интеграции мы хотим запускать тесты Rails и JavaScript.
Непрерывная интеграция, непрерывная доставка и непрерывное развертывание
Знать разницу между этими тремя подходами неочевидно. Эта статья помогла нам сориентироваться в различиях между ними. Это заставило нас задуматься о подходе, который лучше всего подходит для нашей команды. Автоматический поток нашей непрерывной доставки выглядит так:
Непрерывная доставка автоматизирует этап развертывания приложения до момента выпуска. Это делается с помощью ручного спускового крючка. Для нас это означало три отдельных конвейера на битбакете.
Что такое BitBucket Pipelines?
С помощью простого bitbucket-pipelines.yml
файла конфигурации вы можете создавать, тестировать и развертывать код в репозитории BitBucket. Вот руководство по началу работы.
Настройка нашего первого конвейера
ПРИМЕЧАНИЕ. Полная bitbucket-pipelines.yml
конфигурация находится внизу этой статьи.
Первая часть, которую мы хотели достичь, - это запустить тесты по запросу на включение в разработку. В BitBucket Pipelines мы можем настроить конвейеры специально для запросов на вытягивание. В корне вашего приложения Rails создайте файл bitbucket-pipelines.yml
со следующим кодом:
image: starefossen/ruby-node:latest
Эта одна строка настраивает образ Docker для запуска тестов и развертывания кода в наших различных средах. Этот конкретный образ Docker дает нам Ruby и Node.
В следующей части нашего файла конфигурации мы можем настроить наш конвейер для запросов на вытягивание:
pipelines: pull-requests: "**": - step:
Давайте разберемся с этим .pipelines:
- это место, где мы группируем все наши отдельные определения конвейера. pull-requests:
- это когда мы хотим, чтобы наш конвейер работал. Далее "**":
обозначает подстановочный знак. Мы настроили наш конвейер для запуска при выполнении запроса на перенос из любого источника в любое место назначения. Последняя часть - это — step
, которая запускает процесс Docker (с использованием предоставленного нами образа) и где мы будем выполнять наши команды конвейера.
Преимущество запуска нашего конвейера по запросу на вытягивание заключается в том, что код сначала объединяется от пункта назначения к источнику. Это означает, что если конвейер проходит, или, что более важно, дает сбой, код не был добавлен в ветвь разработки.
На этом этапе мы хотим настроить сценарий команд, который будет настраивать нашу среду и тестировать наше приложение. Многое из того, что мы установили, было взято из этого фантастического блога.
В нашем — step:
мы создадим script:
, который будет списком последовательных команд. Сначала мы устанавливаем и запускаем наши тесты JavaScript:
script: - yarn install - yarn test:js
Вторая часть нашего скрипта настраивает Rails для тестирования. Это немного сложнее. Вот что у нас получилось:
- export DATABASE_URL=postgresql://ci_test_user:ci_test_user_password@localho st/ci_test - cp config/database.ci.yml config/database.yml - bundle install --path vendor - RAILS_ENV=development bundle exec rake db:setup - RAILS_ENV=test bundle exec rake db:test:prepare - bundle exec rake test
Скорее всего, ваш database.yml
файл будет проигнорирован git. Вы можете продублировать и переименовать database.ci.yml
и указать правильные учетные данные:
default: &default adapter: postgresql encoding: unicode pool: 5 host: localhost development: <<: *default database: ci_development test: <<: *default database: ci_test username: ci_test_user password: ci_test_user_password
Теперь у нас есть правильные файлы базы данных. Затем нам нужно настроить нашу базу данных Postgres в нашем образе докера. Это находится в отдельном разделе bitbucket-pipelines.yml
, который называется определениями:
definitions: services: postgres: image: postgres environment: POSTGRES_DB: ci_test POSTGRES_USER: ci_test_user POSTGRES_PASSWORD: ci_test_user_password
Раздел определений позволяет нам определять ресурсы в нашем конвейере, такие как базы данных. У Definitions есть еще одна удобная функция caches
. Связи Bundler и yarn потребовали бы много времени для загрузки каждой отдельной сборки. Вместо этого мы можем определить каталоги, которые хотим кэшировать внутри конфигурации definitions:
:
definitions: caches: bundler: ./vendor yarn: ./node_modules services: postgres: image: postgres environment: POSTGRES_DB: ci_test POSTGRES_USER: ci_test_user POSTGRES_PASSWORD: ci_test_user_password
Теперь у нас есть кеши и настройки служб, которые нам нужно сообщить нашему конвейеру, чтобы они их использовали. В разделе -step
мы можем добавить:
- step: caches: - bundler - yarn services: - postgres
Мы создали наш первый конвейер!
Развернуть на промежуточной стадии
Следующим шагом в нашей непрерывной доставке является развертывание в тестовой среде. Для нас это означает развертывание на Heroku с новым конвейером. Bitbucket позволяет нам создавать конвейеры для конкретных веток, например:
clone: depth: full pipelines: branches: develop: - step: name: "Deploy to Staging" script: - git push https://heroku:[email protected]/$STAGING_HEROKU_APP_NAME.git HEAD:master
ПРИМЕЧАНИЕ. Перед развертыванием в Heroku нам необходимо добавить полный клон.
Этот конвейер запускается только тогда, когда новый код объединяется с ветвью разработки. Фактически, в настройках мы отключили отправку в эту ветку. В script
мы добавили в нашу промежуточную среду Heroku переменные среды, которые можно установить в вашей учетной записи Bitbucket.
Теперь мы подошли к интересному моменту. Наш код переведен на промежуточную стадию и требует подписи. Мы могли бы сделать что-то похожее на то, что было раньше, с запросом на перенос в мастер, а затем отправкой в реальном времени. Однако мы решили использовать ручной триггер для автоматического слияния кода и развертывания. Для этого мы можем добавить к нашему конвейеру дополнительный шаг:
- step: name: "Trigger Deploy to Production" trigger: manual script: - git checkout master - git merge develop - git push origin master
Теперь в конвейере после завершения развертывания в производственную среду он будет ждать ручного триггера (нажатие кнопки «Выполнить») перед выполнением сценария для слияния разработки в мастер.
Развернуть в производство
Последний шаг - отправить наш код в рабочую среду. Теперь мы слили наш код с мастером, чтобы мы могли запустить другой конвейер, чтобы отправить его в Heroku в рамках наших конвейеров ответвлений:
master: - step: name: "Deploy to Production" script: - git push https://heroku:[email protected]/$PRODUCTION_HEROKU_APP_NAME.git HEAD:master
Здесь мы установили другую переменную среды с именем нашего приложения, и эта команда отправит наш код в реальном времени.
Заключение
Если вы сделали что-то подобное и у вас есть комментарии или вопросы, дайте мне знать. Есть потенциальные улучшения, которые необходимо внести, и было бы здорово услышать предложения.
image: starefossen/ruby-node:latest clone: depth: full pipelines: branches: master: - step: name: "Deploy to Production" script: - git push https://heroku:[email protected]/$PRODUCTION_HEROKU_APP_NAME.git HEAD:master develop: - step: name: "Deploy to Staging" script: - git push https://heroku:[email protected]/$STAGING_HEROKU_APP_NAME.git HEAD:master - step: name: "Trigger Deploy to Production" trigger: manual script: - git checkout master - git merge develop - git push origin master pull-requests: "**": - step: name: "Build & Test" caches: - bundler - yarn script: - yarn install - yarn test:js - export DATABASE_URL=postgresql://ci_test_user:ci_test_user_password@localhost/ci_test - cp config/database.ci.yml config/database.yml - bundle install --path vendor - RAILS_ENV=development bundle exec rake db:setup - RAILS_ENV=test bundle exec rake db:test:prepare - bundle exec rake test services: - postgres definitions: caches: bundler: ./vendor yarn: ./node_modules services: postgres: image: postgres environment: POSTGRES_DB: ci_test POSTGRES_USER: ci_test_user POSTGRES_PASSWORD: ci_test_user_password