Dockerで開発環境に使用するMySQLを用意する

Rails 環境で SQL サーバーを用意する場合、標準だと SQLite になっています。
開発環境として、MySQL を使用することもできますが、システムにインストールするとそのうち DB 名がぶつかる可能性も考えられます。

なので、今回は Docker で MySQL を準備してみます。


参考

実行環境

  • macOS Mojave 10.14.4

そもそも Rails から Mysql への接続の仕方

Rails から、MySQL に接続するには方法が 2 つある。
それぞれで、config/database.yml の書き方が異なる。

TCP(ローカルインストール MySQL)

IP とポートを指定して接続するパターン。
host と port を指定する。

config/database.yml(development抜粋)
1
2
3
4
5
6
7
8
9
10
11
12
default: &defalt
adapter: mysql2
pool: <%= ENV.fetch("RAILS_MAX_THREADS")%>
timeout: 5000
encoding: utf8

development:
database: mysql_developmentDB
username: [任意のID]
password: [任意のパスワード]
host: 127.0.0.1 #ここを指定するlocalhostか127.0.0.1
port: 3306 #ここを指定する

UNIX ドメインソケット(ローカルインストール MySQL)

UNIX ドメインソケットを使用して接続するパターン。
socket を指定する。

config/database.yml(development抜粋)
1
2
3
4
5
6
7
8
9
10
11
default: &defalt
adapter: mysql2
pool: <%= ENV.fetch("RAILS_MAX_THREADS")%>
timeout: 5000
encoding: utf8

development:
database: mysql_developmentDB
username: [任意のID]
password: [任意のパスワード]
socket: /tmp/mysql.sock #ここを指定する

以上で mysql の接続の方法を確認できました。
これを踏まえて、Docker で MySQL を用意します。
作成する Docker コンテナの元イメージはmysql Docker Official Imagesを使用します。


Docker イメージ入手

以下コマンドで docker イメージを入手します。

1
docker pull mysql

Docker で MySQL を用意してみる

今回も、TCP と UNIX ドメインソケットそれぞれを試します。

TCP(Docker 構築 MySQL)

以下コマンドで Docker コンテナ作成と起動をします。

1
2
3
4
5
6
7
8
9
10
11
# コンテナの作成
# -p 3306:3306
# ポートリダイレクトの設定
# ローカルマシンのポート3306をコンテナのポート3306に転送する
#
# -e MYSQL_ROOT_PASSWORD=[任意のパスワード]
# パスワード設定
docker create --name mysql_tcp -p 3306:3306 -e MYSQL_ROOT_PASSWORD=[任意のパスワード] mysql

# コンテナの開始
docker start mysql_tcp

これでコンテナが起動する。

ここで TCP 用の設定を config/database.yml に以下の通り入力する。

config/database.yml(development抜粋)
1
2
3
4
5
6
7
8
9
10
11
12
default: &defalt
adapter: mysql2
pool: <%= ENV.fetch("RAILS_MAX_THREADS")%>
timeout: 5000
encoding: utf8

development:
database: mysql_developmentDB
username: [任意のID]
password: [任意のパスワード]
host: 127.0.0.1 #ここを指定するlocalhostか127.0.0.1
port: 3306 #ここを指定する

以下の通り、入力して rails アプリを起動します。

1
2
3
4
# DB作成
bundle exec rails db:create
# Railsアプリの開始
bundle exec rails s

これでコンテナ上の MySQL に TCP で接続して Rails アプリが起動します。

UNIX ドメインソケット(ローカルインストール MySQL) できなかった

コンテナ上の MySQL が作成している mysql.sock の作成先を調べます。
一旦 TCP 接続のために作ったコンテナを使って確認します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# dockerコンテナの中に入る。
docker exec -it myql_tcp /bin/bash
# ここからコンテナの中
# mysql.sockの位置を調べる。
mysql -u root -p
# =>任意のパスワードを入力
show variables like '%sock%'
+-----------------------------------------+-----------------------------+
| Variable_name | Value |
+-----------------------------------------+-----------------------------+
| mysqlx_socket | /var/run/mysqld/mysqlx.sock |
| performance_schema_max_socket_classes | 10 |
| performance_schema_max_socket_instances | -1 |
| socket | /var/run/mysqld/mysqld.sock |
+-----------------------------------------+-----------------------------+

# mysql終了
quit;

# dockerコンテナから出る
Ctrl+p,Ctrl+q

mysql.sock は、mysql コンテナ上で mysqld.sock という名称だと確認できました。
パスは/var/run/mysqld/mysqld.sock なので、/var/run/mysqld ディレクトリをローカルにマウントさせればよさそうです。

以下のコマンドで、コンテナを作成と起動します。

1
2
3
4
5
6
7
8
9
10
# コンテナの作成
# -v /tmp:/var/run/mysqld
# コンテナ上の/var/run/mysqldをローカルマシンの/tmpに展開する
#
# -e MYSQL_ROOT_PASSWORD=[任意のパスワード]
# パスワード設定
docker create --name mysql_sock -v /tmp:/var/run/mysqld -e MYSQL_ROOT_PASSWORD=[任意のパスワード] mysql

# コンテナの開始
docker start mysql_sock

ここで、/tmp を確認すると、mysqld.sock 他があることを確認できます。
docker stop mysql_sockすると、mysqld.sock 他が消えます。

ここで UNIX ドメインソケット用の設定を config/database.yml に以下の通り入力する。

config/database.yml(development抜粋)
1
2
3
4
5
6
7
8
9
10
11
default: &defalt
adapter: mysql2
pool: <%= ENV.fetch("RAILS_MAX_THREADS")%>
timeout: 5000
encoding: utf8

development:
database: mysql_developmentDB
username: [任意のID]
password: [任意のパスワード]
socket: /tmp/mysqld.sock #mysqld.sockになっていることを確認

以下の通り、入力して rails アプリを起動します。

1
2
3
4
5
# DB作成=>失敗
bundle exec rails db:create

# Railsアプリの開始=>失敗
bundle exec rails s

ここまでやってみましたが、.sock ファイルをローカルにマウントさせる方法はできませんでした。
うーん残念。

どうにも納得できなくて、再度 UNIX ドメインソケットについて調べ直しました。
「単一オペレーションシステム内で~」というのが見落としポイントでした。
確かに MySQL はコンテナ上に立ち上がっているので、確かに単一オペレーションシステム内ではないです。
だから、.sock ファイルをローカル側から見えるようにしてもダメでした。
この点については納得しました。


番外:docker 上の MySQL にローカルから直接接続

TCP 接続用の MySQL コンテナに、ローカルの mysql クライアントで接続できます。
一々コンテナの中に入って mysql クライアントを起動するよりも楽です。

1
2
3
mysql -u root -p -h 127.0.0.1 --protocol=TCP
# mysql -u root -p --protocol=TCP でもOK
=>パスワード入力

今回は Rails 開発環境用に MySQL を Docker で用意してみました。
結果として UNIX ドメインソケットを学ぶきっかけになったのがよかったです。
今後はケースバイケースで、docker で DB の用意します。

ではでは。