Dockerで予め欲しいデータをつっこんだMySQLをこしらえる(Mac用)

MySQLいっぱい生み出して使い分けがしたかったので調べた。
今はまだコンテナが死ぬとデータも死ぬ仕組みなので、主にDaoあたりのユニットテストで一時的なデータ入れるためのDBとして使っておる。

うまくいくまで悩んだりもしたので、やり方だけメモしておく!
ちなみにMac OS X El CapitanVirtualBox使って動かしているよ!!

やってみること

  1. MySQLをDocker上で動かす
  2. hogeデータベースを作る
  3. hoge.usersテーブルを作る
  4. dukeユーザを作り、hogeに実行権限を付与する

インストール

VirtualBox, Docker Machine, Docker Toolboxをインストール

$ brew cask install virtualbox
$ brew install docker-machine
$ brew cask install dockertoolbox

DockerfileとSQLの用意

サンプル

こんな感じ。

#Dockerfile

# FROM コマンドでDocker公式のMySQLイメージを使える(コロン以降がバージョン)
FROM mysql:5.7

# RUN コマンドでDocker側で実行するシェルのコマンドを書ける
# MySQLの設定をこんな感じで追加しておく
RUN { \
    echo '[mysqld]'; \
    echo 'character-set-server = utf8'; \
} > /etc/mysql/conf.d/charset.cnf

# COPY コマンドで自分のマシンからDockerの/docker-entrypoint-initdb.d/下にprepare.sqlをコピーする
# /docker-entrypoint-initdb.d/ 下にあるSQLは全部勝手に実行してくれる!!!
COPY prepare.sql /docker-entrypoint-initdb.d/prepare.sql
--prepare.sql

-- これはいらないかも...
DROP DATABASE IF EXISTS hoge;
DROP DATABASE IF EXISTS fuga;
-- データベースを作る
CREATE DATABASE hoge;

-- dukeユーザをつくってよしなに権限をつける
GRANT ALL PRIVILEGES ON hoge.* TO 'duke'@'localhost';

-- テーブルを作る (実際はちゃんとしたDDLを用意する)
CREATE TABLE `hoge`.`users` ~ ;

要は、実行したいSQL(登録したいデータ)入りファイル/docker-entrypoint-initdb.d/にコピーすればよい!
複数ファイルあっても、コピーした分全部実行される。あと、ダンプファイルとかそのまま使えるのでべんり!

応用編(正しいかは分からないけどこれで解決できた)

  • SQLが複数ファイルにまたがっているが、実行順を制御したいとき(外部キーがあるとか...)
    /docker-entrypoint-initdb.d/にコピー後のファイル名を、lsコマンドで上から実行順に並ぶよう工夫する。
    つまり、a.1番目のファイル.sqlb.2番目のファイル.sql、...みたいにすればその順番に実行できるよ〜。強引。
  • 操作対象のデータベースを変更したいとき(データベース指定のないSQL文を実行するとか...)
    USE hoge とか書いたファイルを作って、意図した通りの順序で実行する。

初回セットアップでやること

testという名前でDockerホストを作成

IPアドレスの指定が不要な場合は、--virtualbox-hostonly-cidr "192.168.99.99/24"の部分は書かなくてもよい。自動で採番されるので大丈夫。
指定したい場合は例みたいにして、CIDR形式で書こう!

$ docker-machine create --driver virtualbox --virtualbox-hostonly-cidr "192.168.99.99/24" test

testホストを起動

restartコマンドやstopコマンドもある。

$ docker-machine start test

環境変数を適用

$ eval "$(docker-machine env test)"

Dockerイメージをビルド

latestはイメージのバージョンに該当する。

$ docker build -t test:latest .

起動の度にやること

testホストを起動

$ docker-machine start test

環境変数を適用

$ eval "$(docker-machine env test)"

起動中のコンテナをすべて停止、削除

関係ないものも停止しちゃうので注意。当然だけどまだ何も起動してないならやらなくてもよい。

$ docker stop $(docker ps -aq)
$ docker rm $(docker ps -aq)

test-mysqlという名前でコンテナを立ち上げ (ポート番号はお好きに変更してね)

次の例だと、ローカルからポート3307のmysqlに繋ごうとすればよい。Dockerがポートフォワードしてくれて3306に繋げ変えてくれるらしい・・・

$ docker run --name test-mysql -p 3307:3306 -v ~/docker/mysql/conf.d:/etc/mysql/conf.d -e MYSQL_USER=duke -e MYSQL_PASSWORD=password -e MYSQL_ROOT_PASSWORD=password -e MYSQL_DATABASE=test -d test:latest

はい出来た!これでOK!!!
prepare.sqlに書いたSQLたちが実行された状態でMySQLが誕生するよ〜。

接続できるか確認してみよう!

$ mysql -h$(docker-machine ip test) -P3307 -uduke -p

ちなみに立ち上げで使うコマンドはシェルスクリプトか何かにしてしまえばもっとラクラクになる。

#!/bin/sh

# ホストを起動する
docker-machine start test

# 環境変数を適用する
eval "$(docker-machine env test)"

# 起動中のコンテナをすべて停止、削除する(関係ないものも停止するので注意)
docker stop $(docker ps -aq)
docker rm $(docker ps -aq)

# コンテナを立ち上げる
docker run --name test-mysql -p 3307:3306 -v ~/docker/mysql/conf.d:/etc/mysql/conf.d -e MYSQL_USER=duke -e MYSQL_PASSWORD=password -e MYSQL_ROOT_PASSWORD=password -e MYSQL_DATABASE=test -d test:latest

その他よく使うコマンド(の一部)

実行中のコンテナを確認

$ docker ps

ログ確認 (立ち上がらない時とかはこれをチェック!)

$ docker logs --follow test-mysql

以上!Docker入門出来て嬉しいな!
強引なやり方を採用しているところは、もっとよい術があれば是非教えて下さい!

参考ページ: