Как мы настраиваем непрерывную доставку с помощью 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