https://hub.docker.com/r/centos/mysql-57-centos7/
このイメージを使うと一つのDB、ユーザーは簡単に作れるけど、複数のDBを作りたいときにどうすればいいかわからなかったので、コンテナを起動したときに何が起きているのかをDockerFileから追ってみました。
まずはDockerFile github.com
※本記事の内容に関係するところだけ抜粋
...
ENV CONTAINER_SCRIPTS_PATH=/usr/share/container-scripts/mysql \
MYSQL_PREFIX=/opt/rh/rh-mysql57/root/usr \
ENABLED_COLLECTIONS=rh-mysql57
...
ENTRYPOINT ["container-entrypoint"]
CMD ["run-mysqld"]
ENTRYPOINTとCMDを併用すると、ENTRYPOINTの引数にCMDが渡るので、ここではこんなコマンドが実行されます。
bash-4.2$ container-entrypoint run-mysqld
container-entrypointの中は以下のようになっています。
#!/bin/bash exec "$@"
とどのつまり、exec run-mysqldが実行されるわけです。
※本記事の内容に関係するところだけ抜粋
#!/bin/bash
...
source ${CONTAINER_SCRIPTS_PATH}/common.sh
...
# pre-init files
process_extending_files ${APP_DATA}/mysql-pre-init/ ${CONTAINER_SCRIPTS_PATH}/pre-init/
if [ ! -d "$MYSQL_DATADIR/mysql" ]; then
initialize_database "$@"
else
start_local_mysql "$@"
fi
# init files
process_extending_files ${APP_DATA}/mysql-init/ ${CONTAINER_SCRIPTS_PATH}/init/
# Restart the MySQL server with public IP bindings
shutdown_local_mysql
...
exec ${MYSQL_PREFIX}/libexec/mysqld --defaults-file=$MYSQL_DEFAULTS_FILE "$@" 2>&1
最初みたときにprocess_extending_filesやinitialize_databaseがどこに定義されているんだ?と思いましたが、${CONTAINER_SCRIPTS_PATH}/common.shに定義されていました。長くなるので割愛しますが、initialize_databaseでその名の通り、環境変数に基づいてDBの初期化(CREATE USER, CREATE DATABASE, GRANT...)をやってました。
気になったのがinitialize_databaseの後に書かれているprocess_extending_filesの部分。追加のDB作成などはここにここで呼び出されるようにすればいいんじゃないかと予想。
process_extending_filesはこうなってます。
# process_extending_files process extending files in $1 and $2 directories
# - source all *.sh files
# (if there are files with same name source only file from $1)
function process_extending_files() {
local custom_dir default_dir
custom_dir=$1
default_dir=$2
while read filename ; do
echo "=> sourcing $filename ..."
# Custom file is prefered
if [ -f $custom_dir/$filename ]; then
source $custom_dir/$filename
else
source $default_dir/$filename
fi
done <<<"$(get_matched_files "$custom_dir" "$default_dir" '*.sh' | sort -u)"
}
つまり、process_extending_files ${APP_DATA}/mysql-init/ ${CONTAINER_SCRIPTS_PATH}/init/は、例えば50-passwd-change.shというファイルを${APP_DATA}/mysql-init/に置けばそれが実行され、なければ${CONTAINER_SCRIPTS_PATH}/init/にある同名のスクリプトが実行されます(ちなみに初期状態で${CONTAINER_SCRIPTS_PATH}/init/には50-passwd-change.shというファイルのみあります)
ということはつまり、${APP_DATA}/mysql-init/にシェルを置けば、DB初期化後に処理を追加できそうです。
なお、APP_DATAは/opt/app-root/srcです。
bash-4.2$ env | grep APP_DATA APP_DATA=/opt/app-root/src
ということで以下のようなDockerFileを作ってみました。
FROM centos/mysql-57-centos7:latest
MAINTAINER doilux
# テストでしか使わないのと、面倒なのでrootのパスワードなどを適当に設定。
# 本番で使う場合はちゃんとしよう。
ENV MYSQL_ROOT_PASSWORD=password \
MYSQL_DATABASE=doilux \
MYSQL_PASSWORD=doilux \
MYSQL_USER=doilux
# sqlディレクトリ配下のスクリプトを/opt/app-root/src/mysql-init配下にコピーする
COPY sql/*sh /opt/app-root/src/mysql-init/
# MySQLの初期化および起動
CMD ["run-mysqld"]
#!/bin/bash mysql -u root --socket=/tmp/mysql.sock << EOF CREATE DATABASE hr; CREATE DATABASE sales; CREATE DATABASE account; CREATE USER 'ceo'@'%' IDENTIFIED BY 'ceo'; GRANT ALL ON hr.* TO 'ceo'@'%' IDENTIFIED BY 'ceo'; GRANT ALL ON sales.* TO 'ceo'@'%' IDENTIFIED BY 'ceo'; GRANT ALL ON account.* TO 'ceo'@'%' IDENTIFIED BY 'ceo'; EOF
#!/bin/bash
mysql -u ceo --socket=/tmp/mysql.sock hr << EOF
CREATE TABLE emp(
id INT(11) PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
dept_id INT(11)
) ENGINE=InnoDB;
INSERT INTO emp(name, dept_id) VALUES('Shown White', '5');
EOF
イメージ作成&コンテナ起動
docker build ./ -t mymysql && docker run -p 3306:3306 mymysql
コンテナに接続してmysqlコマンドを叩くとテーブルを確認できた。
$ mysql -h 127.0.0.1 -P 3306 -u ceo -pceo hr mysql> select * from emp; +----+-------------+---------+ | id | name | dept_id | +----+-------------+---------+ | 1 | Shown White | 5 | +----+-------------+---------+ 1 row in set (0.00 sec)
追伸
わざわざ解読したけど、ちゃんとドキュメントに書いてたorz
mysql-init/ Shell scripts (*.sh) available in this directory are sourced when mysqld daemon is started locally. In this phase, use ${mysql_flags} to connect to the locally running daemon, for example mysql $mysql_flags < dump.sql