Docker公式イメージで開発用RDBをゲットだぜ(PostgreSQL編)
に続きMySQL編です。Docker for Macを使用しております。はじめるよ〜。
Dockerの公式MySQLイメージの使い方を徹底的に解説するよ
という素敵なページがありましたのでこちらも参考にさせていただこうと思います。
2016年8月中旬現在、以下のバージョンがあるようです。
5.7(5.7.14), 5.6(5.6.32), 5.5(5.5.51)
少ない気もしますが覚悟を決めて5.5以上で行きましょう。「古いMySQL死すべし」という意思を感じます。
latestは5.7系のようですので、あえて5.5系ですすめてみます。
$ docker run -d --name mysql55 -e MYSQL_ROOT_PASSWORD=mysecretpassword -p 13306:3306 mysql:5.5
公式の例を参考にコンテナの3306を13306にポートフォワードしています。
mysqlコマンドで接続します。公式の例はクライアントコンテナでenvの情報を利用して一気につなぐ方法ですね。
$ docker run -it --link mysql55:mysql --rm mysql:5.5 sh -c 'exec mysql -h"$MYSQL_PORT_3306_TCP_ADDR" -P"$MYSQL_PORT_3306_TCP_PORT" -uroot -p"$MYSQL_ENV_MYSQL_ROOT_PASSWORD"'
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 4
Server version: 5.5.51 MySQL Community Server (GPL)
Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
+--------------------+
3 rows in set (0.00 sec)
mysql> select Host, User from mysql.user;
+------+------+
| Host | User |
+------+------+
| % | root |
+------+------+
1 row in set (0.00 sec)
mysql> exit
Bye
便利だけど長い〜。シェルスクリプトにでもしておくのがよいでしょうか。clientというファイルに書いて実行権限を付けておきます。
$ ./client
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 5
Server version: 5.5.51 MySQL Community Server (GPL)
Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
おけおけ。PostgreSQLの方にも作っておこうかな。
次に Sequel Pro 先生で繋いでみます。13306にポートフォワードしてますので
サクッと繋がりました。
mysqlデータベースの中など覗いてみたり。楽ちん。
コンテナのシェルを起動して探検してみます。
$ docker exec -it mysql55 bash
とりあえずmy.cnfを眺めてみる。
root@688eab40f1a8:/# more /etc/mysql/my.cnf
[mysqld]
skip-host-cache
skip-name-resolve
datadir = /var/lib/mysql
!includedir /etc/mysql/conf.d/
/etc/mysql/conf.d/ のcnfファイルを読み込むようになっていますね。
いろいろな方法が用意されているようです。
まず、先ほど調べたようにコンテナの /etc/mysql/conf.d/ にcnfファイルを置くと読み込まれます。
PostgreSQLの公式イメージと同じくコンテナの /docker-entrypoint-initdb.d に拡張子がsh、sql、sql.gzのファイルを置くとコンテナ起動時に実行してくれます。mysql/5.5/docker-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
このように仕組みも同じ感じでした。
他、PostgreSQLの時と同じように日本語化されたイメージを作ろうと思います。
PostgreSQLでのやり方を参考にdefault localeを設定するDockerfileを作ります。
Dockerfile
FROM mysql:5.5
MAINTAINER murave
RUN apt-get update && apt-get install locales -y && localedef -i ja_JP -c -f UTF-8 -A /usr/share/locale/locale.alias ja_JP.UTF-8
ENV LANG ja_JP.utf8
公式イメージにはlocalesが入っていなかったのでlocaledefの前にapt-getで導入するようにしました。
日本語化されたイメージ、mysql_jp:5.5を作ります。
$ docker build -t mysql_jp:5.5 ./
確認
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql_jp 5.5 42465a1c94d5 22 minutes ago 284.5 MB
/etc/mysql/conf.d/ にバインドするディレクトリconf.dを作成して追加の設定を書いたcnfファイルを置きます。
conf.d/custom.cnf
[mysqld]
character-set-server=utf8
Mac上のcond.dディレクトリを/etc/mysql/conf.dにバインドするようにオプションを付けて起動します。
$ docker run -d --name mysql55 -e MYSQL_ROOT_PASSWORD=mysecretpassword -p 13306:3306 -v $(pwd)/conf.d/:/etc/mysql/conf.d mysql_jp:5.5
execでコンテナ上の/etc/mysql/conf.dのls結果を見てバインドされているか確認。
$ docker exec -it mysql55 ls /etc/mysql/conf.d
custom.cnf
おけおけ。
アカウント、データベース作成は設定用に準備された環境変数(MYSQL_USER、MYSQL_PASSWORD、MYSQL_DATABASE)を利用し、/docker-entrypoint-initdb.d ディレクトリのスクリプト実行を利用してテーブル作成などをしてみたいと思います。
ユーザーをfoo、データベースをfoodbとする前提で初期化用のsqlファイルを作ります。
initdb/01createtable.sql
CREATE TABLE foodb.users (id int , name varchar(255));
GRANT ALL ON foodb.users TO foo;
INSERT INTO foodb.users (id, name) VALUES (1, 'first'), (1, 'second')
foodbデータベースにusersテーブルを作成しユーザーfooに権限を与え、usersテーブルに初期値をINSERT文で投入というシナリオです。
/docker-entrypoint-initdb.d をバインドして起動。
$ docker run -d --name mysql55 -e MYSQL_DATABASE=foodb -e MYSQL_USER=foo -e MYSQL_PASSWORD=foopassword -e MYSQL_ROOT_PASSWORD=mysecretpassword -p 13306:3306 -v $(pwd)/conf.d/:/etc/mysql/conf.d -v $(pwd)/initdb/:/docker-entrypoint-initdb.d mysql_jp:5.5
確認します。
$ ./client
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.5.51 MySQL Community Server (GPL)
Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| foodb |
| mysql |
| performance_schema |
+--------------------+
4 rows in set (0.00 sec)
mysql> select Host, User from mysql.user;
+------+------+
| Host | User |
+------+------+
| % | foo |
| % | root |
+------+------+
2 rows in set (0.00 sec)
mysql> USE foodb;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> SHOW TABLES;
+-----------------+
| Tables_in_foodb |
+-----------------+
| users |
+-----------------+
1 row in set (0.01 sec)
mysql> SELECT * from users;
+------+--------+
| id | name |
+------+--------+
| 1 | first |
| 1 | second |
+------+--------+
2 rows in set (0.00 sec)
mysql> exit
Bye
想定通りに初期化されているようです。
はじめはsqlファイルではなくshファイル(シェルスクリプト)内でmysqlコマンドを呼び出して初期化しようとしていました。実際に使用するユーザーでテーブル作成やデータ投入したいじゃないですか。気分的に。
initdb/01createtable.sh
!/bin/bash
set -e
mysql -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" $MYSQL_DATABASE <<-EOSQL
CREATE TABLE users (id int , name varchar(255));
EOSQL
このようなスクリプトでテーブル作成は行われるのですがshスクリプト実行後にコンテナがExitしてしまうという症状が発生。解決出来ずにハマりまくり、sqlファイルでの初期化に方針変更しました。
その後、落ち着いて公式イメージのページを見なおしていると
No connections until MySQL init completes
という項目があるのに気付きました。mysqlコマンドで接続しているのが原因っぽいですね。
日本語化したイメージを使用しconf.dのcnfファイルで設定調整、initdbのスクリプトで初期化、データの永続化はbusyboxを使用する方針でdocker-compose.ymlを作成します。
docker-composeでmysql & postgreSQL をサクッと起動
を参考にさせていただきました。
docker-compose.yml
datastore:
image: busybox
volumes:
- /var/lib/mysql
container_name: mysql-datastore
mysql:
image: mysql_jp:5.5
environment:
MYSQL_ROOT_PASSWORD: mysecretpassword
MYSQL_USER: foo
MYSQL_PASSWORD: foopassword
MYSQL_DATABASE: foodb
volumes:
- ./conf.d/:/etc/mysql/conf.d
- ./initdb/:/docker-entrypoint-initdb.d
ports:
- "13306:3306"
volumes_from:
- datastore
container_name: mysql-db
起動します。
$ docker-compose up -d
Creating mysql-datastore
Creating mysql-db
以降、使用するあいだはstop・startで停止・起動。
mysqlコマンドでの接続用のclientスクリプトのコンテナ名をmysql-dbに修正して接続して動作を確認。
Sequel Pro を使いポートフォワードした13306にユーザーfooでfoodbデータベースに接続しての操作もできました。
ディレクトリファイル構成は以下のようになりました。
.
├── Dockerfile
├── client
├── conf.d
│ └── custom.cnf
├── docker-compose.yml
└── initdb
└── 01createtable.sql