【Rails7】RailsアプリケーションのDocker化 + GitHubActionsでCIを設定する

# はじめに
`Rails`のみのアプリケーションを作成したけど、その後の`Docker`にマウントさせる方法と`GitHubActions`による`CI`設定がわからない、、、という人向けに**ハンズオン形式**で流れをまとめてみました。

# Railsアプリケーションの開発環境
- Ruby 3.2.2
- Ruby on Rails 7.0.8
- PostgreSQL
- esbuild(バンドラー)

# Railsアプリケーションの作成

```javascript
rails new mount_docker -j esbuild -d postgresql
```
```javascript
cd mount_docker
```

# Dockerの設定

作業ディレクトリ直下に`Dockerfile`を作成します。
```ruby
touch Dockerfile
```

```Dockerfile
FROM ruby:3.2.2

RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
RUN mkdir /app
WORKDIR /app

COPY Gemfile /app/Gemfile
COPY Gemfile.lock /app/Gemfile.lock

RUN bundle install
COPY . /app

COPY entrypoint.sh /usr/bin/

RUN chmod +x /usr/bin/entrypoint.sh

ENTRYPOINT ["entrypoint.sh"]

EXPOSE 3000

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

サーバー起動時の対策として、`entrypoint.sh`を同じく作業ディレクトリ直下に作成します。

```sh
touch entrypoint.sh
```

```sh
#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /myapp/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"
```
次に`docker-compose.yml`を作成します。
```sh
touch docker-compose.yml
```

```yml
version: '3'
services:
  db:
    image: postgres
    volumes:
      - postgresql-data:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: ${DATABASE_USERNAME}
      POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
    ports:
      - '5433:5433'
  web:
    build: .

    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 8000 -b '0.0.0.0'"
    volumes:
      - .:/app
    ports:
      - '8000:8000'

    depends_on:
      - db
volumes:
  postgresql-data:
    driver: local
```

# 環境変数の秘匿化とdatabase.ymlの設定
```ruby:Gemfile
group :development, :test do
  gem 'dotenv-rails'
end
```


```terminal:.env
touch .env
```

```terminal:.env
DATABASE_USERNAME=xxxxxxxx
DATABASE_PASSWORD=xxxxxxxx
```

```yml:database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: <%= ENV['DATABASE_USERNAME'] %>
  password: <%= ENV['DATABASE_PASSWORD'] %>
  pool: 5

development:
  <<: *default
  database: app_development

test:
  <<: *default
  database: app_test
  
# 本番の設定は適宜変更してください。
```

# Docker起動とサーバーの立ち上げ

```terminal
docker-compose build
```

```terminal
docker-compose up -d
```

```terminal
docker-compose exec web bash
```

```terminal
rails db:create
```

```terminal
localhost:8000でブラウザ表示を確認
```

![スクリーンショット 2023-12-08 1.10.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517817/ef8fbaad-4bab-a411-b84e-bb50114edce8.png)

# GitHubActionsによるRspec・RubocopのCI設定

作業ディレクトリ直下に`CI`用のファイルを作成します。
```terminal
mkdir -p .github/workflows && touch .github/workflows/ci.yml
```

```yml:.github/workflows/ci.yml
name: Continuous Integration

on:
  push:

jobs:
  rspec:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: .
    services:
      postgres:
        image: postgres:13
        ports:
          - 5432:5432
        env:
          POSTGRES_USER: postgres
          POSTGRES_PASSWORD: postgres
          POSTGRES_DB: test

    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Set up Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: 3.2.2
          bundler-cache: true

      - name: Cache node modules
        uses: actions/cache@v3
        with:
          path: node_modules
          key: ${{ runner.os }}-node-${{ hashFiles('**/yarn.lock') }}
          restore-keys: |
            ${{ runner.os }}-node-

      - name: Bundler and gem install
        run: |
          gem install bundler
          bundle install

      - name: Database create and migrate
        run: |
          cp config/database.yml.ci config/database.yml
          bundle exec rails db:create RAILS_ENV=test
          bundle exec rails db:migrate RAILS_ENV=test

      - name: Run rspec
        run: bundle exec rspec

  rubocop:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: .
    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Set up Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: 3.2.2
          bundler-cache: true

      - name: Bundler and gem install
        run: |
          gem install bundler
          bundle install

      - name: Run rubocop
        run: bundle exec rubocop
```

`CI`用の`yml`ファイルを作成しておきます。

```ruby
touch config/database.yml.ci
```
```yml:config/database.yml.ci
test:
  adapter: postgresql
  encoding: unicode
  database: test
  username: postgres
  password: postgres
  host: localhost
  port: 5432
```



### Gemのインストール

```ruby
group :development, :test do
  gem 'rspec-rails'
  gem 'rubocop'
end
```

```ruby
bundle install
```
`RSpec`用のファイルを作成します。

```ruby
rails g rspec:install
```
念の為コマンドを確認します。

```ruby
root@dd6579770655:/app# rspec
No examples found.


Finished in 0.0006 seconds (files took 0.13951 seconds to load)
0 examples, 0 failures
```

`Rubocop`ですが、テストを通すためにいくつかのケースを除外しておきます。
この辺りは適宜変更してください。

```ruby
touch .rubocop.yml
```
```ruby:.rubocop.yml
Style/Documentation:
  Enabled: false

Metrics/CyclomaticComplexity:
  Enabled: false

Metrics/MethodLength:
  Enabled: false

Metrics/PerceivedComplexity:
  Enabled: false

Layout/LineLength:
  Max: 200

Metrics/BlockLength:
  Enabled: false
```
`Rubocop`を実行します。
```ruby
rubocop -A

Inspecting 33 files
.................................

33 files inspected, no offenses detected
```

再度ビルドします。

```
docker-compose build
```


`GitHub`上にリポジトリを作成し、`Push`すると、これがトリガーとなり`CI`が実行されます。

画像のように`Actions`タブで`CI`がパスされたことを確認できます。
もしCIが通らないのであれば、適宜修正してください。

![スクリーンショット 2023-12-08 2.45.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517817/cd0dc283-c843-b8af-0c0d-73312ad26f2f.png)


# まとめ

`Docker`と`GitHubActions`で効率的に開発していきましょう！