Dockerで使い捨てできるMysqlコンテナを構築

2018年9月2日

 

自分のローカル環境で、複数の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オプションを取ってログを見ながらデバッグしましょう。

 

立ち上がったコンテナを削除したい

 

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