Rails 7 + MySQLをDockerで環境構築する方法

## はじめに

今回は、Rails 7とMySQLをDockerでの環境構築について、初心者向けに手順を説明します。

## 前提条件:

- Docker がインストールされている
- Docker Compose がインストールされている

## 1. ファイル構成の理解

まずは、以下のファイル構成から始めます。

```
docker_rails_app
├─ backend
│  ├─ Gemfile
│  ├─ Gemfile.lock
│  ├─ entrypoint.sh
│  └─ Dockerfile
└─ docker-compose.yml
```

**なぜこの構成か？**  
一般的に、Railsのアプリケーションは`backend`のようなディレクトリ内に保存されます。その中にはアプリケーションのコードや依存関係を管理するためのファイルが存在します。`docker-compose.yml`はプロジェクトのルートディレクトリに配置するのが一般的です。

## 2. 各ファイルの中身とその目的

- **Gemfile**

Rubyのライブラリ管理のためのファイルです。Railsやその他のgemをインストールするためには、このファイルに記述します。

```ruby
source 'https://rubygems.org'
gem 'rails', '~>7.0.6'
```

**なぜRailsを指定しているのか？**  
今回のプロジェクトはRailsをベースにしているので、Railsのバージョンを指定しています。バージョンを固定することで、未来のバージョンアップによる不具合を防ぐことができます。

- **entrypoint.sh**

このスクリプトは、Railsサーバを起動する前に実行される初期処理を含んでいます。

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

rm -f /app/tmp/pids/server.pid

exec "$@"
```

**なぜ`server.pid`を削除しているのか？**  
前回のRailsサーバの終了が不完全だった場合、`server.pid`というファイルが残ってしまい、それが原因で新しいサーバの起動に失敗することがあります。この問題を防ぐために、サーバ起動前にこのファイルを削除しています。

- **Dockerfile**

`Dockerfile`はDockerイメージの作成手順を記述するファイルです。

```dockerfile
FROM ruby:latest

ARG RUBYGEMS_VERSION=3.4.6

RUN mkdir /app
WORKDIR /app

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

RUN gem update --system ${RUBYGEMS_VERSION} && \
    bundle install

COPY . /app

COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]

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

**Rubyのバージョンや`gem update`は何のために行うのか？**  
最新のRubyイメージを使用しているので、特定のRubyGemsのバージョンを使用したい場合には、明示的に更新する必要があります。ここでの`gem update`はそのためのものです。

**なぜ`ENTRYPOINT`と`CMD`を両方使っているのか？**  
`ENTRYPOINT`はコンテナが実行される際のデフォルトのコマンドを指定し、`CMD`はそのデフォルトのコマンドに渡されるデフォルトの引数を指定します。この設定により、コンテナ起動時には`entrypoint.sh`が実行され、それに続いてRailsサーバが起動されるようになっています。

- **docker-compose.yml**

このファイルは、複数のサービス（今回はRailsとMySQL）を一度に管理・実行するためのものです。

```yaml
version: '3'
services:
  web:
    build: ./backend/ 
    command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - ./backend:/app 
    ports:
      - 3000:3000
    depends_on:
      - db
    tty: true
    stdin_open: true
  db:
    image: mysql:latest
    command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
    volumes:
      - db-volume:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: password
      TZ: "Asia/Tokyo"
    ports:
      - "3306:3306"
  
volumes:
  db-volume:

```

**なぜ`volumes`を使用しているのか？**  
`volumes`を使用することで、ホストOSとコンテナ間でファイルやディレクトリを共有できます。例えば、Railsのソースコードをローカルで編集すると、その変更がすぐにコンテナ内に反映されます。

**MySQLの環境変数について**  
`MYSQL_ROOT_PASSWORD`はMySQLのrootユーザのパスワードを設定します。`TZ`はコンテナのタイムゾーンを設定します。


## 3. Railsアプリケーションの生成とデータベースの設定

新しいRailsアプリケーションを生成するためには、以下のコマンドを実行します：

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

次に、`backend/config/database.yml`を編集して、データベースの設定を更新します：

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

## 4. Docker イメージのビルドと起動

コンテナを起動して、DBを作成します。
docker compose upに-dオプションを付与することで、バックグラウンドでコンテナを実行することができます。
```
$ docker compose up -d
```
最後に、データベースを作成します。

```bash
$ docker-compose exec web rails db:create
```

以上で、Rails 7 + MySQLの環境がDocker上に構築されます！

## まとめ

この記事では、Rails 7とMySQLをDockerを使って環境構築する方法を紹介しました。Dockerを使用するメリットとして、環境差異によるトラブルを最小限に抑えることができ、新しいプロジェクトを迅速に開始できる点が挙げられます。また、各ファイルの役割や設定内容についても詳しく説明しましたので、この情報を元に自身のプロジェクトでの環境構築がスムーズに進むことを期待します。