【Docker】docker-entrypoint-initdb.dにディレクトリをマウントしない形で初期データを投入する【MySQL】


TL;DR

  • Dockerではディレクトリをマウントするとコンテナ内の情報が上書きされてしまうが、bindでファイルをマウントするなら上書きされない
  • MySQL公式イメージでは、docker-entrypoint-initdb.dに置いた.shファイルはコンテナ起動時に実行される
  • よって、DDLを入れたディレクトリを任意のパスにマウントし、投入用スクリプトをdocker-entrypoint-initdb.dbindでマウントすることで、docker-entrypoint-initdb.dDDLをマウントしない形で初期データを投入できる

本文

やりたかったこと

コンテナ内の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-とすることで、最後に実行されるようにできます。

docker-compose.yml
# 略(※イメージです、動かして試してはいません)
  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の実行に関する記述が有ります