centos7 + mysql5.7のDockerFileを一部解読する
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