Heroku
CircleCI
Docker

[Rails]自動テスト〜自動デプロイまでをDockerコンテナで実行する方法


こちらの記事の続きです

RSpec on DockerでChromeブラウザテストを行う方法

DockerでのRuby on Rails環境構築を一つずつ詳解する

CircleCI→herokuのCI/CDパイプライン構築手順

手順としては上記記事の続きであり

・Dockerでの開発環境を構築している

・単体テスト・統合テストをDockerコンテナ内で実行できる

・Github→CircleCI→herokuのCI/CDパイプラインを構築している

を前提としています。

今回はこれらを組み合わせて

CicleCIでの自動テスト環境にdocker-composeを利用していきたいと思います。

これにより開発環境、テスト環境、本番環境の環境差分が無くなります。


CircleCIでDocker使用時はMachine Executor

CircleCIでは通常はdocker環境でテストを実行させるように

config.ymlを設定しますがdocker-composeを自分で使いたい場合は

MachineExecutor(VM環境)を選択します。

(CircleCIのDocker環境ではdocker-composeのvolumesが実行できません)


Machine Executorを使ったconfig.yml


config.yml

version: 2.0

jobs:
build:
machine: true
steps:
- run:
name: Start container
command: docker-compose up -d

基本的には

CircleCI→herokuのCI/CDパイプライン構築手順

こちらで書いたconfig.ymlと同じです。

相違点はdockerとimageを書いていた部分を「machine: true」に変更します。

これでCircleCIのLinuxVM上でコマンドが実行されます。


HerokuのContainerRegistryでデプロイ

次にheroku本番環境でもDockerコンテナが実行可能です。

サービス名はContainer Resigtryという名前で下記リンクが公式です。

Container Registry公式

$ heroku container:login --app APP_NAME

$ heroku container:push web --app APP_NAME
$ heroku container:release web --app APP_NAME

上記のコマンドのみでherokuでDockerコンテナを実行することができます。

container:pushで、Dockerfileを元にimage build、とheroku registryへのpushが実行されます。

そしてcontainer:relaseでpushしたイメージがリリースされます。

remoteが複数になるとapp名が必要になるので念のため

--appで明示的に指定しています。

また、初回はAPP,DB作成のため以下のコマンドが必要になります。

$ heroku create app_name

$ heroku addons:create heroku-postgresql:hobby-dev

つまりheroku containerコマンドをcircleci/config.ymlに

記述すればデプロイが可能ですね。


.circleci/config.yml の設定

heroku cointainer:loginが必要なので

公式にあるように以下のコマンドが必要です。

#heroku container:login

docker login --username=_ --password=${HEROKU_API_KEY} registry.heroku.com


.circleci/config.yml 完成版

そして完成版がこちらになります。


.circleci/config.yml

version: 2.0

jobs:
build:
machine: true
working_directory: ~/repo
steps:
- checkout
- run:
name: Start container
command: docker-compose up -d

- run: docker-compose exec web rails db:create
- run: docker-compose exec web rails db:schema:load

- run:
name: run tests
command: |
mkdir /tmp/test-results
TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | \
circleci tests split --split-by=timings)"

docker-compose exec web rspec \
--format progress \
--format RspecJunitFormatter \
--out /tmp/test-results/rspec.xml \
--format progress \
$TEST_FILES

- store_test_results:
path: /tmp/test-results
- store_artifacts:
path: /tmp/test-results
destination: test-results

deploy_stage:
machine: true
steps:
- checkout
- run:
name: install Heroku CLI
command: curl https://cli-assets.heroku.com/install.sh | sh
- run:
name: heroku maintenance on
command: heroku maintenance:on --app ${HEROKU_APP_NAME_STAGE}
- run:
name: deploy to heroku_staging
command: |
docker login --username=_ --password=${HEROKU_API_KEY} registry.heroku.com
heroku container:push web --app ${HEROKU_APP_NAME_STAGE}
- run:
name: rails db migrate
command: heroku run rails db:migrate --app ${HEROKU_APP_NAME_STAGE}
- run:
name: release app
command: heroku container:release web --app ${HEROKU_APP_NAME_STAGE}
- run:
name: heroku maintenance off
command: heroku maintenance:off --app ${HEROKU_APP_NAME_STAGE}

deploy_prod:
machine: true
steps:
- checkout
- run:
name: install Heroku CLI, if necessary
command: curl https://cli-assets.heroku.com/install.sh | sh
- run:
name: heroku maintenance on
command: heroku maintenance:on --app ${HEROKU_APP_NAME_PROD}
- run:
name: deploy to heroku_staging
command: |
docker login --username=_ --password=${HEROKU_API_KEY} registry.heroku.com
heroku container:push web --app ${HEROKU_APP_NAME_PROD}
- run:
name: rails db migrate
command: heroku run rails db:migrate --app ${HEROKU_APP_NAME_PROD}
- run:
name: release app
command: heroku container:release web --app ${HEROKU_APP_NAME_PROD}
- run:
name: heroku maintenance off
command: heroku maintenance:off --app ${HEROKU_APP_NAME_PROD}

workflows:
version: 2
build-deploy:
jobs:
- build
- deploy_stage:
requires:
- build
filters:
branches:
only:
- staging
- deploy_prod:
requires:
- build
filters:
branches:
only:
- master


必要な環境変数は

HEROKU_API_KEY、HEROKU_APP_NAME_STAGE、HEROKU_APP_NAME_PRODです。

それぞれCircleCIのUIから設定してください。

これで自動テストと、検証環境、本番環境への自動デプロイ。

そしてそれらがDockerコンテナで実行されるCI/CDが構築できました。


注意点

Dockerfileに下記の記述が無いとherokuコンテナで

railsが起動しない場合があるので注意が必要です。


Dockerfile


CMD ["rails", "server", "-b", "0.0.0.0"]

ここの設定については

DockerでのRuby on Rails環境構築を一つずつ詳解する

こちらで書いています。