Rails×RSpec×Docker×CircleCI

#はじめに
RailsアプリをDocker上で構築し、CircleCIを用いて、RSpecによる自動テスト、またHerokuへの自動デプロイの仕組みを実現していく。

**環境**

- フレームワーク : Rails
- テストフレームワーク : RSpec
- データベース : MySQL
- コンテナ : Docker(Docker Compose)
- CI/CDツール : CircleCI
- サーバー : Heroku

**前提**
GitHub、Herokuに登録済み
Docker、Docker Composeをインストール済み

**参考**
山浦清透さんの[Docker超入門講座 合併版 | ゼロから実践する4時間のフルコース](https://youtu.be/lZD1MIHwMBY)という動画を参考にさせていただく。

#Docker環境でRailsアプリを作成

作業用ディレクトリを用意し、必要なファイルを作成する。
今回はqiita-railsというディレクトリ内で作業していく。

```
qiita-rails/
          ├ src/
              └ Gemfile
          ├ docker-compose.yml
          └ Dockerfile
```

```rb:Gemfile
source 'https://rubygems.org'
gem 'rails', '~> 6.1.4', '>= 6.1.4.1'
```

```dockerfile:docker-compose.yml
version: '3'
services:
  db:
    image: mysql:8.0
    command: --default-authentication-plugin=mysql_native_password
    volumes:
      - ./src/db/mysql_data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: password
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - ./src:/app
    ports:
      - "3000:3000"
    environment:
      RAILS_ENV: development
    depends_on:
      - db
```

```dockerfile:Dockerfile
FROM ruby:2.7

RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
  && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
  && apt-get update -qq \
  && apt-get install -y nodejs yarn \
  && apt-get -y install imagemagick
WORKDIR /app
COPY ./src /app
RUN bundle config --local set path 'vendor/bundle' \
  && bundle install
```

作業用ディレクトリに移動後、Railsアプリを作成。

```
$ docker-compose run rails new . --force --database=mysql
```

*Gemfile*が更新されたのでコンテナのイメージをビルドし直す。

```
$ docker-compose build
```

*database.yml*のdefaultのpasswordとhostを設定。

```yml:src/config/database.yml
.
.
.
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: password
  host: db
.
.
.
```

データベースを作成する。

```
$ docker-compose run web rails db:create
```

コンテナを起動する。

```
$ docker-compose up
```

ブラウザでlocalhost:3000を開き、以下の画面が表示されていれば成功。
<img width="500" alt=rails_welcome.png src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2200191/1f5a9094-11bc-83c1-3e08-aeddaf31b656.png>

#Herokuの設定

Heroku、Heroku Container Registryにログインし、アプリを作成。

```
$ heroku login
$ heroku container:login
$ heroku create qiita-rails
```

MySQL用のアドオンを追加する(Herokuにクレジットカードの登録が必要）。

```
$ heroku addons:create cleardb:ignite -a qiita-rails
```

*database.yml*のproductionを設定する。

```yml:src/config/database.yml
.
.
.
production:
  <<: *default
  database: <%= ENV['APP_DATABASE'] %>
  username: <%= ENV['APP_DATABASE_USERNAME'] %>
  password: <%= ENV['APP_DATABASE_PASSWORD'] %>
  host: <%= ENV['APP_DATABASE_HOST'] %>
```

```
$ heroku config -a qiita-rails
```

でこれらの環境変数を確認し

```
$ heroku config:add
```

でそれぞれ設定していく。

作業用ディレクトリに、start.shを追加し、Dockerfileを編集する。

```
qiita-rails/
          ├ src/
          ├ docker-compose.yml
          ├ Dockerfile
　　　　　　　　　　　　　　　　　　　　└ start.sh
```

```bash:start.sh
#!/bin/sh

if [ "${RAILS_ENV}" = "production" ]
then
    bundle exec rails assets:precompile
fi

bundle exec rails s -p ${PORT:-3000} -b 0.0.0.0
```

```dockerfile:Dockerfile
FROM ruby:2.7

ENV RAILS_ENV=production

RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
  && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
  && apt-get update -qq \
  && apt-get install -y nodejs yarn \
  && apt-get -y install imagemagick
WORKDIR /app
COPY ./src /app
RUN bundle config --local set path 'vendor/bundle' \
  && bundle install

COPY start.sh /start.sh
RUN chmod 744 /start.sh
CMD ["sh", "/start.sh"]
```

Herokuに環境変数を追加する。

```
$ heroku config:add RAILS_SERVE_STATIC_FILES='true' -a qiita-rails
```

#CircleCIでCI/CDを構築

事前にGitHubにリポジトリを作成しておく。

GemfileにRSpecを追加する。

```rb:Gemfile
group :development, :test do
  gem 'rspec-rails'
end
```
*Gemfile*が更新されたのでコンテナのイメージをビルドし直す。

```
$ docker-compose build
```
下記ののコマンドでwebコンテナの中に入り、bashが使えるようにるので、

```
$ docker-compose exec web bash
```

RSpecをインストールする。

```
$ rails generate rspec:install
```

CircleCIにGitHubでログインする。
![スクリーンショット 2021-11-23 3.22.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2200191/330d29c5-6b45-f345-5165-4b4fcb6621f9.png)

作業用ディレクトリに、.circleciディレクトリ、config.ymlを追加する。

```
qiita-rails/
          ├ src/
          ├ docker-compose.yml
          ├ Dockerfile
　　　　　　　　　　　　　　　　　　　　├ start.sh
　　　　　　　　　　　　　　　　　　　　└ .circleci/
                    └ config.yml
```

```yml:.circleci/config.yml
version: 2.1
orbs:
  ruby: circleci/ruby@1.1.2
  heroku: circleci/heroku@1.2.3

jobs:
  build:
    docker:
      - image: circleci/ruby:2.7
    working_directory: ~/qiita-rails/src
    steps:
      - checkout:
          path: ~/qiita-rails
      - ruby/install-deps

  test:
    docker:
      - image: circleci/ruby:2.7-node
      - image: circleci/mysql:5.5
        environment:
          MYSQL_ROOT_PASSWORD: password
          MYSQL_DATABASE: app_test
          MYSQL_USER: root
    environment:
      BUNDLE_JOBS: "3"
      BUNDLE_RETRY: "3"
      APP_DATABASE_HOST: "127.0.0.1"
      RAILS_ENV: test
    working_directory: ~/qiita-rails/src
    steps:
      - checkout:
          path: ~/qiita-rails
      - ruby/install-deps
      - run:
          name: Database setup
          command: bundle exec rails db:migrate
      - run:
          name: yarn Install
          command: yarn install
      - run: 
          name: webpack
          command: bundle exec bin/webpack
      - run:
          name: Rspec
          command: bundle exec rspec

  deploy:
    docker:
      - image: circleci/ruby:2.7
    steps:
      - checkout
      - setup_remote_docker:
          version: 19.03.13
      - heroku/install
      - run:
          name: heroku login
          command: heroku container:login
      - run:
          name: push docker image
          command: heroku container:push web -a $HEROKU_APP_NAME
      - run:
          name: release docker image
          command: heroku container:release web -a $HEROKU_APP_NAME
      - run:
          name: database setup
          command: heroku run bundle exec rake db:migrate RAILS_ENV=production -a $HEROKU_APP_NAME
          
workflows:
  version: 2
  build_test_and_deploy:
    jobs:
      - build
      - test:
          requires:
            - build
      - deploy:
          requires:
            - test
          filters:
            branches:
              only: main
```

*database.yml*のtestを設定する。

```yml:src/config/database.yml
.
.
.
test:
  <<: *default
  database: app_test
  host: <%= ENV.fetch('APP_DATABASE_HOST') { 'db' } %>
.
.
.
```

```
$ heroku config:add
```

でmaster.keyの値をHerokuの環境変数RAILS_MASTER_KEYとして追加する。

CicleCIのサイトにログイン後、Projects→qiita-rails→Project Settings→Environment Variables→Add Environment Variablesと進み、

- Name:HEROKU_APP_NAME,　Value:qiita-rails
- Name:HEROKU_API_KEY,　Value:(HerokuのサイトでAccount settingsから確認)

を追加する。

#最後に
これで、gitにpush後GitHub上でCreate pull requestを行うと自動でRSpecによるテストが開始し、それが成功するとMerge pull requestが押せるようになり、Merge pull requestを実行するとまた自動でRSpecによるテストが開始し、それが成功すると自動でHerokuにデプロイされるという仕組みを実現することができた。
いずれサーバー環境をHerokuからAWSに切り替えようと考えている。