【初心者向け】Rails環境をDockerで構築する方法

Dockerを自分で構築したことがなかったので、以下の記事を参考にRailsの環境構築をDockerで行いました。その際に学んだことのアウトプットをしたく記事にしました。
＊初心者向けの内容となります。

https://musclecoding.com/rails7-mysql8-docker/

## はじめに
今回はRails 7とMySQLの開発環境を構築します。
もしまだDockerをインストールしていない場合は公式サイトからダウンロードしておきましょう。

https://www.docker.com/ja-jp/

インストールが出来たら、作業ファルダを作成しておきます。
```bash
mkdir rails-docker
```
```bash
cd rails-docker
```

## 必要になるファイル
- Dockerfile
- docker-compose.yml
- Gemfile
- Gemfile.lock
- entrypoint.sh

以下のコマンドで一括でファイル作成ができます。
```bash
touch Dockerfile docker-compose.yml Gemfile Gemfile.lock entrypoint.sh
```

作成ができたらファイルを編集していきます。

## Dockerfile
まずはDockerfileの編集から行っていきます。
Dockerfileは、イメージを作成するための手順書です。

ちなみに、イメージやコンテナなどDockerに関連する用語を理解するのに以下の動画が参考になりました。

https://www.youtube.com/watch?v=YfaB3PJv1f0

```dockerfile
# ベースイメージを指定
FROM ruby:3.3.5
ARG RUBYGEMS_VERSION=3.5.22

# 作業ディレクトリを指定
WORKDIR /sample_rails

# ホスト(自分のPC)のGemfileをコンテナ内の作業ディレクトリ(sample_rails)にコピー
COPY Gemfile Gemfile.lock ./

# sample_rails内でbundle installを実行
RUN bundle install

# ホストのファイルをコンテナ内の作業ディレクトリにコピー
COPY . ./

# entrypoint.shをコンテナ内のbinフォルダ配下にコピー
COPY entrypoint.sh /usr/bin/

# entrypoint.shの実行権限を付与
RUN chmod +x /usr/bin/entrypoint.sh

# コンテナ起動時にentrypoint.shを実行するように設定
ENTRYPOINT ["entrypoint.sh"]

# コンテナ起動時に実行するコマンドを指定
CMD ["rails", "server", "-b", "0.0.0.0"]
```

ちなみに以下の部分の記述は`sample_rails`フォルダをDockerコンテナ内に作成しています。
これにより、以降の操作は`sample_rails`で行われるようになります。
僕は最初イメージがつきにくかったので、補足として入れました。
```Dockerfile
WORKDIR /sample_rails
```

## docker-compose.yml
docker-compose.ymlは複数のコンテナの設定と管理を行うためのファイルです。
今回はMySQLとRailsの2つのコンテナの設定を記述しています。
```docker
services:
 # MySQLデータベースのコンテナ設定
 db:
   image: mysql:8.0
   environment:
     MYSQL_ROOT_PASSWORD: password
   volumes:
     - mysql_volume:/var/lib/mysql
   # ポート転送設定（ホスト:コンテナ）
   ports:
     - '3306:3306'
   # MySQL8.0でのパスワード認証方式を設定
   command: --default-authentication-plugin=mysql_native_password

 # Railsアプリケーションのコンテナ設定
 web:
   # Dockerfileからイメージをビルド
   build:
     context: .
     dockerfile: Dockerfile
   # コンテナ起動時に実行されるコマンド（CMD ["rails", "server", "-b", "0.0.0.0"]を上書き）
   command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails tailwindcss:build && bundle exec rails s -p 3000 -b '0.0.0.0'"
   volumes:
     - .:/sample_rails
   # ポート転送設定（ホスト:コンテナ）
   ports:
     - 3000:3000
   stdin_open: true
   tty: true
   # dbコンテナが起動してから開始するように設定
   depends_on:
     - db

# データを永続化するボリュームの定義
volumes:
 mysql_volume:                      
```
個人的に理解するのに苦戦した部分について解説をしていきます。
```
   volumes:
     - mysql_volume:/var/lib/mysql 
```
この部分はMySQLコンテナのデータを永続化させるための設定です。
一番下に記述されている`mysql_volume`はデータを永続化させるためのボリュームを定義しています。
このボリュームとMySQLコンテナ内のデータをマウント（接続）することでコンテナが削除してもデータが消えないようになります。

```
context: .        
```
`context: .`を指定すると最初に作成した`rails-docker`内にあるファイルがDockerでも扱えるようになります。
そして、`dockerfile: Dockerfile`で`rails-docker`の直下にある`Dockerfile`を読み込むようにしています。
ちなみに、`Dockerfile`内で記述している、`COPY . ./`は、`rails-docker`内にあるファイルたちをDockerコンテナ内の`sample_rails`にコピーするという意味です。

## entrypoint.sh
entrypoint.shは、コンテナが起動する時に最初に実行されるスクリプトです。
```
#!/bin/bash

set -e
# エラーが発生したら即座にスクリプトを終了する設定

rm -f /sample_rails/tmp/pids/server.pid
# サーバーの二重起動を防ぐため、前回のサーバーPIDファイルを削除

exec "$@"
# docker-compose.yml の command を実行
```

## Gemfile
今回は7.2を指定しました。
```ruby
source 'https://rubygems.org'
gem 'rails', '~> 7.2'
```

## Railsプロジェクトの作成
dockerのコマンドを使ってRailsプロジェクトを作成していきます。
```bash
docker compose run web rails new . --force --database=mysql --css=tailwind
```
コマンドの意味は下記のとおりです。
`docker-compose run web` webコンテナで実行
`rails new .` カレントディレクトリにRailsアプリ作成
`--force` ファイルが存在する場合に上書き
`--database=mysql` DBはMySQLを使用
`--css=tailwind` TailwindCSSを設定

**＊このコマンド実行後、Dockerfileが書き換えられてしまうので再度先ほどの内容に変更してください。**
他に良い対応が思いつきませんでした🙇‍♂️
## コンテナイメージをビルド
先ほど編集したDocker関連のファイルを使ってコンテナイメージをビルドします。
ビルドが完了するまでには少し時間がかかります。
```bash
docker compose build
```

## MySQLデータベース設定
データベースの設定を行っていきます。
config ディレクトリ内の database.yml というファイルを編集します。
以下のように設定しました。
```ruby
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: password
  host: db

development:
  <<: *default
  database: sample_rails_development

test:
  <<: *default
  database: sample_rails_test

```
`host: db`というのは、docker-compose.yml で指定した MySQL のコンテナ名です。
これでdbコンテナ内のデータベースに接続できるようになります。

以下のコマンドでデータベースを作成します。
```bash
docker compose run web rails db:create
```

## 動作確認
設定が終わったので動作確認を行っていきます。
以下のコマンドでコンテナを起動します。
`-d`をつけるとバックグラウンドで実行できるようになります。
```bash
docker compose up -d
```

コンテナの停止は以下のコマンドで行います。

```bash
docker compose down
```
コンテナが起動してるかを確認するコマンドは`docker ps`です
`db`と`web`の2つのコンテナが起動されていればOKです。
```bash
rails-docker % docker ps
CONTAINER ID   IMAGE              COMMAND                   CREATED        STATUS        PORTS                               NAMES
2c0b838a2977   mysql:8.0          "docker-entrypoint.s…"   24 hours ago   Up 24 hours   0.0.0.0:3306->3306/tcp, 33060/tcp   rails-docker-db-1
50d77f34bf81   rails-docker-web   "entrypoint.sh bash …"   4 days ago     Up 4 days     0.0.0.0:3000->3000/tcp              rails-docker-web-1
```

ブラウザのアドレスバーに[http://localhost:3000/](http://localhost:3000/)を入力して以下の画面が表示されたら無事設定が完了しています！

![スクリーンショット 2024-11-07 15.58.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1374322/acb00d99-a95e-5fe5-11d4-d408f38e24d4.png)


### その他開発時に使うコマンド
```bash
# Railsコンソール起動
docker compose exec web rails console

# マイグレーション実行
docker compose exec web rails db:migrate

# コンテナ内でbashを実行
docker compose exec web bash
```

最後まで読んでいただきありがとうございました！

## 参考
https://musclecoding.com/rails7-mysql8-docker/

https://qiita.com/sam8helloworld/items/e7fffa9afc82aea68a7a

https://www.youtube.com/watch?v=YfaB3PJv1f0