第08章:初期化の基本:初回だけ動く“entrypoint初期化”の正体🎬
この章はひとことで言うと… **「なんで初期化スクリプトが“初回だけ”動いて、2回目以降は無視されるの?」**を腹落ちさせる章です😎✨ (ここが分かると、初期化で事故る率がグッと下がります🧯)
この章のゴール🎯✨
- entrypoint初期化が何をしているか、ざっくり説明できる📣
- 「初回だけ動く」理由を **volume(永続データ)**とセットで理解する📦
- 初期化が走らない/止まる時に、最短で復旧できる🛠️
- (おまけ)Composeで
entrypoint/commandを触って事故らない🚧
まず“登場人物”を整理しよう👪🧩
DockerのDB運用で主役はこの3人です👇
- Image(イメージ):設計図🧱(固定)
- Container(コンテナ):動く実体🏃(壊して作り直す前提)
- Volume(ボリューム):データ金庫🔐(消さない限り残る)
ここで超重要なのが👇
✅ 「DBの中身」は基本的に Volume に入る ✅ コンテナを消しても、Volumeが残ってたらDBは残る(=初期化いらない)
Composeの volumes: は“使い回せる永続データ”を作る仕組みです。(Docker Documentation)
“entrypoint初期化”って何?🚪🎬
多くの公式DBイメージ(例:Postgres)は、起動時にまず **ENTRYPOINT(入口スクリプト)**が走ります🚪 この入口がやってること(超ざっくり)はこう👇
- データディレクトリが空かチェック🔎
- 空なら:
initdbなどで 初期DBを作る🏗️ - その後:
/docker-entrypoint-initdb.dの SQL/SHを順番に実行📜 - 最後に:DB本体を起動🚀
Postgres公式イメージは、/docker-entrypoint-initdb.d に置いた *.sql / *.sh を「初期化の最後」に実行してくれます。(Docker Hub)
そして最大のポイント👇
⚠️ 初期化スクリプトは「データディレクトリが空のときだけ」実行される (=2回目以降、既にDBがあるなら“触らない”)(Docker Hub)
初期化のタイミング表🗓️📌(成果物)
これを頭に入れると、9割勝てます😄✨
- ✅ 初回
up(volumeが空):初期化が走る🎬🌱 - ✅ 2回目以降
up(volumeが残ってる):初期化は走らない🙅♂️ - ✅ コンテナ作り直し(でも同じvolume):走らない🙅♂️
- ✅ volumeを消す/新しくする:また初期化が走る🎬🌱
- ⚠️ 初期化スクリプトが途中で失敗→再起動: 途中まで作られたDBが残ると、“続き”が走らず詰むことがある😇(なのでvolumeリセットが必要になりがち)(Docker Hub)
体験ラボ🧪🐘:わざと「初回だけ」を体感する
ここでは Postgres 18 を使います(2026時点の“今ど真ん中”想定)🐘✨ ちなみに Postgres 18 からデータ保存先の扱いが変更されてるので、古い記事コピペは罠になりやすいです⚠️(後で解説)(Docker Hub)
1) フォルダ構成📁
compose.ymlinit/01_schema.sqlinit/02_seed.sql
2) compose.yml(そのままコピペOK)🧩
services:
db:
image: postgres:18
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: pass
POSTGRES_DB: appdb
ports:
- "5432:5432"
volumes:
# ✅ Postgres 18+ はここが超大事(後述)
- pgdata:/var/lib/postgresql
# 初期化スクリプト置き場
- ./init:/docker-entrypoint-initdb.d:ro
volumes:
pgdata:
✅ この状態だと「初回だけ init が走る」構成になります。
docker-entrypoint-initdb.dは ファイル名順に実行されるので、01_02_みたいに番号を振ると安定します。(Docker Hub)
3) init/01_schema.sql 🧱
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
4) init/02_seed.sql 🌱
INSERT INTO users(name) VALUES ('Alice'), ('Bob');
5) 起動してログを見る👀
docker compose up -d
docker compose logs -f db
ログに「initdb」「running /docker-entrypoint-initdb.d/...」みたいな雰囲気の行が出たら成功🎉 (初回だけ出ます!)
6) データ確認✅
docker compose exec db psql -U app -d appdb -c "select * from users;"
Alice と Bob が出たらOK🙌
“2回目以降に動かない”をわざと起こす🪤😇
パターンA:普通に再起動(初期化は走らない)
docker compose down
docker compose up -d
docker compose logs -f db
✅ ここで initスクリプトが走らないのが正常です。 理由はシンプルで、volumeにDBが残ってるからです📦🔐
パターンB:seedを変えても反映されない(初心者あるある)😂
init/02_seed.sql をこう変えてみて👇
INSERT INTO users(name) VALUES ('Charlie');
そして
docker compose up -d
✅ 反映されません🙅♂️ なぜなら、初期化は 初回だけだから。(Docker Hub)
じゃあ、どうやって“初期化をやり直す”の?🔁🛠️
まず結論🎯
「もう一回 init を走らせたい」= 空のvolumeが必要です📦✨
方法1:volumeごと消す(いちばん分かりやすい)💣➡️🧹
docker compose down -v
docker compose up -d
down はデフォルトだと コンテナとネットワーク中心で、volumeは残りがち。
-v/--volumes を付けると Composeで作ったvolumeも削除します。(Docker Documentation)
方法2:volume名を変える(古いDBを残して新規を作る)🧳➡️📦
例えば pgdata2 に変えると「別の金庫」になります🔐
過去のデータを残したまま検証したい時に便利👍
方法3:初期化に頼らず“マイグレーション”で更新する(本命)📜✨
初期化(init)は **“最初の1回だけ”**の儀式🎬 運用でDB構造やデータを更新するのは、基本 migration でやるのが王道です(第12章でガッツリやるやつ💪)
ここが2026の地雷⚠️:Postgres 18+ の保存先が変わった話💥
昔のチュートリアルだと、データをこうマウントしてるのをよく見ます👇
/var/lib/postgresql/data
でも Postgres 18+ は変更が入りました👇
PGDATAが バージョン別になり、18なら/var/lib/postgresql/18/dockerVOLUMEも 18+ では/var/lib/postgresql側に変更- なので マウント先も“新しい場所”を狙うのが推奨(Docker Hub)
この章の compose.yml が /var/lib/postgresql をマウントしてるのはそのためです👍
(古い記事をコピペすると「データが残らない」「初期化挙動が変」みたいな事故につながりがち😇)
Composeの entrypoint / command を触るときの注意🚧🧠
Dockerfileには ENTRYPOINT と CMD があって、ざっくり👇
- ENTRYPOINT:基本の実行ファイル(入口)🚪
- CMD:デフォルト引数/コマンド(上書きしやすい)🧩
この関係はDocker公式のDockerfileリファレンスでも説明されています。(Docker Documentation)
そして Compose は CMD/ENTRYPOINT を上書きできます。(Docker Documentation)
⚠️ ここで事故る典型👇
entrypoint を “postgres本体” に置き換えてしまい、公式entrypointをスキップ
→ その結果、docker-entrypoint-initdb.d が一切走らない😇
✅ 迷ったら:
「公式イメージのentrypointは残す」(= 変えるのは command: から)
が安全です👍
よくあるトラブルQ&A🧯❓
Q1. 「初回なのに init が走らない!」😱
A. だいたいこれ👇
- 以前のvolumeが残ってる(別プロジェクト名でも残る)📦
- もしくは “意図してないvolume/匿名volume” を掴んでる
Composeはプロジェクト名(基本はフォルダ名)で環境を分けます。(Docker Documentation) 「あれ?別フォルダでやってるのに同じvolume掴んでる?」みたいな時は、プロジェクト名とvolume名を疑うのが近道🔎
Q2. 「init スクリプトが途中で落ちた。その後ずっと動かない」😇
A. 公式も注意してます👇
失敗後に再起動しても、既に初期化済み扱いになって“続き”が走らないことがある。(Docker Hub)
→ 直し方はだいたい down -v でリセットが最短💣➡️🧹
Q3. Windowsで .sh が動かない💀
A. まずはこの章みたいに *.sql だけで進めるのが安定👍
.sh を使うなら、**改行コード(CRLF)**や実行権限でコケやすいので注意⚠️(VS Codeの右下でLFにできるよ🧊)
AIの使いどころ🤖✨(安全に爆速)
おすすめの聞き方👇(そのままコピペOK)
- 「Postgres公式イメージで
docker-entrypoint-initdb.dが2回目に動かない理由を、volumeの観点で説明して」 - 「初期化スクリプトが失敗→再起動で走らない。最短復旧手順を3つ出して」
- 「Composeで
entrypointとcommandを変えたらinitが走らなくなった。ありがちなミスをチェックリスト化して」
⚠️ ただし、.env やパスワードや実データは貼らないでね🔒(そこはガードレール🚧)
まとめ🏁🎉
- entrypoint初期化は **「データが空のときだけ」**の“儀式”🎬
- 2回目以降に動かないのは、volumeにDBが残ってるから📦
- やり直すなら 空のvolume(
down -vが最短)💣➡️🧹(Docker Documentation) - 2026的には Postgres 18+ の保存先変更に要注意⚠️(Docker Hub)
entrypointを雑に上書きすると 初期化が死ぬので慎重に🚧(Docker Documentation)
チェック問題✅📝(3分でOK)
- なぜ初期化スクリプトは2回目以降に動かない?(一言で)
- 初期化をもう一回走らせたい。最短コマンドは?
- Postgres 18+ で古い記事コピペが危険な理由は?
次の第9章は、いよいよ王道の docker-entrypoint-initdb.d で“種(seed)”を入れるやつ🌱🔥
この章のラボ構成、そのまま拡張していけますよ〜😄