第10章:「初期化スクリプトが2回目に動かない」罠を体験する🪤
この章は 「えっ、SQL直したのに反映されないんだけど!?」 をわざと踏んで、最短で直せる人になる回です😇✨ (結論:壊れてないです。仕様です。)
1) 先に“結論”だけ言うね📌
postgres 公式イメージの docker-entrypoint-initdb.d は、DBのデータディレクトリが空のときだけ実行されます。
つまり 一度でもDBが初期化されて volume に残ったら、2回目以降は基本動かないです🧠
(Docker Hub)
さらに怖いのがコレ👇 初回の初期化スクリプトが途中で失敗してコンテナが再起動されても、データディレクトリが「空じゃない」判定になると続きが走らないことがあるんです😱(“失敗→再起動→スクリプト続き走らない”) (Docker Hub)
2) まずは罠を“再現”してみよう🧪🔥(5〜10分)
フォルダ構成📁
mydb/
compose.yaml
init/
01_init.sql
compose.yaml(Postgresは最新系の例として 18 をピン📌)
PostgreSQL 18 は 2025-09-25 リリースなので、2026年2月時点でも「最新メジャー」として扱いやすいです✨ (PostgreSQL)
services:
db:
image: postgres:18
environment:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
POSTGRES_DB: app
volumes:
- db-data:/var/lib/postgresql/data
- ./init:/docker-entrypoint-initdb.d:ro
ports:
- "5432:5432"
volumes:
db-data:
db-dataが named volume(永続領域)です📦- Composeの
volumes:は “永続ストア” を定義して再利用できます🧠 (Docker Documentation)
init/01_init.sql(初回だけ流す想定のやつ🌱)
CREATE TABLE IF NOT EXISTS hello (
id SERIAL PRIMARY KEY,
msg TEXT NOT NULL
);
INSERT INTO hello(msg) VALUES ('first boot!');
起動 ▶ 確認👀
PowerShell(VS Code のターミナルでもOK)で👇
docker compose up -d
docker compose exec db psql -U postgres -d app -c "select * from hello;"
たぶんこう出ます👇
first boot! が入ってたらOK🎉
3) ここからが罠🪤:SQLを変えても“反映されない”のを見よう😈
init/01_init.sql をこう変えてみてね👇(メッセージ変更)
CREATE TABLE IF NOT EXISTS hello (
id SERIAL PRIMARY KEY,
msg TEXT NOT NULL
);
INSERT INTO hello(msg) VALUES ('second boot should run?');
で、再起動(または作り直し)してみる👇
docker compose up -d
docker compose exec db psql -U postgres -d app -c "select * from hello;"
✅ 結果:だいたい 増えてない / 変わってない はずです😂 「なんで!?今SQL変えたよ!?」ってなるやつ〜〜〜💥💥
4) なぜ起きる?原因を“見える化”する🔎🧠
4-1) 犯人は volume(永続化)📦
db-data に すでにDBの実体が残ってるから、起動時に
「空じゃない → 初期化はスキップ」
になる、という仕組みです。docker-entrypoint-initdb.d は “初回だけ” の儀式🎬
(Docker Hub)
4-2) 「down したのに残ってる!」も罠😇
普通の docker compose down だと、named volume は消えません(だからデータが残る)
なので “初期化が再実行されない” 状態が続きます🫠
5) 最短の直し方(この章の主役)🛠️✨
パターンA:開発で「最初からやり直したい」💣→🌱(一番よく使う)
volume を消す。これが最短です。
docker compose down -v
docker compose up -d
-v / --volumes は Composeファイルで宣言した named volume と、コンテナに紐づく anonymous volume を削除します。
(Docker Documentation)
⚠️
down -vは「DB消すボタン」なので、間違って本番でやると即死です😇💀 だから開発用にだけ“儀式化”しよう(後述)🙏
パターンB:データを残したまま“変更を反映”したい📜🔁
この場合、やるべきは 初期化じゃなくて migration(履歴で更新) です🧠✨
docker-entrypoint-initdb.d は「初回の箱詰め」専用なので、2回目以降は別のルートが必要。
-
例)
migrations/を作って、増分SQLを順番に適用する- Node/TSなら Prisma/Drizzle/Knex などの migration 機構を使う(ここは後章で伸ばせる👍)
この章では最低限として👇 “反映したいSQLは手動で流す” だけでもOKです(まず体感をつかむ回なので)😊
docker compose exec db psql -U postgres -d app -c "ALTER TABLE hello ADD COLUMN created_at timestamptz default now();"
パターンC:初回スクリプトが失敗したっぽい😱(起動はしてるのに中身おかしい)
さっきの「失敗→再起動→続き走らない」系が疑わしいときは👇
docker compose logs dbを見て、初期化でコケてないか確認👀- コケてたら 直してから volume を消してやり直す (途中まで入った “半端なDB” が残ると余計ハマる) (Docker Hub)
6) 事故を減らす“運用小ワザ”🧯✨(Windows向け)
6-1) DBリセットを「専用コマンド」に固定しよう🎛️
PowerShell スクリプトにして、手で打つ回数を減らすと事故率が下がります👍
scripts\db-reset.ps1(例)
docker compose down -v
docker compose up -d
これで VS Code から .\scripts\db-reset.ps1 って打つだけ💨
6-2) volume 名が分からなくなったら「プロジェクト名」を疑う🧩
Compose は “プロジェクト名” を元に、コンテナ名や volume 名に プレフィックスを付けがちです📛 デフォルトは compose.yaml があるディレクトリ名だったりします。 (Docker Documentation)
「削除したつもりなのに別の volume が残ってた😇」を防ぐには👇
docker volume lsで名前を確認🔎- 必要ならプロジェクト名を固定(
-pやCOMPOSE_PROJECT_NAME) (Docker Documentation)
7) AI(Copilot / Codex)で時短する聞き方🤖⚡
そのまま貼ってOKな“安全な質問テンプレ”👇(秘密は貼らない前提)
-
原因推理:
- 「Postgres の
docker-entrypoint-initdb.dが2回目に動かない。named volume を使っている。原因と最短修正を3つ。」
- 「Postgres の
-
破壊コマンドの安全確認:
- 「
docker compose down -vを実行すると何が消える? named volume / anonymous volume の違いも含めて説明して。」
- 「
-
失敗時ログの読み:
- 「この
docker compose logs dbのエラーから、初期化失敗の可能性と対処を箇条書きで。」
- 「この
8) この章のミニ課題🎯📝(3つやると一気に身につく)
01_init.sqlを変えても反映されないのを再現✅docker compose down -vで直して “初期化が走る” を確認✅- 「データを消さずに反映」ルートとして、
ALTER TABLEを手動で当てて確認✅
9) まとめ🌈✨
docker-entrypoint-initdb.dは 初回だけ(データディレクトリが空のときだけ)🎬 (Docker Hub)- 2回目以降に反映したい変更は、基本 migration / 手動SQL の世界📜
- 開発でリセットしたいときは
docker compose down -vが最短💣 (Docker Documentation)
次に進むなら、第11章(seed設計)や第12章(migration設計)で「2回目以降の更新」を“ちゃんとした運用”にしていくと、めちゃ強くなりますよ💪🔥