【Raills】rails6.1.7 × Docker × MySQLの環境構築の際の疑問点を解消

# はじめに
DockerでrailsとMySQLの環境構築を初めてしていく中で「ここなんでこうなるの!？」という箇所が何個かあったり、私がエラーで詰まった場所があったので共有したいと思います。

### バージョン
下記のバージョンで実行環境を構築しました。

* ruby 3.2
* rails 6.1.2
* MySQL 8.0
* Docker 20.10.12

# 必要なファイルを作成
任意のディレクトリを作成し、その直下に
`Dockerfile`
`docker-compose.yml`
`Gemfile`
`Gemfile.lock`
`entrypoint.sh`
を作成します。　　
今回は`my_rails`というディレクトリで進めていきます。

### Dockerfile
```Docker:Dockerfile
FROM ruby:3.2
RUN apt-get update && apt-get install -y \
    build-essential \
    libpq-dev  && \
    curl -fsSL https://deb.nodesource.com/setup_19.x | bash - && \
    apt-get install -y nodejs && \
    npm install --global yarn
WORKDIR /my_rails
COPY Gemfile Gemfile.lock /my_rails/
RUN bundle install
# コンテナー起動時に毎回実行されるスクリプトを追加
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

# イメージ実行時に起動させる主プロセスを設定
CMD ["rails", "s", "-b", "0.0.0.0"]
```
まず前提にですが、rails6から`webpacker`がインストール必須になります。
その`webpacker`をインストールするために`node.js`と`yarn`を使います。
>apt-getでnode.jsとyarnをインストールしてはだめなの？
>>apt-getでインストールしてくる`node.js`や`yarn`は古いバージョンのものなので別の方法でインストールしなくてはいけないです。
今回は`curl`で`node.js`、`npm`で`yarn`をインストールしています。
`npm`は`node.js`をインストールしてからでないと使うことができないので
```npm install --global yarn```は最後に記述する必要があります。　

>entrypoint.shを実行するプロセスは必要なの？
>>これはRailsアプリ特有の問題でサーバー内にserver.pidというファイルが先に存在していたときに、サーバーが再起動できなくなる問題を回避するために置いています。

> MySQLは`Dockerfile`でインストールしなくていいの？
>>`docker-compose.yml`ファイルにmysqlの記述をすることでmysqlのimagesを取得できます

### docker-compose.yml
```ruby:docker-compose.yml
version: '3'
volumes:
  db-data:


services:
  web:
    build: .
    ports:
    - '3000:3000'
    volumes:
    - '.:/my-rails'
    tty: true
    stdin_open: true
    depends_on:
      - db
  db:
    image: mysql:8
    volumes:
    - 'db-data:/var/lib/mysql'
    command: --default-authentication-plugin=mysql_native_password
    environment:
      MYSQL_ROOT_PASSWORD: password
```
imageキーにmysql:8を指定することでmysqlをDockerで使うことができるようになります。
```
command: --default-authentication-plugin=mysql_native_password
    environment:
      MYSQL_ROOT_PASSWORD: password
```
この３行についてはmysql8.0から必要になったみたいです。[参照](https://hub.docker.com/_/mysql/)
__mysqlのコンテナが起動できない場合はここが原因かもしれません。__

### Gemfile
```ruby:Gemfile
source 'https://rubygems.org'
gem 'rails', '~> 6.1.7'
```
railsのバージョンを指定してあげればDockerfileをビルドすることで`bundle install`が実行され、railsがインストールされます。
__Gemfile.lock__ ファイルには特に何も記述しなくて大丈夫です。

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

# Rails に対応したファイル server.pid が存在しているかもしれないので削除する。
rm -f /rails-docker-mysql/tmp/pids/server.pid

# コンテナーのプロセスを実行する。（Dockerfile 内の CMD に設定されているもの。）
exec "$@"
```
rails特有の問題を処理するためのファイルです。[参照](https://matsuand.github.io/docs.docker.jp.onthefly/samples/rails/)

# railsアプリ作成
コンテナに入ってから
```
rails new . --force --database=mysql
```
をすることでrailsのデフォルトのファイルが作成され、mysqlが使えるようになります。
webpackerがインストールされないよというエラーが出た場合はコンテナ内で`rails webpacker:install`を実行してください。

# database.ymlの編集
rails newによって`config`というディレクトリが作られ、その直下に`database.yml`が存在します。
```ruby:database.yml
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  port: 3306
  username: <%= ENV.fetch("MYSQL_USERNAME", "root") %>
  password: <%= ENV.fetch("MYSQL_PASSWORD", "password") %>
  host: db
```
portはmysqlのデフォルトのポート番号が3306なのでそれを指定します。

# コンテナでサーバーを起動
コンテナで
```
rails db:create
```
をしてサーバーを作成してからホストに戻って
```
docker-compose up
```
でDockerfileの`CMD`が実行され、localhost:3000でサーバーが立ち上がります。

# さいごに
まだ学び始めて日が浅いので言葉足らずな説明もあるかもしれませんが、誰かの役に立てれば嬉しいです。

# 参考
[【Rails】Rails 6.0 x Docker x MySQLで環境構築](https://qiita.com/nsy_13/items/9fbc929f173984c30b5d)
[Dockerで、Rails 6系とMySQL8の開発環境の構築（OS : mac)](https://qiita.com/parkon_hhs/items/7a37b4f2a3083be07988)
[DockerのMySQLイメージ起動時に渡す環境変数](https://qiita.com/nanakenashi/items/180941699dc7ba9d0922)
[既存の開発環境をDocker化する手順 Rails6+Webpacker+Postgresql+Sidekiq](https://blog.furu07yu.com/entry/build-docker-rails-webpacker)