1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Docker】docker-entrypoint-initdb.dに初期化のsqlを置いたけど実行してくれない

Last updated at Posted at 2024-11-24

対象読者

Docker ComposeでMySQLコンテナを立ち上げて、初期データを投入しようとしてるけど、なぜか初期データが全然入らない!と困っている人向け

結論

私の場合は、コンテナのみ削除していて、Dockerボリュームの削除をし忘れていたことが原因でした。。
これを機にちょっとDockerボリュームについて学び直してみようと思い、このブログを書きました!

ボリュームのマウントの方法について

ボリュームのマウントタイプは三つあります。

  • Volumes
  • bind mounts
  • tmpfs mounts

スクリーンショット 2024-11-24 10.14.32.png

参考)適切なマウントタイプを選択する

ボリュームのマウントタイプ①:Volumes

  • データ永続化や管理が簡単
  • コンテナを削除してもデータは残る
  • Docker(Linuxでは/ var / lib / docker / volumes /)によって管理されるホストファイルシステムの一部に保存される
  • 複数のコンテナ間で共有可能
  • ボリュームをマウントする場合、ボリュームは名前付きか匿名で作成することができる

匿名ボリュームは、管理が大変そう。。
匿名ボリュームは、名前が指定されていないボリュームで、Dockerが毎回ランダムな名前を生成します。この特性により、コンテナの終了後にそのボリュームを手動で削除しないと、システムに不要なボリュームが溜まってしまうリスクがあります。
また、匿名ボリュームは特定の名前で管理されないため、他のコンテナと共有したり再利用したりするのが難しく、結果として運用管理が手間になります。

ボリュームのマウントタイプ②:bind mounts

  • ホストの特定のディレクトリをコンテナにマウントする方法で、開発時やデバッグ時に便利

ホストのファイルシステム変更・削除のリスク

  • デフォルトの書き込みアクセス:
    • バインドマウントでは、デフォルトでホスト上のファイルやディレクトリに対してコンテナ内のプロセスが自由に書き込みできます。これにより、意図せずホスト上の重要なファイルが削除されたり、改ざんされたりする危険性があります。
  • ユーザーパーミッションの問題:
    • バインドマウントを使用すると、ホストとコンテナ間で同じユーザー権限が適用されるため、ホスト上のファイルを操作する際に、特定のプロセスが意図しない影響を及ぼす可能性があります。

読み取り専用(Read-Only)モードを活用する
バインドマウントの設定時に「読み取り専用モード(ro)」を指定することで、コンテナからホスト上のファイルの変更を防ぐことができます。

volumes:
  - /host/path:/container/path:ro

ボリュームのマウントタイプ③:tmpfs mounts

  • 一時的なデータを保存するために、メモリ上にボリュームを作成
  • 一時的なデータ保存に最適
  • コンテナの存続期間中、非永続的な状態や機密情報を保存

今回の調査の流れ

docker-compose.yamlで名前付きボリュームdb_volume_commonをマウントし、./db/initdb.d/01_create_database.sql/var/lib/mysqlに必要なシステムデータベース(paku)が作成した

その後、データベース(paku)の中にテーブル(test)を作成したいと思い、./db/initdb.d/02_create_tables.sqlファイルを追加し、コンテナを削除してから再度コンテナを立ち上げたが、テーブルが削除されない

どうしてなんだ?と困る

docker-entrypoint-initdb.dの中に./db/initdb.d/02_create_tables.sqlは格納されていることも一応確認

ログを見ると実行されていないことが分かった

どうして実行されなかったか調査すると、ボリュームの中が初期状態じゃないとinitdbが実行されないことに気がつく

docker compose downを打つときに、オプション-vをつけて実行しボリュームを削除したのち、再度コンテナを立ち上げるとテーブル作成されていた

なるほど!

実際に使用したファイルと修正点

./docker-compose.yaml
version: "3.8"

services:
  # DBコンテナ
  db:
    platform: linux/x86_64
    image: mysql:8.0.34
    container_name: db
    command: --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci
    environment:
      MYSQL_ROOT_PASSWORD: password
    ports:
      - "23306:3306"
    volumes:
      - ./db/initdb.d:/docker-entrypoint-initdb.d
      - ./db/my.cnf:/etc/mysql/conf.d/my.cnf
      - db_volume_common:/var/lib/mysql

volumes:
  db_volume_common: null
./db/initdb.d/01_create_database.sql
CREATE DATABASE IF NOT EXISTS `paku` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
./db/initdb.d/02_create_tables.sql
USE `paku`;

CREATE TABLE `test` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(255) NOT NULL,
  `age` INT(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
./Makefile
setup:
	@make build
	@make up
	@make ps
d:
-	docker compose down
+   docker compose down -v
build:
	docker compose build
up:
	docker compose up -d
ps:
	docker compose ps
db:
	docker compose exec db bash
app:
	docker compose exec app bash

まとめ

  • コンテナ削除だけじゃダメ! ボリュームも消さないと初期化されない。
  • 匿名ボリュームは溜まると管理地獄。名前付きボリュームを使おう。
  • bind mountsの操作ミスには注意! ホスト側のファイルも変えちゃう危険あり。
  • 「なんで初期データが入らないの?」ってなったら、ボリューム削除をしているか確認してみる。
1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?