【Docker】Rails7 API + MySQL8環境構築

## この記事でやること
* Mac OSでの環境構築
* 環境構築で必要なファイルとコードの提示
* 各ファイルとコマンドの簡単な説明

## この記事でやらないこと
* Mac以外のOSでの環境構築
* Dockerのインストールとセットアップ
* RailsやDockerについての仕様や用語の解説
* コードの細かな解説

細かな解説に関しては随時記事をリンクにて追加しますので、今しばらくお待ちください。

## 開発環境
* M1 MacBook Pro 13-inch (2020)
* macOS Ventura13.2
* Docker Desktop 4.24.2

## 使用バージョン
* Ruby 3.2.2
* Ruby on Rails 7.0.8
* MySQL 8.1.0

## 環境構築
:::note info
以降に出てくる「myapp」はアプリ名です。任意の名前に置き換えてください。
:::
### ファイルの用意
今回は合計で5つのファイルを用意します。myapp（任意のアプリ名）という作業ディレクトリを作成し、以下のように配置します。
```
myapp
 ┣━ docker-compose.yml
 ┣━ Dockerfile
 ┣━ entrypoint.sh
 ┣━ Gemfile
 ┗━ Gemfile.lock
  
```
#### docker-compose.yml
コンテナを定義するための設定ファイルです。

https://docs.docker.jp/compose/compose-file/index.html

```docker-compose.yml
version: '3.8'

services:
  db:
    image: mysql:8.1
    environment:
      MYSQL_USER: user
      MYSQL_ROOT_PASSWORD: password
    ports:
      - "3306:3306"
    volumes:
      - mysql_data:/var/lib/mysql

  api:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
    ports:
      - 3000:3000
    depends_on:
      - db

volumes:
  mysql_data:
```
#### Dockerfile
イメージの作成手順を記述するファイルです。


https://docs.docker.jp/engine/reference/builder.html

```Dockerfile
FROM ruby:3.2.2

RUN apt-get update -qq && apt-get install -y default-mysql-client

RUN mkdir /myapp
WORKDIR /myapp

COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp

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
イメージを作成する際に行いたい処理を記述するファイルです。
Dockerfile内の**ENTRYPOINT**に渡しています。

https://docs.docker.jp/engine/reference/builder.html#entrypoint

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

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

exec "$@"
```

#### Gemfile
インストールしたいgemを記述するファイルです。
``` Gemfile
source 'https://rubygems.org'

gem 'rails', '~> 7.0.8'
```
#### Gemfile.lock
インストールされた全てのgemに関する情報が記されるファイルです。
gemをインストールするたびに自動で書き込まれていくので、中身は空で大丈夫です。

### Railsアプリケーションの作成
ターミナルを開き、作業ディレクトリ`myapp`に移動してください。

以下のコマンドを実行して、イメージの作成からコンテナの起動まで行い、Railsアプリケーションを作成します。
```
docker-compose run api rails new . --api --force --no-deps --database=mysql --skip-bundle
```
Railsアプリケーションの作成が終わると作業ディレクトリは以下のようになっています。

![docker-rails-tutorial_container_rails-new.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3353988/45ccb3a7-e4c4-e36e-9dd3-fc79404e55df.jpeg)

### Gemfileの更新をイメージに反映
Gemfileが更新されているので、以下のコマンドを実行して、イメージを再作成してください。
```
docker-compose build
```
### データベースの設定
データベースの設定は`config/database.yml`に記述されています。
デフォルトの設定ではデータベースにアクセスできないので、[docker-compose.yml](#docker-composeyml)で設定した内容に編集します。

`password:`には`MYSQL_ROOT_PASSWORD`（今回は`password`）を記述、
`host:`にはMySQLサービス名（今回は`db`）を記述してください。

``` database.yml
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  # 以下2行を編集
  password: password
  host: db
```
### データベースの作成
以下のコマンドを実行して、コンテナを起動します。
```
docker-compose up -d
```
コンテナが起動しているかどうかを確認するには、Docker DesktopのContainersを確認するか、ターミナルで`docker-compose ps`を実行してください。

`docker-compose ps`で確認した場合は、以下のように2つのコンテナが確認できればOKです。
```
NAME          IMAGE       COMMAND                                                                                           SERVICE   CREATED         STATUS         PORTS
myapp-api-1   myapp-api   "entrypoint.sh bash -c 'rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0''"   api       3 minutes ago   Up 3 minutes   0.0.0.0:3000->3000/tcp
myapp-db-1    mysql:8.1   "docker-entrypoint.sh mysqld"                                                                     db        9 minutes ago   Up 9 minutes   0.0.0.0:3306->3306/tcp, 33060/tcp
```
問題なくコンテナが起動できていたら、以下のコマンドを実行して、Railsアプリケーションのデータベースを作成します。
```
docker-compose exec api rails db:create
```
### 環境構築完了
ブラウザで`localhost:3000`にアクセスし、Railsのデフォルトページが表示されていれば、環境構築は完了です。

![docker-rails-tutorial_fin.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3353988/368c2ec3-2758-0eab-5c88-0853b70600f1.jpeg)

## 最後に
環境構築は毎回苦労するので、備忘録として記事に残しました。
異なるバージョンでも対応できるよう、Dockerの仕様や各ファイルの解説も他の記事にまとめ、そのリンクを本記事に追加していく予定なので、初学者の方達の参考になれば幸いです。