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

##こちらの記事の続きです

[RSpec on DockerでChromeブラウザテストを行う方法](https://qiita.com/t-koshi/items/97adab8628d201e85d10)
[DockerでのRuby on Rails環境構築を一つずつ詳解する](https://qiita.com/daichi41/items/dfea6195cbb7b24f3419)
[CircleCI→herokuのCI/CDパイプライン構築手順](https://qiita.com/daichi41/items/972483e963b6a08933d8)


手順としては上記記事の続きであり
**・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

```yml:config.yml
version: 2.0
jobs:
  build:
    machine: true
    steps:
      - run:
          name: Start container
          command: docker-compose up -d
```

基本的には
[CircleCI→herokuのCI/CDパイプライン構築手順](https://qiita.com/daichi41/items/972483e963b6a08933d8)
こちらで書いたconfig.ymlと同じです。
相違点はdockerとimageを書いていた部分を「machine: true」に変更します。
これでCircleCIのLinuxVM上でコマンドが実行されます。



##HerokuのContainerRegistryでデプロイ

次にheroku本番環境でもDockerコンテナが実行可能です。
サービス名はContainer Resigtryという名前で下記リンクが公式です。
[Container Registry公式](https://devcenter.heroku.com/articles/container-registry-and-runtime)


```
$ 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　完成版

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

```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が起動しない場合があるので注意が必要です。

```yml:Dockerfile

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

ここの設定については
[DockerでのRuby on Rails環境構築を一つずつ詳解する](https://qiita.com/daichi41/items/dfea6195cbb7b24f3419)
こちらで書いています。