自分のローカル環境で、複数のMySQL使わないといけない時ってありますよね?
仕事ではちょっと古めのバージョンを使ってるけど、プライベートの開発では最新の使いたいなどなど
そんな時はDockerを使って使い捨てのMy SQL環境を構築しましょう。
Dockerを使えば、起動時に必要なデータベース、ユーザーを作成してくれるので一度環境さえ作ってしまえば、使い捨てのデータベースを作成したり、捨てたりを結構カジュアルにできます。
Dockerの公式イメージを取得
Dockerの基本はこちらにまとめているので、Dockerの基本的な操作がわからない方はこちらを参照ください。 DockerでRails + Nginx + Postgresの環境を構築する。その①
また、Dockerのインストールがまだの人はこちらでインストールしましょう。
今回は、My SQL環境の構築にMy SQLの公式イメージを使っていきます。
公式イメージを使うとコンテナ作成時に環境変数を与えてあげるだけで、必要なデータベースとユーザーを作成することができます。
先ずははDockerコマンドで公式イメージを取得してきましょう。
docker pull mysql
このコマンドでmysqlの最新のバージョンを取得することができます。
バージョンを指定して取得したい場合は、
docker pull mysql:5.6
のようにします。
Dockerコンテナの作成
イメージが取得できたら、コンテナを作成していきます。
docker run --name mydb -e MYSQL_ROOT_PASSWORD -p 3309:3306 -d mysql
docker runでコンテナを作成していきます。
引数の説明をすると
--name | コンテナの名前を指定 |
---|---|
-e | コンテナ起動時の環境変数を指定 |
-p | ポートフォワーディングの指定 |
-d | デーモン起動 |
mysql 使用するイメージを指定。5.6を使う場合はmysql:5.6とする。
ポイントはいくつかありますが、繰り返し書いたように-e オプションでコンテナ起動時の環境変数を指定できるので、起動時のROOTユーザーのパスワードを設定しています。
指定できる環境変数はいくつかあって、
MYSQL_USER | 起動時に作成されるユーザー名 |
---|---|
MYSQL_PASSWORD | 起動時に作成されるユーザーのパスワード |
MYSQL_ROOT_PASSWORD | 起動時のrootユーザーのパスワード |
MYSQL_DATABASE | 起動時に作成されるデータベース名 |
のようになります。
また、 dockerでは-pオプションでポートフォワーディングの指定ができ、上のように 3309:3306 とするとホスト上の3309番のポートをコンテナ上の3306番ポートに、流し込んでくれます。
起動したMySQLコンテナに接続する
ここが今回の記事の肝になってきますが、 dockerにあまり慣れていない人は立ち上げたDBコンテナに接続する時のIPアドレスは???どうやって接続するの???となりがちです。
結論から先に書くと、IPアドレスは127.0.0.1です。
これを聞くと、ローカルに既にあるmysqlのホストも127.0.0.1なんだけど。。。
となると思いますが安心してください。 dockerに繋げるときは別のポートで繋ぎましょう。
これを念頭においているので、上のコンテナ作成時は3309番がコンテナの3306番に割り当てられるように指定しています。
この3309番というのはポートが空いてさえいればなんでも良いのですが上で3309:3306として指定しているので、今回MySQLに接続する際はこの3309番を使用します。
mysql -u root -p -h 127.0.0.1 -P 3309
でデータベースに接続できます。
独自のユーザー、データベースが作成されたコンテナを作成
上では、rootユーザーでコンテナを使う形になっていますがそんなのは嫌なのでちゃんと独自のユーザーとDBを使いましょう。
便宜的に独自のデータベース名をmydbとするとコンテナ作成のコマンドは以下になります。
docker run --name mydb \
-e MYSQL_ROOT_PASSWORD=password \
-e MYSQL_USER=mydb \
-e MYSQL_PASSWORD=mydb \
-e MYSQL_DATABASE=mydb \
-p 3309:3306 \
mysql
これで独自のユーザーを持ったコンテナを作成できます。接続する際のコマンドは
mysql -u mydb -p -h 127.0.0.1 -P 3309 mydb
です。
データベース起動時に初期化処理を差し込む
mysqlの公式イメージでは、/docker-entrypoint-initdb.d にスクリプトやSQLを配置するとコンテナ起動時に実行してくれます。
コンテナ作成時にデータベース内のテーブルもいっしょに作成してほしい!ダンプを取り込んで欲しい!という場合はローカルにそれらのファイルを配置しコンテナ作成時にそのディレクトリを/docker-entrypoint-initdb.dにマウントしてあげます。
ホストのディレクトリをコンテナのディレクトリにマウントするには、-vオプションを指定します。 (ホストのディレクトリは絶対パスでの指定が必要です。)
例を書くと、
mkdir init-scripts
touch init-scripts/init.sql
として init.sqlの中身を
create table ~略~
として次のコマンドでコンテナを作成します
docker run --name mydb \
-e MYSQL_ROOT_PASSWORD=password \
-e MYSQL_USER=mydb \
-e MYSQL_PASSWORD=mydb \
-e MYSQL_DATABASE=mydb \
-v $( pwd )/init-scripts:/docker-entrypoint-initdb.d \
-p 3309:3306 \
-d mysql
これでコンテナ起動時に必要なデータベースを流し込みことができます。
ここまでで記事タイトルの目的は達成していますが以下にはトラブルシューティングを書いておきます。
初期化スクリプトがエラーになりコンテナが立ち上がらない時
初期化のスクリプトでエラーになった場合はコンテナが立ち上がらないので、-dオプションを取ってログを見ながらデバッグしましょう。
立ち上がったコンテナを削除したい
```bash docker rm [コンテナ名] で削除できます ```-fオプションをつけるとコンテナが起動している状態でも問答無用で削除できます。
同じ名前のコンテナを2つ起動することはできないので既にあるコンテナが邪魔な場合は消してしまいましょう。
mysqlが文字化けする
mysqlのデータが文字化けする場合は、mysqlの設定が原因なので、起動時にmysqlのオプションで文字コードをutf8に指定してあげましょう。
docker run --name mydb \
-e MYSQL_ROOT_PASSWORD=password \
-e MYSQL_USER=mydb \
-e MYSQL_PASSWORD=mydb \
-e MYSQL_DATABASE=mydb \
-v $( pwd )/init-scripts:inithogehoge \
-p 3309:3306 \
-d mysql --character-set-server=utf8 --collation-server=utf8_unicode_ci
まとめ | 自分が使用しているスクリプトを晒す
こうやって使い捨てのDBが構築できるようになるとカジュアルにデータベース捨てられるので、データも綺麗な状態を保てるし、ローカルも汚さないで複数のデータベース入れられるしでとっても捗りますね。
ちょっと難点として気軽にdb構築できる割にコマンドが長くて煩雑なので僕はスクリプトにして、再利用しています。
今回はそのスクリプトを晒して終わりにしたいと思います。基本は上にまとめたコマンドと同じですが、コンテナの落とし上げを繰り返すと同じコンテナ名が被って起動できないので、既に同じコンテナがある場合は削除するか訪ねてくれるようにしています。
もしつかえそうだったらコピペして使って頂ければ
INIT=$(pwd)"/init/ddl.sql"
CONTAINER_NAME=mydb
if [[ $( docker ps -a | grep "${CONTAINER_NAME}" ) ]]
then
echo ${CONTAINER_NAME}" is already started..."
echo "remove container? (y/n) ------->"
read ANS
if [[ $ANS == [yY] ]]
then
docker rm -f ${CONTAINER_NAME}
else
exit 1
fi
fi
if [[ ! -r ${INIT} ]]
then
echo "not found ${INIT}"
exit 1
fi
docker run \
--name ${CONTAINER_NAME} \
-e MYSQL_DATABASE=${CONTAINER_NAME} \
-e MYSQL_USER=${CONTAINER_NAME} \
-e MYSQL_PASSWORD=${CONTAINER_NAME} \
-e MYSQL_ROOT_PASSWORD=${CONTAINER_NAME} \
-v ${INIT}:/docker-entrypoint-initdb.d \
-p 3309:3306 \
-d mysql:5.6 --character-set-server=utf8 --collation-server=utf8_unicode_ci