第20章:configs / env / files の整理術:どれに何を置く?🧰🧩
この章は「設定と秘密とただの値」をごちゃ混ぜにしないで、チームでも未来の自分でも迷わない“置き場所ルール”を作る回だよ〜😄✨ (ここが固まると、セキュリティも運用も一気にラクになる!)
0. まず結論:迷ったらこの3箱📦📦📦
設定っぽいものは、最終的にこの3種類に分類できるよ👇
- env(環境変数):
- 「文字列のスイッチ」向き(例:
NODE_ENV=production、LOG_LEVEL=debug) - 12-factorっぽい運用に寄せたい時に強い💪
- configs(設定ファイルとして配る“非秘密”):
- 「ファイルとして渡したい設定」向き(例:
app-config.json、nginx.conf) - Composeでは ファイルとしてコンテナにマウントされる(デフォルトの置き場所あり)📄
- コンテナ内のデフォルトマウント先は Linux なら
/<config-name>(Windows コンテナならC:\<config-name>)だよ。(Docker Documentation)
- files(普通のファイル):
- 画像・テンプレ・SQL・初期データ・ローカル専用設定など
- bind mount で共有することも多い(ただし共有範囲は最小で!)🧷
そして「秘密(secret)」は この章では“別枠”扱いにするのが正解✅ (次のSecrets章で本格的にやるやつ)
1. ありがちな事故:全部envに押し込んで爆発💥
envって便利だから、こうなりがち👇
.envに DBパスワードも APIキーも 設定JSONも詰め込む- どれが「公開OK」で、どれが「漏れたら即死」かわからなくなる😇
- ログやエラーに env が混ざって漏れる、AI拡張に貼って漏れる…🫣
だから、この章は**“分ける”が主役**だよ🧠✨
2. envを正しく理解しよう(ここが超重要)🧪
2-1. .env は「Composeのための変数」になりがち🤹♂️
Composeは、Composeファイル内の ${VAR} を埋める(変数補間)ために、複数ソースから変数を読み込むよ。優先順位もある。(Docker Documentation)
つまり .env を置くと「Composeが読む」用途でまず効いてくる。
2-2. コンテナに入るenvは別(environment と env_file)📦
コンテナへ渡すenvは、主にこの2つ👇
environment:… Composeファイルに直書き(or 変数補間で差し込み)env_file:… ファイルからまとめて読み込んでコンテナへ
しかも **どれが勝つか(優先順位)**が明文化されてる!
ざっくり言うと「CLIで渡した -e が最強」で、その次に色々続くよ。(Docker Documentation)
✅ ここだけ覚えればOK 「最後に上書きしたいものほど“強い場所”に置く」(CLI > environment > env_file)
3. configsって何がうれしいの?📄✨
Composeの configs は、サービスの挙動を変える設定をイメージ再ビルドなしで差し替えたい時に便利。
しかも「ファイルとして」コンテナに入る。(Docker Documentation)
使いどころの目安🎯
- ✅ JSON/YAML/TOML みたいな設定ファイル
- ✅ nginx や caddy の conf
- ✅ 「環境変数にすると読みにくい」設定の塊
- ✅ “サービスごとに違う設定ファイル”を渡したい
逆に env が向くのは👇
- ✅ ON/OFF、URL、ポート、ログレベルみたいな「短い文字列」
4. “置き場所ルール”テンプレ(そのまま採用OK)📌
チームで揉めない、定番の分け方を置いとくね😄
4-1. リポジトリ構成(例)📁
compose.yaml.env… 公開OKなデフォルト値(例:ポート、機能フラグ).env.local… 個人PCだけの値(Git管理しない)configs/… 非秘密の設定ファイル置き場secrets/… 秘密ファイル置き場(Git管理しない)src/… アプリ本体scripts/… 運用補助(初期化など)
4-2. 仕分けの判定フロー(秒速で決まる)⚡
-
漏れたらヤバい?(パスワード/鍵/トークン) → **secret(ファイル)**へ(envに置かない)🔑
-
漏れても致命傷じゃないが、ファイル形式の方が読みやすい? → configs(ファイルで渡す)📄
-
それ以外の「短い値」 → env(ただしログに出ない設計に)🧪
5. 実践:Composeで “env + configs + files” を同居させる🛠️
ここからは、よくあるNode/TS構成を例に「こう書けば迷わない」を作るよ😄 (コードは雰囲気でOK!)
5-1. compose.yaml 例(configs + env_file + bind mount)🧩
services:
api:
build: .
ports:
- "${APP_PORT:-3000}:3000"
# ✅ 短い値は env へ
environment:
NODE_ENV: "development"
LOG_LEVEL: "${LOG_LEVEL:-info}"
# ✅ まとまった“非秘密の値”は env_file でもOK(ただし秘密は入れない)
env_file:
- ./.env
# ✅ 非秘密の設定ファイルは configs へ(ファイルとして入る)
configs:
- source: app_config
target: /app/config/app-config.json
# ✅ 開発中だけ、ソースを bind mount(共有範囲は最小!)
volumes:
- ./src:/app/src:ro
configs:
app_config:
file: ./configs/app-config.dev.json
ポイント👇
configsは「ファイルとして入れる」。デフォルトのマウント先もあるけど、targetで揃えると読みやすいよ。(Docker Documentation)- envの優先順位があるので「どこで上書きするか」は最初に決めちゃうのが楽!(Docker Documentation)
- Composeファイルの仕様は基本「Compose Specification」を見ればOK(これが今の推奨路線)。(Docker Documentation)
6. Node/TypeScript側の読み方(“漏れない”読み方)🧠🔒
6-1. まず原則:ログに出すな🫣
process.envを丸ごと出力しない- エラー時に設定オブジェクトを丸ごと投げない
- 「接続文字列」や「ヘッダ」も危険(トークン混ざりがち)⚠️
6-2. “設定の入口”を1か所にする(超大事)🚪
- env と config file をアプリのあちこちで読まない
config.tsみたいな 1ファイルに集約する
例(雰囲気)👇
import fs from "node:fs";
type AppConfig = {
featureX: boolean;
allowOrigins: string[];
};
function readJson(path: string): AppConfig {
return JSON.parse(fs.readFileSync(path, "utf-8"));
}
const configPath = process.env.APP_CONFIG_PATH ?? "/app/config/app-config.json";
export const appConfig = readJson(configPath);
export const env = {
nodeEnv: process.env.NODE_ENV ?? "development",
logLevel: process.env.LOG_LEVEL ?? "info",
};
✅ これで「envは短い値」「configsは読みやすい塊」って役割分担がキレイになる✨
7. “秘密”をenvに入れない理由(この章でも触れる)🔑💥
「秘密はファイルで渡す」が安全寄り。理由は単純で👇
- envはログやクラッシュレポートに混ざりやすい
- ツールやAI拡張に“見えやすい”
- うっかり
printenvで全部出る😇
Composeの secrets は、コンテナ内で /run/secrets/<name> にファイルとしてマウントされるよ。(Docker Documentation)
(この詳細は次章でがっつり!)
8. AI拡張時代の“置き場所ルール”追加🚧🤖
AI拡張は便利だけど、「見せていい範囲」を先に決めないと危ないやつ😵 特に 間接プロンプトインジェクション(リポジトリ内の文章やコメントに仕込まれた指示でAIが暴走)みたいな話が現実にある。(The GitHub Blog) Microsoftも間接インジェクション対策の考え方を整理してるよ。(Microsoft Developer)
この章の結論としての対策(超現実的)✅
- 秘密はワークスペース直下に置かない(AIが拾いやすい)🫥
secrets/は.gitignore+ “AIに読ませない場所”に寄せる- AIに貼るのは
.env.exampleまで(本物は貼らない)🙅♂️ - 生成されたコマンド・設定変更は 必ず人間がレビュー(自動実行しない)👀
- 「設定ファイル(configs)」は攻撃の混入地点になりうるので、レビュー対象にする(PRで見る)🔍
9. 演習(15〜25分)✍️🔥
演習A:15個を仕分けしよう📦
次を「env / configs / secrets / files」に分類してみて〜😄
LOG_LEVELDB_HOSTDB_PASSWORDJWT_SECRETfeatureFlags.jsonnginx.confallowed-origins.jsonseed.sqlgoogle-oauth-client-secret.jsonREADMEに書いたAPIキー(ダメ)…とか😂
演習B:構成を作る🛠️
configs/app-config.dev.jsonを作ってconfigsで渡すLOG_LEVELは env で渡す- アプリは
APP_CONFIG_PATHから config を読む
演習C:事故を体験(安全に)💥
- わざと
console.log(process.env)を入れて「危なさ」を見て、すぐ消す😇 - 次に「ログに出さない config.ts 集約」に直す
10. 章末チェックリスト✅🕵️♂️
- 秘密(鍵/トークン/パスワード)が env /
.envに入ってない -
.env.exampleがあって、秘密が混ざってない - “設定の入口”が1か所(
config.tsなど) - configs は「ファイルの塊」、env は「短い値」に寄せた
- configs / 設定ファイルはPRでレビュー対象になってる
- AIに貼るのは example まで。本物は貼らない🙅♂️
次の第21章(Compose secrets実践)に進むと、ここで分けた「secrets箱」をちゃんと安全に運用するところまで一気に完成するよ〜🔐🚀