第24章:dev/prodで分ける:開発データの扱いを“本番に持ち込まない”🚧
この章はひとことで言うと👇 **「開発で便利な“仮データ・テストユーザー・seed”を、本番に混ぜない仕組みを作る」**です 🙅♂️➡️✅
24.1 まず“事故の絵”を3つだけ描こう🖼️😱
- テストユーザーが本番に存在してしまう👤🧪
- 例:
test@example.com / password123が“ログインできる”状態に… - さらに最悪:権限が admin だった😇
- 開発用の初期化が本番で走る💣
- 「初回だけ走るはず」が、環境の切り替えミスで本番DBを破壊…
- DBイメージによっては初期化の条件が“データディレクトリが空”かどうかなので、構成次第で危ないです。(hub.docker.com)
- 同じデータ箱(volume)を dev/prod で共有🧺🔁
- これ、地味に多いです。
- 「プロジェクト名」「Composeファイル」「起動ディレクトリ」が違うだけで、意図しない共有や取り違えが起きがち…😵
24.2 ゴール:dev/stg/prod の“ルール3枚”を作る📛🧾✅
ここで作る成果物はこれ👇(短くてOK)
- **dev(開発)**🧪:seed OK、テストユーザー OK、リセット OK
- **stg(検証)**🧫:seed 基本NG(必要なら専用seedを別扱い)、リセット慎重
- **prod(本番)**🏭:seed NG、テストユーザー NG、リセット原則NG(やるなら手順・承認・バックアップ必須)
ポイントは「気合」じゃなくて “仕組みで間違えようがない” に寄せることです💪😺
24.3 実装パターンA(おすすめ):Composeファイルを分けて“物理的に混ざらない”ようにする🧱📦
Docker Composeは複数ファイルをマージできて、デフォルトでもベース+上書き(override)を読む設計です。(Docker Documentation) (「上書きファイルを本番では読み込まない」だけで事故率が激減します👍)
フォルダ構成例📁✨
- compose.yaml(共通の最小)
- compose.dev.yaml(開発だけ)
- compose.prod.yaml(本番だけ)
- config/.env.dev(開発の値)
- config/.env.prod(本番の値)
起動コマンド例(Windows PowerShell想定)🪟⌨️
開発🧪
docker compose -f compose.yaml -f compose.dev.yaml --env-file ./config/.env.dev up -d
本番(ローカルで本番相当を立てる時)🏭
docker compose -f compose.yaml -f compose.prod.yaml --env-file ./config/.env.prod up -d
-fで指定した順にマージされます(後勝ち)(Docker Documentation)--env-fileは「どの .env を使うか」を明示できます。複数指定もOKで、後の方が上書きできます。(Docker Documentation)
✅ これだけで「dev用の設定をprodに混ぜる」がかなり防げます👍
24.4 実装パターンB:profilesで“dev専用サービス”を出し入れする🎚️🧪
Composeには profiles があり、指定したプロファイルが有効なときだけ起動するサービスを作れます。
サービス側に profiles を付けるのが基本です。(Docker Documentation)
たとえば「seed専用サービス(1回だけ実行)」を dev プロファイルに隠すイメージ👇
- 通常起動:アプリ+DBだけ
- dev起動:さらに seed サービスも起動(または
runで1回実行)
(profileの有効化は --profile や COMPOSE_PROFILES でできます。(Docker Documentation))
✅ “同じcompose.yamlに書ける”のが利点 ⚠️ ただし「本番で profile を有効化しない運用」が守れないと事故るので、初心者向けには **A(ファイル分割)**が無難です😺
24.5 「seedをdevだけにする」具体策2つ🌱🧯
方法1:DBの初期化ディレクトリ(例:Postgres)を“devのときだけ”マウントする🐘📦
Postgres公式イメージは、/docker-entrypoint-initdb.d に置いたSQL/シェルを初回初期化時に実行できます。(hub.docker.com)
ただしこれは “データディレクトリが空のときだけ” なので、開発では便利、でも本番に混ざると怖い😱(hub.docker.com)
開発用compose(例)🧪
services:
db:
image: postgres:18
volumes:
- db_data_dev:/var/lib/postgresql/data
- ./db/init:/docker-entrypoint-initdb.d:ro
volumes:
db_data_dev:
本番用compose(例)🏭:initをマウントしない
services:
db:
image: postgres:18
volumes:
- db_data_prod:/var/lib/postgresql/data
volumes:
db_data_prod:
✅ これで「本番にseedが入る」は相当防げます👍
方法2:アプリ側seedスクリプトを“ガード付き”で1回だけ実行する🧠⚙️
「seed.ts / seed.js」を用意して、絶対に production では動かないチェックを入れます🛡️ (AIに書かせるのもOKだけど、ガードだけは自分で目視チェック!👀✨)
例:超シンプルなガード案(概念)
NODE_ENV === "production"なら即終了- 実行時に
--confirm-devみたいなフラグがないと止める - さらに “DB名が dev の命名規則じゃないと止める” まで入れると鉄壁🏰
✅ DBイメージ依存が減る ✅ 「必要なときだけ seed」できる ⚠️ ただし“運用で実行する”ので、コマンド間違い対策(ガード)が命🔥
24.6 変数・秘密情報も「dev/prodで混ざらない」ようにする🔑🧊
1) .env を環境別にする🧾🧪🏭
- Composeは
--env-fileで読むファイルを切り替えできます。(Docker Documentation) - サービス側には
env_fileも使えます(複数OK・上書き順あり)。(Docker Documentation)
✅ devは
.env.dev、prodは.env.prodみたいに“ファイル自体を分離”しよう😺
2) パスワード等は secrets を検討する🔒
Composeの secrets は コンテナ内 /run/secrets/<name> にファイルとしてマウントされ、サービスごとに明示許可が必要です。(Docker Documentation)
また Postgres公式イメージは POSTGRES_PASSWORD_FILE のように _FILE 形式で secrets を読み込む流れも案内しています。(hub.docker.com)
✅ 「環境変数がログに出る」「デバッグで表示される」みたいな事故を減らせます。(Docker Documentation)
24.7 “混入ゼロ”チェックリスト(保存版)✅✅✅
本番投入前チェック🏭🔎
- 本番用の起動コマンドが devファイルを参照してない(
-fの指定順も含む)(Docker Documentation) - 本番用composeに seed/init のマウントが無い
- 本番用volume名が dev と別(例:
db_data_prod/db_data_dev) - 本番に “テストユーザー作成処理” が入ってない(コード・SQL両方)
- seedスクリプトがあるなら productionガードがある🛡️
-
.envが環境別に分かれていて、読み込みも明示されている(--env-file)(Docker Documentation) - 秘密情報は可能なら secrets 化(少なくとも “本番
.envをGitに入れない”)🔒
事故りやすい“あるある”⚠️😇
- なんとなくで
compose.override.yamlを本番でも拾ってた(デフォルトで読むので要注意)(Docker Documentation) - 「プロジェクト名違うだけで別環境のつもり」が、実は同じデータ箱を見ていた😵
- seedを「便利だから」と本番にも残した(未来の自分が泣く)😭
24.8 ミニ演習(15〜20分)🏃♂️💨
compose.yamlとcompose.dev.yamlとcompose.prod.yamlを作る📄📄📄- devだけ
db/initをマウントして、テストユーザーが入るのを確認👤✅ - prodで起動して、同じテストユーザーが存在しないのを確認🙅♂️✅
- 最後に
docker compose configで “最終的にどうマージされたか” を確認👀(マージ確認に便利)(Docker Documentation)
AIの使いどころ🤖✨(安全運転)
- GitHub Copilot や OpenAI 系のAIには、 ✅「dev/prodのcompose差分レビュー」 ✅「seedのガード条件の提案」 ✅「チェックリストの穴探し」 をやらせると超強いです💪😺
- ただし 本番の秘密情報や実データは貼らない(ダミーに置き換え)🔒🧊
必要なら、ここで出した compose分割テンプレ(Node+TS+Postgres版) を「第24章用の完成サンプル」として、丸ごと教材用に整えて書き起こしますよ📦✨