事前にデータ投入をした MySQL Docker イメージが必要になり,最初は「Dockerfile で頑張る感じかなぁ...」なんて考えながら調査をしていたら,公式の MySQL Docker イメージに「カスタムスクリプトを実行する機能」が用意されていることを知って,全て解決した.今までも MySQL を Docker で動かす場面はあったけど,今回の機能は知らなくて勉強になった.
CI で使うためにマイグレーション実行済の MySQL Docker イメージを用意しても良いし,新メンバーのために開発用の初期データを投入した MySQL Docker イメージを用意しても良いし,ハンズオンイベントのためにテストデータを投入した MySQL Docker イメージを用意しても良いと思う.今回の仕組みを知っておくと便利な場面は多そう.
公式のDockerfile とdocker-entrypoint.sh を調べつつ,GitHub の Readme を読んでいたら,今回の機能に気付いた.
After the database is created, the entrypoint script will execute any .sh or .sql scripts found in /docker-entrypoint-initdb.d/ If you wish to execute any custom initialization scripts (e.g. for extra database or user creation), map them to this location the first time you start up the image.
最初に動作確認をした結果を載せておこうと思う.今回まずDockerfile と投入データが入ったworld.sql.gz を用意した.データは MySQL から公開されているworld database にした.
.├── Dockerfile└── world.sql.gz
Dockerfile はシンプルで,以下のようになる.今回はサンプルとして MySQL 5.7 をベースにし,事前にworld.sql.gz を投入しておくような設定にした.ファイルをコンテナ内部の/docker-entrypoint-initdb.d にコピーしている点がポイントで,ここに置いておくだけで,自動的に実行してくれる.
FROM mysql:5.7COPY world.sql.gz /docker-entrypoint-initdb.d/world.sql.gz
実際にコンテナイメージをビルドして,コンテナを動かしてみると(オプションなどは必要に応じて),正常にデータが投入されていることを確認できた.便利!
$ docker run-eMYSQL_ALLOW_EMPTY_PASSWORD=yes-it kakakakakku/mysql-57-world-database$ dockerexec-it xxxxxxxxxxxx /bin/shmysql> SHOW DATABASES;+--------------------+| Database |+--------------------+| information_schema || mysql || performance_schema || sys || world |+--------------------+5 rowsinset (0.00 sec)mysql> USE world;mysql> SHOW TABLES;+-----------------+| Tables_in_world |+-----------------+| city || country || countrylanguage |+-----------------+3 rowsinset (0.00 sec)
/docker-entrypoint-initdb.d とは?もう少し/docker-entrypoint-initdb.d の仕組みを調べてみようと思う.まずdocker-entrypoint.sh に以下のような実装があった.
for fin /docker-entrypoint-initdb.d/*;docase"$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";;esacechodone
よって,サポートされている拡張子と動作は以下となる.
.sh : そのまま実行する.sql : mysql コマンドに流し込む.sql.gz : 解凍してから mysql コマンドに流し込むさらにgrant.sql とinit.sh も追加して,全ての拡張子を試してみた.
.├── Dockerfile├── grant.sql├── init.sh└── world.sql.gz
grant.sql では,以下の通り,新規ユーザーを作成して権限を付与している.
GRANTALLPRIVILEGESON world.*TO'kakakakakku'@'localhost'IDENTIFIEDBY'kakakakakku';
init.sh では,単純に MySQL のバージョンを表示している.
#!/bin/shmysql--version
Dockerfile は,以下の通り.
FROM mysql:5.7COPY init.sh /docker-entrypoint-initdb.d/init.shCOPY world.sql.gz /docker-entrypoint-initdb.d/world.sql.gzCOPY grant.sql /docker-entrypoint-initdb.d/grant.sql
この状態でコンテナを起動すると,以下のようにログが出力されていて,正常に実行されていた.
/usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/grant.sql/usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/init.shmysql Ver 14.14 Distrib 5.7.20, for Linux (x86_64) using EditLine wrapper/usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/world.sql.gz
新規ユーザーも作成できていた.
mysql> SELECT Host,UserFROM mysql.user;+-----------+-------------+| Host |User |+-----------+-------------+| % | root || localhost | kakakakakku || localhost | mysql.sys || localhost | root |+-----------+-------------+4rowsinset (0.00 sec)
もし,ファイルの実行順序に依存関係がある場合,今回の仕組みではファイル名の昇順で実行されてしまうため,問題になる場合がある.その場合はDockerfile で数字などの接頭辞を付けて COPY することで,意図した順番で実行できるようになる.マイグレーションなどは,基本的にファイル名にタイムスタンプなどが入っていると思うので,大丈夫なはず.
FROM mysql:5.7COPY init.sh /docker-entrypoint-initdb.d/1_init.shCOPY world.sql.gz /docker-entrypoint-initdb.d/2_world.sql.gzCOPY grant.sql /docker-entrypoint-initdb.d/3_grant.sql
/docker-entrypoint-initdb.d を使う.sql だけではなく.sh や.sql.gz もサポートしている今回,検証として world database を投入した MySQL Docker イメージを作って Docker Hub に公開してみた.MySQL のハンズオンなどに活用できそう.
2016年に作った MySQL ハンズオン資料でも world database を使ったけど,Homebrew で MySQL をインストールして,データを投入するところから始まるので,ここを Docker イメージで置き換えてあげれば,もっと簡単に進行できそう!
ソフトウェア開発全般をご支援できます😀 お仕事ウェブサイトkakakakakku.github.io からお気軽にご相談ください💪
引用をストックしました
引用するにはまずログインしてください
引用をストックできませんでした。再度お試しください
限定公開記事のため引用できません。