メインコンテンツまでスキップ

第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(入口スクリプト)**が走ります🚪 この入口がやってること(超ざっくり)はこう👇

  1. データディレクトリが空かチェック🔎
  2. 空なら:initdb などで 初期DBを作る🏗️
  3. その後:/docker-entrypoint-initdb.dSQL/SHを順番に実行📜
  4. 最後に: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.yml
  • init/01_schema.sql
  • init/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;"

AliceBob が出たら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/docker
  • VOLUME も 18+ では /var/lib/postgresql 側に変更
  • なので マウント先も“新しい場所”を狙うのが推奨(Docker Hub)

この章の compose.yml/var/lib/postgresql をマウントしてるのはそのためです👍 (古い記事をコピペすると「データが残らない」「初期化挙動が変」みたいな事故につながりがち😇)


Composeの entrypoint / command を触るときの注意🚧🧠

Dockerfileには ENTRYPOINTCMD があって、ざっくり👇

  • 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で entrypointcommand を変えたらinitが走らなくなった。ありがちなミスをチェックリスト化して」

⚠️ ただし、.env やパスワードや実データは貼らないでね🔒(そこはガードレール🚧)


まとめ🏁🎉

  • entrypoint初期化は **「データが空のときだけ」**の“儀式”🎬
  • 2回目以降に動かないのは、volumeにDBが残ってるから📦
  • やり直すなら 空のvolumedown -v が最短)💣➡️🧹(Docker Documentation)
  • 2026的には Postgres 18+ の保存先変更に要注意⚠️(Docker Hub)
  • entrypoint を雑に上書きすると 初期化が死ぬので慎重に🚧(Docker Documentation)

チェック問題✅📝(3分でOK)

  1. なぜ初期化スクリプトは2回目以降に動かない?(一言で)
  2. 初期化をもう一回走らせたい。最短コマンドは?
  3. Postgres 18+ で古い記事コピペが危険な理由は?

次の第9章は、いよいよ王道の docker-entrypoint-initdb.d で“種(seed)”を入れるやつ🌱🔥 この章のラボ構成、そのまま拡張していけますよ〜😄