エラーの内容
docker compose up を実行すると、大量の警告が表示されます:
WARN[0000] The "DB_PASSWORD" variable is not set. Defaulting to a blank string.
WARN[0000] The "DB_HOST" variable is not set. Defaulting to a blank string.
WARN[0000] The "REDIS_URL" variable is not set. Defaulting to a blank string.
.env ファイルは存在しています。目で確認できます。変数名も三回確認しました。それでも Docker Compose はファイルが存在しないかのように振る舞います。その間、データベースコンテナは空のパスワードで起動してすぐに失敗します — しかも深夜2時、本番環境で。
根本原因
Docker Compose には .env ファイルの読み込み場所と方法について厳格なルールがあります。どれか一つでも違反すると、ファイル全体が無警告でスキップされます:
- ディレクトリが違う:
.envファイルはdocker composeを実行するディレクトリと同じ場所に置く必要があります。docker-compose.ymlが存在する場所ではありません(両者が異なる場合)。 - ファイル名が違う:ファイルの名前は正確に
.envでなければなりません —.env.local、.env.production、env(ドットなし)は不可です。 - 構文エラー:値のクォート、
=前後の余分なスペース、Windows 形式の改行コード(\r\n)により、変数が正しく解析されないかスキップされることがあります。 env_fileと変数置換の混同:env_fileはコンテナに変数を注入します。.envファイルはcompose.yml内の変数置換に値を提供します。これらはまったく異なる仕組みです。- ファイルのパーミッション:Linux では、
.envファイルが現在のユーザーに読み取り権限がない場合、Docker Compose は何も言わずに無視します。
修正1:ファイルの場所と名前を確認する
まずここから始めましょう。正しいディレクトリにいることを確認します:
# 現在地を確認
pwd
# カレントディレクトリの隠しファイルを一覧表示
ls -la | grep .env
# 次のような表示になるはず:
# -rw-r--r-- 1 user user 245 May 14 02:13 .env
.env ファイルがサブディレクトリにあるか別の名前の場合は、移動するか --env-file で直接 Docker Compose に指定します:
docker compose --env-file ./config/.env.production up
修正2:.env ファイルの構文を確認する
構文には細かいルールがあります。ファイルを開いて、以下の典型的な落とし穴を確認してください:
# 悪い例 — = 記号の前後にスペース
DB_PASSWORD = mysecretpassword
# 悪い例 — クォートで囲んだ値(Docker Compose はクォートを除去しない)
DB_PASSWORD="mysecretpassword"
# 悪い例 — 値の後にインラインコメント
DB_PASSWORD=mysecretpassword # production password
# 良い例
DB_PASSWORD=mysecretpassword
二番目の例は非常によくある落とし穴です。Docker Compose はクォートされた値をそのままリテラルとして渡します — クォート文字も含めて。つまり DB_PASSWORD="mysecretpassword" は実際にクォートマーク付きの文字列 "mysecretpassword" になります。データベース認証がわかりにくい形で失敗します。
Windows 形式の改行コードも静かな問題の原因です。特にファイルが Windows で作成されたか、適切な .gitattributes なしに Git 経由で同期された場合:
# キャリッジリターンを確認
cat -A .env | head -5
# 悪い例: DB_PASSWORD=secret^M$
# 良い例: DB_PASSWORD=secret$
# Windows の改行コードを修正
sed -i 's/\r//' .env
修正3:env_file と .env 置換の違いを理解する
似た名前の仕組みが二つあります。動作はそれぞれ異なります。以下がその違いです:
仕組み1 — compose.yml 内の変数置換(プロジェクトルートの .env を使用):
# docker-compose.yml
services:
db:
image: postgres
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD} # ← 解析時に .env から置換される
仕組み2 — env_file ディレクティブ(変数を直接コンテナに注入):
# docker-compose.yml
services:
db:
image: postgres
env_file:
- .env # ← このファイルの変数がコンテナ環境に渡される
compose ファイルで ${DB_PASSWORD} 構文を使用している場合、Docker Compose はコンテナ起動前にその値を置換するためにプロジェクトルートの .env が必要です。代わりに env_file を使用する場合は、ファイルが実行時に読み取り可能であれば十分です。
修正4:Docker Compose が実際に認識している内容をデバッグする
推測は不要です。Docker Compose に直接確認しましょう:
# 完全に解決された compose 設定を表示(全変数が置換済み)
docker compose config
# DB_PASSWORD が空白のままなら、読み込まれていない
Docker Compose が実際に読み込んでいる .env ファイルを確認することもできます:
# Docker Compose v2 は詳細出力にこの情報を表示する
docker compose --verbose config 2>&1 | grep -i env
もう一つ便利な確認方法 — コンテナが受け取るすべての変数を表示:
docker compose run --rm your_service env | sort
修正5:フォールバックとして変数を明示的に渡す
根本原因を調査しながら今すぐ動かす必要がある場合は、ファイルを完全に迂回します:
# インラインで渡す(シークレットには不向き)
DB_PASSWORD=temporaryfix docker compose up
# または先にエクスポートする
export DB_PASSWORD=temporaryfix
docker compose up
シェル環境変数は .env の値より優先されるため、ファイルの問題に関係なく常に機能します。
確認手順
修正を適用したら、完了を宣言する前にこの三つの確認を実行してください:
# 1. config を実行して変数を grep する
docker compose config | grep DB_PASSWORD
# 実際の値が表示されるはず(空白ではない)
# 2. 起動時に WARN 行が出ないことを確認
docker compose up 2>&1 | grep WARN
# 空であるはず(少なくとも変数の警告はない)
# 3. コンテナが正しい値を受け取ったか確認
docker compose run --rm db env | grep DB_PASSWORD
予防策
今からこの習慣を身につければ、深夜2時に再びデバッグすることはなくなります:
- デプロイのたびに
docker compose configを実行する。 コンテナが起動する前に置換エラーを検出できます。5秒で終わります。 .envを.gitignoreに追加するが、必要なキーと空の値を含む.env.exampleはコミットしておく。新しいチームメンバーがドキュメントを読まなくても必要な変数がすぐにわかります。- CI/CD では env ファイルを明示する。
--env-fileを使ってファイル名を指定してください。パイプラインでは暗黙の.env検出に頼らないこと — ローカルで動いても CI では動かないことがよくあります。 - DB_PASSWORD などのシークレットには手で入力するのではなく強力なランダム値を生成する。 ToolCraft のパスワードジェネレーターは完全にブラウザ内で動作します — データベース認証情報を生成する際にサーバーに何も送信されません。
- 予期しない解析動作が見られる場合は compose ファイルの YAML を検証する。 ToolCraft の YAML ↔ JSON コンバーターで不正な YAML をすばやく発見できます。
クイックリファレンス:.env ファイルのルール
# 場所: 'docker compose' を実行するディレクトリと同じ場所
# 名前: 正確に '.env'(または --env-file で指定)
# 構文:
# KEY=value ✓ 正しい
# KEY = value ✗ = の前後にスペース不可
# KEY="value" ✗ クォートはリテラルとして扱われる
# KEY=value # note ✗ インラインコメント非対応
# export KEY=value ✗ 'export' キーワード非対応
DB_HOST=localhost
DB_PORT=5432
DB_NAME=myapp
DB_PASSWORD=use-a-real-random-password-here

