Dockerでコンテナ化したMySQLを使用してRails環境構築

## はじめに
Railsを使った開発で、Dockerを採用する事はよくある事だと思います。
Rails・DBの両方をDockerでコンテナ化する選択肢もあるようですが、立ち上げや通信がかなり遅くなるため(やり方によってはかなり高速にできるようですが)、今回はDocker Composeを使ってDBのみコンテナ化する環境構築の手順をメモしたいと思います。

## 開発環境
macOS Catalina バージョン10.15.7
ruby: 3.0.0
rails: 6.1.1
docker: 20.10.2

## Dockerをインストール
Docker HubからDockerをインストールします。
https://hub.docker.com/editions/community/docker-ce-desktop-mac/

```
# インストールできたか確認
docker version
```
私の場合、バージョンは20.10.2でした。

## Railsプロジェクトを生成
グローバルを汚さないRails環境構築の方法を別記事にしてますので、よければ参考にして下さい。[
Railsの環境構築(グローバル環境を汚さずに) - Qiita](https://qiita.com/revanira_siitake/items/0dd50671fcf5f5635763)

```
bundle exec rails . new -d mysql
```
こちらの実行。
`-d mysql`で使用するDBをMySQLに指定しています。指定しないとデフォルトでSQLiteが使われます。

## エラーが出ました、、、

```
...
checking for MYSQL_OPTION_MULTI_STATEMENTS_ON in mysql.h... yes
checking for MYSQL_OPTION_MULTI_STATEMENTS_OFF in mysql.h... yes
checking for my_bool in mysql.h... no
-----
Don't know how to set rpath on your system, if MySQL libraries are not in path mysql2 may not load
-----
...
2 warnings generated.
compiling infile.c
compiling mysql2_ext.c
compiling result.c
compiling statement.c
linking shared-object mysql2/mysql2.bundle
ld: library not found for -lssl
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [mysql2.bundle] Error 1
...
An error occurred while installing mysql2 (0.5.3), and Bundler cannot continue.
Make sure that `gem install mysql2 -v '0.5.3' --source 'https://rubygems.org/'` succeeds before bundling.

In Gemfile:
  mysql2
         run  bundle binstubs bundler
Could not find gem 'mysql2 (~> 0.5)' in any of the gem sources listed in your Gemfile.
       rails  webpacker:install
Could not find gem 'mysql2 (~> 0.5)' in any of the gem sources listed in your Gemfile.

```
`bundle install`でmysql2をインストール時にエラってる模様。
rails mysql インストールエラーみたいな感じでググってみると、


```:.bundle/config
BUNDLE_BUILD__MYSQL2: "--with-ldflags=-L/usr/local/opt/openssl/lib --with-cppflags=-I/usr/local/opt/openssl/include"
```
これを`.bundle/config`に記載して、`bundle install`でいけました。
https://nyakanishi.work/bundle-install%E6%99%82%E3%81%ABmysql2%E3%81%A7%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%97%E3%81%9F%E6%99%82%E3%81%AE%E5%AF%BE%E5%BF%9C/

https://stackoverflow.com/questions/30834421/error-when-trying-to-install-app-with-mysql2-gem/39628463#39628463

何をやってるかと言うと、`bundle install`時の環境変数を設定しています。
どうやらAppleはopensslを推奨しておらず、独自のライブラリを優先して使うらしいので、opensslを指定しないとうまく動かないらしい。

ちなみに上のコマンドのかわりに、

```
export LIBRARY_PATH=$LIBRARY_PATH:/usr/local/opt/openssl/lib/
```
こっちでもいけるっぽいです。



## docker-compose.ymlを作成
railsプロジェクトのルートディレクトリで、docker-compose.ymlを作成します。

```yml:docker-compose.yml
version: '3'
services:
  db:
    container_name: sample-db
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: 'password'
      MYSQL_DATABASE: sample
      TZ: "Asia/Tokyo"
    ports:
    - '7306:3306'
    volumes:
    - ./docker/config/my.cnf:/etc/mysql/conf.d/my.cnf
    - ./docker/storage/db:/var/lib/mysql

```

##### version
docker-composeファイルのバージョンを指定。今の最新は３系なので３系を指定。

##### services
コンテナ化する要素をネストして記載する。

##### db
コンテナ要素。名前はdb出なくても何でも良いです。

##### container_name
コンテナの名前を指定してます。指定しないと`docker ps`などで対象コンテナが分かりづらくなるため指定していた方がいいとも思います。

##### image
docker hubに上がっているDockerImageを指定しています。

##### emvironment
環境変数を定義しています。
##### ports
ローカル環境とコンテナ内のポート番号を指定しています。
プロジェクト毎に複数コンテナを立てることを想定しているので、ローカル環境側のポートを適当な数字にしています。プロジェクト毎に`6303:3306`, `6306:3306`などローカル側を違うポートにすることで複数のコンテナでdbサーバを起動できます。

##### volumes
コンテナ内のデータをローカルにマウントして永続化します。`ローカル:コンテナ内`で書きます。こうする事でコンテナが破棄されてもデータは残り再びコンテナを立てればデータを利用できます。`docker-compose up`で自動的に`docker/config/my.cnf`と`docker/storage/db/`が生成されます。`db/`には色々自動生成されるものが入ると思いますが、`my.cnf`は自分で設定を書かなければいけないので、このタイミングで作成しておきます。

```:docker/config/my.cnf
# 必要な設定を記述

[mysqld]                              # mysqlサーバーへの設定
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci
explicit_defaults_for_timestamp = 1

[client]                              # mysqlクライアントツールへの設定
default-character-set=utf8mb4
```

## コンテナ起動
```
docker-compose up
```
別タブでコンテナ内に入ってみましょう。

```
mysql sample -h 127.0.0.1 -u root -P 7306 -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.30 MySQL Community Server (GPL)

Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>
```

`MYSQL_ROOT_PASSWORD`のパスワードでログインできます。
成功したら`exit;`で抜けておきましょう。

## rails側の設定

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

development:
  <<: *default
  database: sample_development
```

```
bundle exec rails db:create
```
createが成功すればOKです。

## 終わりに
dockerでMySQLをコンテナ化している場合、ホストを`localhost`にすると接続できません。
最初`database.yml`に`127.0.0.1`ではなく`localhost`と記載していてかなり詰まりました。