カジュアル開発者こそ Docker で MySQL を触ろう

この記事は [MySQL Casual Advent Calendar 2016](http://qiita.com/advent-calendar/2016/mysql-casual) の25個目の窓です。

# はじめに

MySQL Casual はよく "カジュアル詐欺" とか言われて初心者に優しくないみたいなことをネタ的に言われることがあるわけですが、MySQL Casual における ”カジュアル” というのは ”カジュアルにMySQLに関することを話そう” という意味でのカジュアルです。
なので、その内容が初心者向けであれガチ勢であれ、広く気軽にシェアしようと理解いただければと思います。さあ君も今日からカジュアルだ！

と、言いながらタイムラインを検索してみたら @yoku0825 さんが6回くらい "カジュアル詐欺" とツイートしていて自縄自縛ではないかという気もしてきました。

# MySQL の検証環境どうやって作ってますか

さて、この記事を読まれるみなさんの多くは MySQL を使ってお仕事をされていると思います。
お仕事で MySQL をやっていると避けられないのが新バージョンへの追随です。
yokuさんのようなパッチを当ててビルドしてという環境が必要なガチ勢の方は、カジュアルにVPSやクラウドでビルド環境を作るようです。

しかしながら、みんながそんなガチュアルではないのも事実で、単にstableで検証できればいいのだという向きも多いにあることは想像にかたくありません。
が、普段 brew などでインストールしている環境をいちいち切り替えるというのもカジュアル感がありませんし、インストール/アンインストールという刺身タンポポをやるのも避けたいところです。
2016年に入って、Docker 環境で MySQL を動かす人が増えてきました。実際多くの記事が見つかるようになってきました。
だからと言って野良オレオレ Docker Container をこさえるのはやはりカジュアルではありませんし、誰かが作った野良コンテナでは検証としてはどうかなという向きもあります。

# カジュアルユーザのための Docker コンテナのすすめ

そんな時は [Docker Hub にある公式リポジトリ](https://hub.docker.com/r/_/mysql/) を使うのがカジュアルかつ安心です。
ここには [5.5](https://github.com/docker-library/mysql/blob/ee989d0666458d08dd79c55f7abb62be29a9cb3d/5.5/Dockerfile), [5.6](https://github.com/docker-library/mysql/blob/fd3bdabe513643b62fc379f365b2b5dd10886311/5.6/Dockerfile), [5.7(latest)](https://github.com/docker-library/mysql/blob/c207cc19a272a6bfe1916c964ed8df47f18479e7/5.7/Dockerfile) そして [8.0](https://github.com/docker-library/mysql/blob/4dd33136c4739667a223d39b6f829beb27b235cf/8.0/) のイメージが置かれています。

Docker イメージの取得は

```
docker pull mysql
```

だけで latest がカジュアルに落ちてくるわけですが、検証目的であればバージョンを明示的に指定したくなるでしょう。
そういう時は

```
docker pull mysql:5.7
docker pull mysql:5.6
```

など、タグを明示すれば

```
docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
mysql               5.6                 e1406e1f7c42        10 days ago         327.6 MB
mysql               5.7                 594dc21de8de        10 days ago         400.2 MB
mysql               latest              594dc21de8de        10 days ago         400.2 MB
```

このような形で手元に公式イメージがダウンロードされてきます。

コンテナを動かす時もカジュアルに

```
docker run -d -p 13306:3306 --name mysql57 -e MYSQL_ROOT_PASSWORD=secret mysql:5.7
```

とやるだけでOKです。

# ちゃんと使っていくための設定1 my.cnf

。。。ここで終わったら幾ら何でもカジュアルなめすぎですよね、さすがに my.cnf くらいはカスタムできないと、検証もへったくれもあったもんじゃありません。
なにせ MySQL のデフォルトは

```
mysql> show variables like '%char%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | latin1                     |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | latin1                     |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.02 sec)
```

だったりして、みなさんもこの辺りは真っ先に変えたい設定のひとつだと思います。

というわけで、独自の my.cnf を指定することも当然できます。
このリポジトリにあるコンテナは Debian jessie で作られていて、詳しい手順は Dockerfile に書かれています。
この環境の MySQL は `/etc/mysql/conf.d` にあるファイルを include するので、起動時に任意のファイルをそこに置いてあげれば上書きされます。
ちなみにその内容は Docker Hub の README にちゃんと記述がありますので安心してください。
Docker コンテナの起動時に、所望の .cnf が存在するディレクトリを読ませるには -v オプションで場所を指定すれば良いので

```
docker run -v /path/to/custom:/etc/mysql/conf.d -d -p 13306:3306 --name mysql57 -e MYSQL_ROOT_PASSWORD=secret mysql:5.7
```

という形で path を指定すれば OK です。

```
mysql> show variables like '%char%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | utf8                       |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | utf8                       |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.01 sec)
```

実際やってみればわかりますが、正しく反映されています。

# ちゃんと使っていくための設定2 初期データの投入

おいおい、設定が初期化できただけじゃダメじゃん？データはどうやって入れたらいいんだよ。という声は当然あるわけですが、このコンテナの Dockerfile を見ると

```
COPY docker-entrypoint.sh /usr/local/bin/
RUN ln -s usr/local/bin/docker-entrypoint.sh /entrypoint.sh # backwards compat
ENTRYPOINT ["docker-entrypoint.sh"]
```

という記述があります。
`entrypoint.sh` を見ると

```entrypoint.sh
for f in /docker-entrypoint-initdb.d/*; do
	case "$f" in
		*.sh)     echo "$0: running $f"; . "$f" ;;
		*.sql)    echo "$0: running $f"; "${mysql[@]}" < "$f"; echo ;;
		*.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${mysql[@]}"; echo ;;
		*)        echo "$0: ignoring $f" ;;
	esac
	echo
done
```

という感じの実装になっているので、.sh か .sql か .sql.gz を docker run 時にマウントすれば良いことがわかります。

# ちゃんと使っていくための設定3 開発環境に組み入れていくとしたら

単にクライアントアプリケーションから接続してテストするだけなら、上記のような機能だけ使えば後腐れなく各バージョンの MySQL を切り替えたり切り戻したりして利用できるので、やり過ぎずほどほどにしておくのがカジュアルだと思います。

もうこの際全部 Docker でやりたいという場合、 docker-compose を使って、アプリのコンテナと連携させるのがお手軽かと思います。

```docker-compose.yml
mysql57:
  image: mysql:5.7
  volumes:
    - "/path/to/custom:/etc/mysql/conf.d"
    - "/path/to/init:/docker-entrypoint-initdb.d"
  environment:
    - MYSQL_ROOT_PASSWORD=password
```

という感じで書いておいて他のコンテナとリンクすれば、指定した名前でコンテナにアクセスできます。

```docker-compose.yml
links:
 - mysql57
 - redis
 - rails
```

# 発展的な構成

[Dockerfile](https://github.com/docker-library/mysql/blob/c207cc19a272a6bfe1916c964ed8df47f18479e7/5.7/Dockerfile) を見るとわかるのですが、実際にやっていることは極めてオーソドックスなインストールと起動だけなので、その気になればいくらでもカスタマイズできます。
実際に @yoku0825 さんの作っている [MySQL Fabric のリポジトリ](https://github.com/yoku0825/docker_for_mysqlfabric) のような内容を見ると

また、レプリケーションの構成に関しては [Percona のエントリ](https://www.percona.com/blog/2016/03/30/docker-mysql-replication-101/) が複雑になり過ぎない入門にちょうど良いかと思います。
Percona のエントリだけあって、 `docker pull percona` していますが、基本は MySQL も同様です。

# 最後におしらせ

次回の MySQL Casual は 2017年2月1日 の開催に決定しました。
詳細は追っていろんなところで告知していきますので、皆様お誘い合わせの上ご参加ください。
なおスピーカーの席は空いておりますので、”やってみたい！” というカジュアルな方は [MySQL Casual の Slack](https://mysql-casual-slackin.herokuapp.com/) にて是非表明ください。

それでは、よいお年を。