コードを書く日々:フリーランスエンジニアの技術メモ

何度も同じことをググってしまう自分の備忘録です。何か調査した際には、そのエッセンスを記事としてまとめ、とりあえず共有することを心がけています。

DockerでMySQL初期化スクリプト docker-entrypoint-initdb.dが走らない時の対処法

Dockerを使ってMySQLのセットアップをしようとして初期化スクリプトdocker-entrypoint-initdb.dにぶち込んだはいいけど なんかスクリプトが実行されない… imageをガッツリ削除して一からやり直すと、うまくいく。なぜ。

なぜ実行されないのか

MySQLのDockerイメージでは、docker-entrypoint-initdb.dディレクトリ内のスクリプトは、データベースが存在していない(つまり初回起動時)にのみ実行されます。

この問題は、データベースファイルをホストマシンと同期(バインドマウント)している場合に起こりやすいです。 同期されたデータベースファイルが存在すると、Dockerはデータベースが既に初期化されていると判断し、初期化スクリプトの実行をスキップします。

解決策は?

名前付きボリュームを使う

名前付きボリュームを使う方法

以下のdocker-compose.ymlサンプルは、名前付きボリュームを使用してMySQLデータベースをセットアップする方法を示しています。この設定では、MySQLの設定ファイル、初期化スクリプト、およびデータベースファイルを名前付きボリュームに保存します。

db:
  container_name: mysql-local
  image: mysql:8
  volumes:
    - ./docker/local/db/my.cnf:/etc/mysql/conf.d/my.cnf
    - mysql-local:/var/lib/mysql
    - ./docker/local/db/initDb.sql:/docker-entrypoint-initdb.d/initDb.sql
  # (中略)
volumes:
  mysql-local:

この構成では、mysql-localという名前のボリュームがMySQLのデータディレクト/var/lib/mysqlマッピングされ、データの永続化を保証します。 加えて、カスタムのMySQL設定ファイルと初期化スクリプトが適切にコンテナに適用されます。

クリーンアップ

docker-compose down --volumeコマンドを使って、必要に応じて作成した名前付きボリュームを綺麗に消し去りましょう。 ただし、この操作はすべてのデータを削除するため、必要なデータが失われないように注意してください。

まとめ

  • MySQLのDockerを使う時にDB初期化したいなら、スクリプトdocker-entrypoint-initdb.dに置きましょう。
  • 名前付きボリュームをdocker-composeで設定して、コンテナの/var/lib/mysqlに紐づけます。
  • docker-entrypoint-initdb.dスクリプトを再実行したい場合は、docker-compose down --volumeを使って名前付きボリュームを削除しましょう。ただし、DBが完全に初期化されるので注意が必要です。
  • 再度upすると、docker-entrypoint-initdb.dスクリプトが実行されます。