TL;DR
-
Dockerではディレクトリをマウントするとコンテナ内の情報が上書きされてしまうが、bindでファイルをマウントするなら上書きされない -
MySQL公式イメージでは、docker-entrypoint-initdb.dに置いた.shファイルはコンテナ起動時に実行される - よって、
DDLを入れたディレクトリを任意のパスにマウントし、投入用スクリプトをdocker-entrypoint-initdb.dにbindでマウントすることで、docker-entrypoint-initdb.dにDDLをマウントしない形で初期データを投入できる
本文
やりたかったこと
コンテナ内のdocker-entrypoint-initdb.dを上書きせず、かつディレクトリをマウントするのと同じような使い勝手で、コンテナ起動時に初期化用DDLを実行したかったです。
やり方
冒頭で書いた通り、ファイルをマウントする形であれば、コンテナ内のdocker-entrypoint-initdb.dは上書きされません。
また、MySQL公式イメージでは、docker-entrypoint-initdb.dに置いた.shファイルはコンテナ起動時に実行されます。
よって、任意のディレクトリとしてDDLを入れたディレクトリをマウントし、その投入はdocker-entrypoint-initdb.dにマウントしたシェルスクリプトで行えばできます。
以下は投入スクリプトの例です。
# !/bin/sh
# ---
# MySqlコンテナの/docker-entrypoint-initdb.dにファイルとしてマウントすることで
# そのコンテナの/tmp/init.dにマウントされた差分DDLをMySQLに投入する
#
# /tmp/init.dにファイルが存在しない場合はエラーとなる
# ---
ls -1 /tmp/init.d/*.sql | while read file
do
mysql -uroot -proot < $file
done
一連の実行はファイル名のアルファベット順であるため、マウント時のファイル名を調整すれば、順序の制御も可能です。
例えばマウントするファイル名のプレフィックスをzzz-とすることで、最後に実行されるようにできます。
# 略(※イメージです、動かして試してはいません)
volumes:
- type: bind # 投入シェルのマウント、実行順を最後にするためzzz-というプレフィックスを指定している
source: ./init.sh
target: /docker-entrypoint-initdb.d/zzz-init.sh
- ./init.d:/tmp/init.d/ # DDLを投入スクリプトに合わせ/tmp/init.dにマウント
これが必要になった背景
docker-entrypoint-initdb.dに初期データが入っている形式のイメージを利用する必要が有り、ここにディレクトリをマウントすることができなかったためです。
素直にdocker-entrypoint-initdb.dにファイルを配置する方法でやるならDDLファイルを個別にマウントする必要が有るため、ディレクトリでまとめてマウントする方法を検討してこのやり方に行きつきました。
参考にさせて頂いた内容
-
mysql - Docker Hub
-
Initializing a fresh instanceの章に.shや.sqlの実行に関する記述が有ります
-