Dockerfileが読みたいの
今回は公式のMySQLのDockerfileを読んでみようと頑張りました。この記事は長すぎたので2つに分割しています。こちらの記事はDockerfileに付随しているdocker-entrypoint.sh編です。
今回読んでみたのは以下です。
Dockerfile本体の記事はこちらです。ぜひ参照してください。
Docker公式MySQLのDockerfileを頑張って読んで理解しようとしてみた[Dockerfile本体編]
それではdocker-entrypoint.sh編の始まりです。
エラー時の挙動設定
set -eo pipefail
このシェルスクリプトではパイプ中のエラーでもちゃんと終了するようにpipefailオプションをつけています。ともかくちゃんと落ちろということのようです。
オプションの確認
まずは冒頭の部分
# if command starts with an option, prepend mysqld
if [ "${1:0:1}" = '-' ]; then
set -- mysqld "$@"
fi
コメントでは
# if command starts with an option, prepend mysqld
もしオプションがあったらmysqldを先頭に足します
とあるのでオプション関係の処理のようですね。
拡張的な変数展開
さっそく${0:1:0}
の部分からわからなくてハマりましたが、この${0:1:0}
は「bashの拡張的な変数展開」というものらしく、変数を細かくハンドリングしたい時に有用なのだそうです。
意味としては以下の様になります。
${変数:位置:個数}
${1:0:1}
の場合、$1
(引数の1個目)の最初の文字(0)から1個分(1)という意味になります。
引数がunco
だったらu
を表すことになりますし、--set-server-caracter
だったら-
になります。
if [ "${1:0:1}" = '-' ]; then
-
と比較して真
ならという意味ですから、$1(引数の一個目)の最初の文字(0)から1個分(1)が-
だったらという意味になります。
つまりこのコードでは-
があるかどうかでオプションの有無を確認しているようです。
特殊変数の書き換え
さて、この条件にかなっていたら次は
set -- mysqld "$@"
を行います。
set
はシェルオプションの設定等に使いますが、ここでは変数の内容を変更するために使っています。
--
という不思議なオプションがありますが、これは「これ以降はオプションじゃないよ」という意味になります。これもなかなか情報が見つからず苦労しました。
setはオプションが何もなくて値を与えられると、与えられた値は位置パラメーターに代入されます。つまり$@
や$1
などです。
この処理でmysqld
と$@
の展開が新たに$@
の内容になります。結果的に引数の先頭にmysqldが足された格好になるわけです。なるほど。わかりにくい。
特定のオプションがあった場合
# skip setup if they want an option that stops mysqld
wantHelp=
for arg; do
case "$arg" in
-'?'|--help|--print-defaults|-V|--version)
wantHelp=1
break
;;
esac
done
コメントでは
# skip setup if they want an option that stops mysqld
もしMySQLを止めるオプションがあったらセットアップをスキップします。
とあります。何らかのオプションがある時にはセットアップしない処理のようですね。
しらないarg
for arg;
さて、まずarg
ってどっからでできたんだよ。arg
って引数ってことだよね?でもどこにも定義されていないぞ?
arg
には何がはいるんだ〜!!????
散々調べた結果、驚きの答え…。
通常for文は
for 変数 in 配列
と書きますが、inを省略すると$@
がforの対象になるそうです。
え〜…。ちゃんと書いたほうが読みやすくない?みんなこうやって書くの?
ともかくarg
には引数が全部入るわけですね。
ヘルプなどのオプションがあったら…
もし以下のようなヘルプやバージョン確認などのオプションが与えられていたらwanthelp
に1が代入されるようになっています。 そしてbreak
で抜けてますね。wanthelp
はのちの条件式で使われます。
-'?'|--help|--print-defaults|-V|--version
DockerfileではCMDがmysqldになっているので、本来はなにも引数を与えなくてもMySQLが起動するようになっています。
しかしもしオプションを付けて起動したいなら、CMDが上書きされてしまうので、
mysqld -オプション
という風にmysqldを付けて起動する必要があるのですが、このスクリプトのおかげでオプションだけでもMySQLが起動するようになっているのです。親切なのかこれ?
条件分岐
if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; then
ここは簡単ですね。「引数の1番目が(文字列の)’mysqld’でかつ(-a)$wantHelpが空白の場合(-z)」を表しています。
先ほど処理していた特定のオプションがあった場合はここで弾かれるようになっているのですね。
これ以降がメインの処理になっていきます。
ゲットこんふぃぐ
# Get config
DATADIR="$("$@" --verbose --help 2>/dev/null | awk '$1 == "datadir" { print $2; exit }')"
さて何やら複雑な感じです…。焦らずに解読します。
データディレクトリの取得
DATADIR
に何らかの値を代入しようとしているようですね。
まずこのラインは$()
でくくられているのでコマンド結果展開ですね。
"$@" --verbose --help 2>/dev/null
ここでは引数を展開してなおかつ、--verbose --help
の2つのオプションを付けて実行しパイプで次に送っています。
$@
は通常であればmysqld
ですから
mysqld --verbose --help
が実行されてパイプに渡される訳ですね。$@
にはちゃんとオプションも入りますから安心です。
さて--verbose
を付けてhelpを開くと、 以下の様にMySQLのさまざまな設定値などが出力されます。 (ものすごくたくさんの項目があるので、以下は一部です)
Variables (--variable-name=value)
and boolean options {FALSE|TRUE} Value (after reading options)
------------------------------------------------------------ -------------
abort-slave-event-count 0
allow-suspicious-udfs FALSE
archive ON
auto-increment-increment 1
auto-increment-offset 1
autocommit TRUE
automatic-sp-privileges TRUE
avoid-temporal-upgrade FALSE
back-log 80
basedir /usr
big-tables FALSE
bind-address *
binlog-cache-size 32768
binlog-checksum CRC32
binlog-direct-non-transactional-updates FALSE
binlog-error-action ABORT_SERVER
binlog-format ROW
binlog-group-commit-sync-delay 0
binlog-group-commit-sync-no-delay-count 0
binlog-gtid-simple-recovery TRUE
binlog-max-flush-queue-time 0
binlog-order-commits TRUE
次にawk
でdatadir
でマッチする行の2コラム目を取得しています。
awk '$1 == "datadir" { print $2; exit }'
先ほど出力されたなかには以下のような項目があります。これはコンテナに入ってみて確認してみました。
datadir /var/lib/mysql/
つまりawk
で/var/lib/mysql/
を取得しているのです。このディレクトリはデータベースのデータが格納される場所のはずです。
こうして得られたDATADIR
は以降でも様々に使われます。
$DATADIR/mysqlの存在分岐
if [ ! -d "$DATADIR/mysql" ]; then
ここも簡単ですね。$DATADIR/mysql
がディレクトリじゃないなら(! -d)という分岐です。
データベースがまだ作られていない場合…
つまり 「/var/lib/mysql/mysql
がディレクトリじゃない時〜」ってことになるのだと思います。
公式のMySQLではコンテナが起動されると普通はデータベースを自動的に作られます(はず)。
データベースが作られると/var/lib/mysql/
の直下にmysql
ディレクトリが作られるようになっているはずです。
なのでこのディレクトリを確認することですでにデータベースが作ってあるコンテナなのかどうかの分岐をさせられるようになっているようです。2回め以降はデータベースを作る必要がないですからね。
こういう分岐がないといつも「データベースつくってええええ」という気味の悪いコンテナになっちゃいマス。
設定値の不足処理
if [ -z "$MYSQL_ROOT_PASSWORD" -a -z "$MYSQL_ALLOW_EMPTY_PASSWORD" -a -z "$MYSQL_RANDOM_ROOT_PASSWORD" ]; then
echo >&2 'error: database is uninitialized and password option is not specified '
echo >&2 ' You need to specify one of MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD and MYSQL_RANDOM_ROOT_PASSWORD'
exit 1
fi
ここでは設定値が不足していた場合の分岐を行っています。公式のMySQLコンテナは少くともMYSQL_ROOT_PASSWORD
、MYSQL_ALLOW_EMPTY_PASSWORD
、MYSQL_RANDOM_ROOT_PASSWORD
のどれかを設定しなければいけません。
root
のパスワードがない状態ではこの後に行うデータベースの生成が行えないですからね。
情報が不足していたら…
条件に$MYSQL_ROOT_PASSWORD
、$MYSQL_ALLOW_EMPTY_PASSWORD
、$MYSQL_RANDOM_ROOT_PASSWORD
のすべて(-a)が空白だった場合(-z)に、エラーメッセージを出すようになっていますね。
最後にexit 1
でエラー終了させています。
run
の時に実際に試すとどういう挙動になるかわかりますよ。
ディレクトリの作成・ユーザ割り当て
mkdir -p "$DATADIR"
chown -R mysql:mysql "$DATADIR"
ここも難しくないですね。先ほどのDATADIR
を使ってディレクトリをつくって、所有権をmysqlに与えています。
データベースイニシャライズ
echo 'Initializing database'
"$@" --initialize-insecure
echo 'Database initialized'
--initialize-insecure
を実行すると、rootであればパスワード無しでログインできるとのことです。コンテナ内からのログインはパスワード無しでOKってことかな?
mysqldの起動およびネットワークの無効化・pidの取得
"$@" --skip-networking &
pid="$!"
--skip-networking
でネットワーク越しアクセスを禁止しているようです。コンテナですから外からアクセスされても困りますしね。
"$@" --skip-networking
に&
が付いていますが、これはバックグラウンド実行をさせるためです。
pid="$!"
でプロセスIDを取得していますが、$!
はバックグラウンドで実行された直前のプロセスのプロセスIDを保持しています。
ですから$!
には、先ほどの"$@" --skip-networking
(mysqld –skip-networking) をバックグラウンド実行した際のmysqld
のプロセスIDが入っているはずです。それをpid
に代入しているのです。
pid
は後の処理で使われマス。
クライアントの起動の準備
さて次のこの部分。かなりハマりました。良くわからない。
mysql=( mysql --protocol=socket -uroot )
コマンドの格納
まず右辺の部分ですが、
( mysql --protocol=socket -uroot )
は()
でくくられているのでコマンド実行ですよね。
mysql
ですからクライアント起動をしているのだと思います。
--protocol
はプロトコルの指定でsocket
にしています。そしてroot
でログインするということdayone、これはわかりますが…。
左辺のこれ。
mysql=
だ、代入?しているよ?なにが入るの?
なにが代入されるのか確かめるために以下のようにしてコンテナを起動しました。これであればスクリプトは実行されない状態でコンテナが起動します。
$ docker run -it --name db mysql /bin/bash
まず試しに右辺だけ実行してみました。
# mysql --protocol=socket -uroot
そしたら…
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)
あ?あんだこら?どうやらmysqld.sock
が無いと怒られたようです。
公式MySQLコンテナに出力されるmy.cnf
の抜粋ですが、通信用のソケットの指定がされているのがわかるかと思います。(socket=/var/run/mysqld/mysqld.sock)ここにソケットがないとあかんのです。
[client]
port = 3306
socket = /var/run/mysqld/mysqld.sock
[mysqld_safe]
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
nice = 0
[mysqld]
skip-host-cache
skip-name-resolve
user = mysql
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
mysqld.sock
とはUNIXドメインソケットのことで、プロセス間通信に用いられるファイルディスクリプタです。localhostの場合はこのファイルを介して通信するんですね。
いろいろ調べてみましたが、mysqld
を起動させないとmysqld.sock
は生成されないそうです。なるほど。いやあたりまえか。
どんな出力になるのか
実際先ほどのテスト用コンテナで
mysqld --skip-networking &
を実行すると以下のような出力がありました。(抜粋)
2016-04-16T02:56:41.480641Z 0 [Note] mysqld: ready for connections.
Version: '5.7.10' socket: '/var/run/mysqld/mysqld.sock' port: 0 MySQL Community Server (GPL)
一番下にソケットができた旨の出力がありますよね。
mysqld
がバックグラウンドで起動している状態で(mysqld: ready for connections)ソケットができたので接続可能になったということのようです。
結局なにが代入された?
で前置きが随分長かったですが、
mysql=( mysql --protocol=socket -uroot )
にはなにが代入されたんでしょうか?実際出力させてみると…
mysql
え?これだけ?もっとゴイスーな数値が入ったりしないの?変数にいれる必要あるの?
しかしこれはこの後に出てくる更に難解な変数の序章でした…。
クライアント起動
for i in {30..0}; do
if echo 'SELECT 1' | "${mysql[@]}" &> /dev/null; then
break
fi
echo 'MySQL init process in progress...'
sleep 1
done
if [ "$i" = 0 ]; then
echo >&2 'MySQL init process failed.'
exit 1
fi
さてこの箇所では何をやっているんでしょう?
この部分から察するに何かを30回試行するみたいですね。
for i in {30..0}; do
コマンドのうまい使い方
さて問題はお次の箇所。
if echo 'SELECT 1' | "${mysql[@]}" &> /dev/null; then
break
fi
${mysql[@]}
←ファッ?
なにこれ?変数展開ということはギリ理解できるが[@]
ってなんやねん…難解。
調べた、ググった、全然[@]
の情報がヒットしない…。記号って検索しにくいな…。
というわけで自分でシェルスクリプトを書いて挙動を確かめました。
結論から言うと[@]
は「引数を伴った変数展開」を表すようです。
例えば
list=( ls -a -l )
echo "${list}"
は
ls
が出力されました。オプションは出力されないんですね。一方こちらは
list=( ls -a -l )
echo "${list[@]}"
以下のように出力されます。
ls -a -l
オプションも出力されていますね。
先ほど
mysql=( mysql --protocol=socket -uroot )
の部分で変数mysql
には”mysql”が格納されました。
これは@MINOが勘違いしていたのですが、( )
でくくるのは「サブシェルでのコマンド実行」であり、「実行結果」を表すものではなかったのです。
実行結果は$( )
で表します。試しに以下の様にしてみると…
#/bin/bash
list=$(ls -a -l)
echo "${list}"
以下のように出力されます。「実行結果」ですよね。
合計 1368
drwxr-xr-x 13 mino mino 4096 4月 16 13:06 .
drwxr-xr-x 60 mino mino 4096 4月 16 12:36 ..
drwx------ 25 mino mino 4096 4月 2 15:05 DesignPattern
一方( )
はコマンド自体が代入されるという認識でいいのかな?
ともかく
mysql=( mysql --protocol=socket -uroot )
のmysqlにはmysql --protocol=socket -uroot
が格納され、オプションも出力するときには"${mysql[@]}"という書き方をするということのようです。
いやハマった…。
確認用SQL文
さてハマりついでにもうひとハマり。簡単そうに見えるけど…。
'SELECT 1'
なんだこれ。こんなん必要なの?
結論から言うとこれSQL文なんですよ…。こんなんあるんですね。しらなんだ。
このセレクト文では整数値の1が取得できます。ただそれだけ。でも1が返ってくることでmysqld
につながったことが明確にわかるのです。
データベースも何もない状態ですから、mysqldがまっさらな状態でも返せるSQL文ということなんでしょうね。。
つまり接続確認の意味合いのようですよ。
"${mysql[@]}"
にパイプで'SELECT 1'
を実行して成功したらステータスコード0が返るはずですから、
if echo 'SELECT 1' | "${mysql[@]}" &> /dev/null; then
は真となり、break
するわけですね。シェルスクリプトは0
が真になるので若干ややこしす。
30回試行して失敗したら
if [ "$i" = 0 ]; then
echo >&2 'MySQL init process failed.'
exit 1
fi
$i
が0
になりますからこの部分が真になり、接続できなかった旨を表示して終了します。
時刻の設定
if [ -z "$MYSQL_INITDB_SKIP_TZINFO" ]; then
# sed is for https://bugs.mysql.com/bug.php?id=20545
mysql_tzinfo_to_sql /usr/share/zoneinfo | sed 's/Local time zone must be set--see zic manual page/FCTY/'
fi
$MYSQL_INITDB_SKIP_TZINFO
が空なら(ーz)実行するようになっていますね。
タイムゾーンデータの取得
ysql_tzinfo_to_sqlはmysql
データベースに、タイムゾーンテーブルをロードするプログラムだそうです。
tz database
という世界各地域の標準時データ(別名zoneinfo)があるそうで、LinuxやMacで利用されています。つまりこのデータがあれば全世界の時刻を扱うことができるということですね。
mysql_tzinfo_to_sql
はtz database
をデータベースに取り込むためのプログラムということのようです。
さて、mysql_tzinfo_to_sql
をパイプでsed
につないでいますが、この箇所の処理はどうも不具合に対する処理のようです。
コメントにもあるとおりhttps://bugs.mysql.com/bug.php?id=20545を確認してみてください。英語ですが。
バージョンによってはLocal time zone must be set--see zic manual page
という記述がなにやら悪さをするそうで、それを書き換えているということです。
以下のような部分を
INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, Offset, Is_DST, Abbreviation) VALUES (@time_zone_id, 0, 0, 0, 'Local time zone must be set--see zic manual page');
こんなふうに書き換えているわけですね。
INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, Offset, Is_DST, Abbreviation) VALUES (@time_zone_id, 0, 0, 0, 'FCTY');
正直なにがダメなのかよくわからないです…ごめんなさい。
ランダムパスワードの生成
if [ ! -z "$MYSQL_RANDOM_ROOT_PASSWORD" ]; then
MYSQL_ROOT_PASSWORD="$(pwgen -1 32)"
echo "GENERATED ROOT PASSWORD: $MYSQL_ROOT_PASSWORD"
fi
ここはすんなりわかりました。docker run時に-e MYSQL_RANDOM_ROOT_PASSWORD
を指定している場合、ランダムでパスワードをつくってくれます。その処理がここで行われています。
ここでは32文字のパスワードを生成しています。ちなみにこんな感じのパスワードになります。
$ pwgen -1 32
shuw5Ohmae6cuow5ohsei2Dahfahvai7
データベースの準備
"${mysql[@]}" <<-EOSQL
-- What's done in this file shouldn't be replicated
-- or products like mysql-fabric won't work
SET @@SESSION.SQL_LOG_BIN=0;
DELETE FROM mysql.user ;
CREATE USER 'root'@'%' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}' ;
GRANT ALL ON *.* TO 'root'@'%' WITH GRANT OPTION ;
DROP DATABASE IF EXISTS test ;
FLUSH PRIVILEGES ;
EOSQL
さてこの部分ではいくつかのSQLをクライアントを通して実行しています。
バイナリログの無効化
まずはこの部分。
SET @@SESSION.SQL_LOG_BIN=0;
SESSION.SQL_LOG_BINはバイナリログにログを残すかどうかの設定です。バイナリログというのは、テーブルやデータへの操作、変更などがイベントとして残るそうです。
いくつかのデータリカバリ処理にはこのバイナリログが必要になる場合があるそうです。
この場合バイナリログを取らない設定にしているということですね。
いろいろ調べたところ、どうやらレプリケーションをもちいるときにこのバイナリログが悪さをする可能性があるみたいです。
レプリケーションとは負荷分散などの目的の為にデータを複数複製する機能です。マスターデータがあってスレーブをたくさん持てるので、スレーブにアクセスしてもらうことで一極集中せずに済みます。
例えばマスターでユーザを増やした場合などにバイナリログが有効になっていると、スレーブで必要ないマスターのユーザ情報が伝わってしまい、なにやら不吉なこと(スレーブが止まるとか)が起きるらしいです。
おそらくこれ以降でユーザ操作をおこなっているので必要な設定なのではないかと思います。
rootユーザの作成
DELETE FROM mysql.user ;
CREATE USER 'root'@'%' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}' ;
GRANT ALL ON *.* TO 'root'@'%' WITH GRANT OPTION ;
DROP DATABASE IF EXISTS test ;
FLUSH PRIVILEGES ;
ここはそれほど難しくないですね。一旦ユーザを全消ししてroot
ユーザを作っています。root
ユーザのパスワードにはMYSQL_ROOT_PASSWORD
が当てられていますね。
あとはGRANT
でroot
にすべての権限を与え、テストデータベースを削除して、権限を更新しています。
rootパスワードの追加
if [ ! -z "$MYSQL_ROOT_PASSWORD" ]; then
mysql+=( -p"${MYSQL_ROOT_PASSWORD}" )
fi
ここでは変数mysql
にrootパスワードを追加しています。先ほどrootを作っていますから、これでパスワードをつかってログインできるようになります。
データベースの作成
if [ "$MYSQL_DATABASE" ]; then
echo "CREATE DATABASE IF NOT EXISTS \`$MYSQL_DATABASE\` ;" | "${mysql[@]}"
mysql+=( "$MYSQL_DATABASE" )
fi
ここでデータベースを作成しています。docker run
時に指定した-e MYSQL_DATABASE
がデータベース名になります。
CREATE DATABASE IF NOT EXISTS
は「もしこの名前のデータベースがなかったら作る」という意味です。このSQLを${mysql[@]}
にパイプで渡して実行、その後に変数mysql
にデータベース名を足しています。
いままでの処理で変数mysqlは以下のようになっているはずです。順次作られたデータベースにログインする為のコマンドに仕上げられていますね。
mysql --protocol=socket -uroot -p password dbname
ユーザを作った際の処理
if [ "$MYSQL_USER" -a "$MYSQL_PASSWORD" ]; then
echo "CREATE USER '$MYSQL_USER'@'%' IDENTIFIED BY '$MYSQL_PASSWORD' ;" | "${mysql[@]}"
if [ "$MYSQL_DATABASE" ]; then
echo "GRANT ALL ON \`$MYSQL_DATABASE\`.* TO '$MYSQL_USER'@'%' ;" | "${mysql[@]}"
fi
echo 'FLUSH PRIVILEGES ;' | "${mysql[@]}"
fi
公式のMySQLではroot
以外にユーザを作ることも可能です。docker run
時に-e MYSQL_USER
と-e MYSQL_PASSWORD
を指定しているとroot
ではなくこのユーザでログインすることもできるようになります。
作ったデータベースで全権をユーザに与える処理がされていますね。
データベースの独自初期化用処理
echo
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
ちょっと複雑そうにみえますが、ここでは自作のshやsqlファイルでデータベースを初期化できるようにしてあります。
/docker-entrypoint-initdb.d/
にsh
、sql
、sql.gz
に該当するファイルがあるとそれらを実行してくれる様になっています。
ここでも"${mysql[@]}"
が大活躍です。便利だなこいつ。
たとえば何らかのデータを起動時に入れてしまいたい場合はsql等でぶっこむことが可能になっています。
具体的にはdocker-entrypoint-initdb.d
をデータボリューム等でバインドしてファイルを突っ込む方法を取るかと思います。
起動と同時に叩き込む!!!!
ワンタイムパスワードが有効な場合
if [ ! -z "$MYSQL_ONETIME_PASSWORD" ]; then
"${mysql[@]}" <<-EOSQL
ALTER USER 'root'@'%' PASSWORD EXPIRE;
EOSQL
fi
ここではdocker run時にMYSQL_ONETIME_PASSWORD
を有効にしていた場合の処理です。
PASSWORD EXPIRE
はパスワードに期限を付けます。次回ログインには別なパスワードを設定する必要があります。
プロセスの終了
if ! kill -s TERM "$pid" || ! wait "$pid"; then
echo >&2 'MySQL init process failed.'
exit 1
fi
echo
echo 'MySQL init process done. Ready for start up.'
echo
おぼえていますでしょうか?以下の部分でmysqldのプロセスID取得していましたよね。
"$@" --skip-networking &
pid="$!"
変数pid
をつかってmysqldを終了しようとしています。
if ! kill -s TERM "$pid" || ! wait "$pid"; then
kill -s TERM "$pid"
のTERMシグナルはプロセスを正常終了させる為のシグナルです。条件には!
が付いているので、「正常終了できなかった時」という意味デス。
さらに! wait "$pid"
のwait
はプロセスが終了するのを待つコマンドです。これも!
が付いているので、「正常に待てなかった時」という意味になるかと思います。
つまり正常終了できないか、プロセスを終了させられない場合には失敗したと判断してエラーをだしてセットアップを終了するようにしています。
ちゃんと終了させられた場合は
echo
echo 'MySQL init process done. Ready for start up.'
echo
を出力してセットアップが正常に終わったことを表示します。
分岐の最後
chown -R mysql:mysql "$DATADIR"
fi
exec "$@"
さて今までは初回起動時にデータベースを作る為の処理でした。
2回目以降の起動はデータベースがすでに作られているはずなので、セットアップ処理はされません。
最後にexec "$@"
がありますが、これは初回起動でも2回目の起動でも、mysqldを起動させるコマンドです。
DockerfileのCMDが引数になりますので、”mysqld”が実行されるわけですね。
こうしてMySQLコンテナは起動するわけです。
まとめ
読んで理解するのは大変ですね。コードを書くより人のコードを読む方が難しく感じます。ともかく時間はかかりましたが、ある程度理解できてよかったです。
はたしてこんな記事が役に立つかどうかはわかりませんが、暇つぶしにはなるかもしれません。
Dokcerfileを読んだことで…
- シェルスクリプトは読むのが難しい
- コマンドを変数に格納して実行する方法が勉強になった
- いろんな作法をしることができた
- Dockerfileに恐怖感を感じにくくなった