Docker Compose の環境変数が反映されない場合:.env、env_file、優先順位とコンテナ再作成の確認方法

Docker Compose で .env の変更が反映されない場合の対処法。再現可能な例で変数の補間とコンテナ環境を区別し、env_file、Shell による上書き、ドル記号のエスケープ、restart と再作成の違いを確認します。PowerShell の調査コマンドも掲載。

Docker Compose の環境変数が反映されないときは、まず二つの処理を区別します。.env と --env-file は Compose が設定を解決するための変数を提供し、サービスの environment と env_file は変数をコンテナに渡します。設定変更後に restart を実行しても、既存コンテナの環境は更新されません。解決後の設定を確認してから up -d で変更を適用します。

デプロイ手順に従っていても、.env に書いた値がコンテナ内に存在しない、値を変更して再起動したのにアプリケーションが古いアドレスを使い続ける、といったことがあります。 「入力ファイル → Compose 設定 → コンテナ環境 → アプリケーションによる読み取り」の順に調べると、原因を絞り込めます。

この記事は Compose V2 と Linux コンテナを対象とし、Docker Desktop の Linux コンテナモードも含みます。 ドキュメントの確認日は 2026 年 11 月 4 日です。コマンドは公式ドキュメントに基づいており、この記事の作成環境では Docker コンテナを実行していません。

Joplin Server や Syncthing などのセルフホストサービスを管理している場合も、まず以下の独立した例で上書きの規則を理解してから、実際のサービス設定を確認してください。

四つの指定方法は変数をどこに渡すのか

指定方法 使用する場所 主な役割
.env Compose プロジェクトで慣例的に使う入力ファイル ${VAR} などの補間に値を提供する
--env-file ./deploy.env Compose のコマンドラインオプション 補間用の入力ファイルを明示的に指定する
env_file: ./app.env 個別のサービス設定 ファイル内の変数をそのサービスのコンテナに渡す
environment: 個別のサービス設定 コンテナ変数を直接設定、参照、上書きする

同じファイルを両方の用途に使うこともできますが、明示的な指定が必要です。 ディレクトリに .env を置くだけで、その中のすべての変数がすべてのコンテナに渡されるわけではありません。

たとえば .env に APP_MODE=production があっても、サービス側で環境変数を宣言していなければ、通常それだけではコンテナに APP_MODE は渡りません。 サービスに environment: APP_MODE: "${APP_MODE}" を指定することで、値の受け渡しがつながります。

公式の説明は コンテナ環境変数の設定 を参照してください。

業務データを持たないプロジェクトで上書きを確認する

まず CLI と、実際に接続している Docker ホストを確認します。

1
2
3
docker compose version
docker context show
docker info

独立したディレクトリ compose-env-lab を作成し、次の三つのファイルを用意します。 実験用サービスを本番プロジェクトに直接追加しないでください。

1
2
3
4
compose-env-lab/
├── compose.yaml
├── .env
└── app.env

compose.yaml:

1
2
3
4
5
6
7
8
9
services:
  probe:
    image: alpine:3.22
    env_file:
      - ./app.env
    environment:
      APP_MODE: "${APP_MODE:-development}"
      APP_LABEL: "${APP_LABEL:?APP_LABEL is required}"
    command: ["sleep", "3600"]

.env:

1
2
3
APP_MODE=production
APP_LABEL=compose-env-lab
ONLY_FOR_COMPOSE=not-in-container

app.env:

1
2
APP_MODE=from-env-file
APP_COLOR=blue

この例ではポートの公開、ボリューム、特権権限を使用しません。 Docker ホストからアクセスできるレジストリからイメージを取得する必要があります。最初の実験が終わるまでは、比較できるようファイルを変更しないでください。

まず、このディレクトリで実行します。

1
2
3
docker compose -p compose-env-lab config -q
docker compose -p compose-env-lab config --environment
docker compose -p compose-env-lab config

config -q の成功は、設定の検証が通ったことだけを意味します。 config --environment は補間に使われる変数を表示し、通常の config はマージと解決を終えたサービスモデルを表示します。 どちらもコンテナの作成済み状態や、アプリケーションが値を読み取ったことを証明するものではありません。

これらの出力にはパスワードが含まれる場合があります。信頼できる端末でのみ確認し、共有前に機密値を削除してください。 各オプションは docker compose config を参照してください。

起動後は確認が必要な変数だけを読む

1
2
3
docker compose -p compose-env-lab up -d
docker compose -p compose-env-lab ps
docker compose -p compose-env-lab exec probe printenv APP_MODE APP_LABEL APP_COLOR

Compose を起動した端末に同名の変数による上書きがなければ、次の順で出力される想定です。

1
2
3
production
compose-env-lab
blue

APP_MODE は .env を使った補間結果で、app.env の同名の値を上書きします。 APP_COLOR はサービスの env_file を通じて渡されます。 APP_LABEL は必須項目で、未設定または空の場合は設定の解決時にエラーになります。

次に、コンテナへの受け渡しを宣言していない変数を個別に確認します。

1
docker compose -p compose-env-lab exec probe printenv ONLY_FOR_COMPOSE

出力はなく、コマンドはゼロ以外の終了ステータスを返す想定です。 これは実験として正常な結果であり、.env が全変数をコンテナに渡すファイルではないことを示します。

.env の値が端末によって上書きされる理由

Compose が ${APP_MODE} を解決するとき、起動元の Shell に同名の変数があれば、その値が優先されます。 ファイルには production とあるのに解決結果が staging になる場合は、まず端末の環境を確認します。

Bash では、実験用の変数を次のように確認して解除できます。

1
2
3
printenv APP_MODE
unset APP_MODE
docker compose -p compose-env-lab config --environment

PowerShell での対応する操作は次のとおりです。

1
2
3
Get-Item Env:APP_MODE -ErrorAction SilentlyContinue
Remove-Item Env:APP_MODE -ErrorAction SilentlyContinue
docker compose -p compose-env-lab config --environment

現在の端末から変数を削除する前に、別の作業で必要な設定ではないことを確認してください。 IDE のタスク、CI ジョブ、システムサービスが継承する環境も、手動で開いた端末とは異なる場合があります。

作業ディレクトリによる曖昧さを減らすには、デプロイコマンドで設定ファイルと入力ファイルを明示します。

1
2
docker compose -p myapp -f ./compose.yaml --env-file ./deploy.env config -q
docker compose -p myapp -f ./compose.yaml --env-file ./deploy.env config

myapp は既存のプロジェクト名に置き換え、本番デプロイ時に安易に変更しないでください。 プロジェクト名はコンテナ、ネットワーク、既定のボリュームの名前に使われるため、変更すると別のリソース群が作成される場合があります。

--env-file の相対パスはコマンド実行時の作業ディレクトリが基準です。サービスの env_file の通常の相対パスは Compose ファイルの場所が基準になります。 複数の Compose ファイル、--project-directory、COMPOSE_FILE はパスの関係を複雑にするため、調査時は明確なパスを使って範囲を絞り込みます。

補間用の入力ファイルを複数指定した場合、後のファイルが前のファイルの同名項目を上書きできます。

1
docker compose --env-file .env --env-file .env.prod config

Shell にすでに存在する同名の変数が、引き続き優先される場合があります。 既定の .env の検出方法は使用中の CLI バージョンと合わせて確認してください。Compose の補間とファイル読み込み規則 に説明があります。

コンテナ内の優先順位は別に確認する

補間の入力が分かったら、サービスが最終的にどのようにコンテナ変数を設定するかを確認します。 明示的に値を代入する一般的なケースでは、次の上書き関係で整理できます。

ケース 結果への影響
docker compose run -e APP_MODE=debug 今回の一時コンテナの変数を上書きする
サービスの environment に APP_MODE を設定する サービスの env_file にある同名の値を上書きする
サービスに複数の env_file を指定する 後のファイルが前のファイルの同名の値を上書きする
イメージの Dockerfile にある ENV 実行時に同名の設定で上書きされない場合に残る

ここでの environment の値自体が、Shell や .env の補間から得られる場合もあります。 「どこから値が解決されたか」と「どのサービス項目を通じてコンテナに渡すか」を一つの処理として考えないようにします。 値を付けずに変数名だけを書く透過的な受け渡しには、解決できない場合に変数を削除する意味もあります。調査中は明示的な代入を優先してください。

実験では次のコマンドで一時的な上書きを確認できます。

1
docker compose -p compose-env-lab run --rm -e APP_MODE=debug probe printenv APP_MODE

想定される出力は debug です。 これは一回限りのコンテナを作成するもので、先ほど up -d で起動した probe コンテナは変更しません。 run -e を up にも使える共通の引数として扱わないでください。

詳細な適用範囲と値の受け渡し例は 公式の環境変数の優先順位 を参照してください。

ファイル変更後も restart で古い値が残る理由

コンテナの環境変数はコンテナ作成時に決まります。 docker compose restart は既存コンテナを再起動するもので、変更後の設定から環境を再作成しません。

実験用 .env の APP_MODE を staging に変更したら、次の順で比較します。

1
2
3
docker compose -p compose-env-lab config
docker compose -p compose-env-lab restart probe
docker compose -p compose-env-lab exec probe printenv APP_MODE

最初にコンテナが production を使っていた場合、再起動後もその値のままになる想定です。 この時点では設定ファイルと実行中のコンテナが異なる状態にあります。

解決後の設定が正しいことを確認してから、変更を適用します。

1
2
docker compose -p compose-env-lab up -d probe
docker compose -p compose-env-lab exec probe printenv APP_MODE

通常、Compose は設定変更を検出して影響を受けるサービスのコンテナを再作成します。 強制的な再作成が実際に必要な場合は、次を使います。

1
docker compose -p compose-env-lab up -d --force-recreate probe

再作成ではサービスが中断するため、適切なメンテナンス時間帯に実施します。 データベースなどの依存サービスも操作すべきかは実際の構成によって判断し、毎回プロジェクト全体を再作成しないでください。

マウントしたボリュームは設定に従って引き続き使用されますが、コンテナの書き込み可能レイヤーに加えた一時的な変更は失われる場合があります。 操作前に、業務データが永続化先に保存されていることを確認してください。 公式の動作説明は restart と up を参照してください。

ドル記号、空の値、真偽値で起きやすい問題

コンテナ内で変数を展開する

Compose ファイル内の $VAR は、通常 Compose によって先に処理されます。 コンテナ内の Shell に変数を読み取らせたい場合は、$$ を使い、Shell を明示的に呼び出します。

1
2
3
4
5
6
services:
  probe:
    image: alpine:3.22
    environment:
      APP_MODE: "production"
    command: ["sh", "-c", "printf '%s\\n' \"$$APP_MODE\""]

これは値を表示して終了する、独立した短時間実行サービスの例です。 $$ はホスト側での Compose による展開を防ぎ、sh -c がコンテナ内で展開を行います。 Shell を通さない引数配列に変数を入れるだけでは、Shell の変数展開は自動的には行われません。

構文は Compose Interpolation を参照してください。

空文字列と「未設定」は意味が異なる

${VAR:-default} は、変数が存在しない場合と空の場合の両方で既定値を使います。 ${VAR-default} は、変数が存在しない場合だけ既定値を使います。 ${VAR:?message} は空であってはならない入力に適しており、空のアドレスやパスが実行段階まで渡るのを防げます。

理由を記録せず、空文字列で本番設定を一時的に隠さないでください。 サービスで明示した空の値が、有効な env_file の設定を上書きする場合があります。

YAML では、真偽値に見える値も文字列として記述することを勧めます。

1
2
3
environment:
  FEATURE_ENABLED: "false"
  WORKER_COUNT: "2"

これで保証されるのは、文字列が渡されることだけです。 アプリケーションが "false" を無効と解釈するか、空でない文字列をすべて真とみなすかは、その設定パーサーによって異なります。

設定もコンテナも正しいのにアプリケーションが変わらない場合

まず、その変数名をアプリケーションがサポートしているか、設定ファイルやコマンドライン引数など、より優先度の高い入力がないかを確認します。 APP_URL、BASE_URL、PUBLIC_URL は共通のプロトコルではなく、異なるプロジェクト間で自由に置き換えることはできません。

次に、読み取りのタイミングを確認します。一部のフロントエンド設定はイメージのビルド時に静的ファイルへ埋め込まれるため、実行時の環境変数では既存の成果物を書き換えられません。 ビルド引数が必要なプロジェクトでは、そのドキュメントに従って build.args や専用の起動スクリプトを設定します。

最後に、正しいサービスとインスタンスを確認しているかを調べます。 同じプロジェクトでも worker、web、scheduler が別々の三つのコンテナである場合、一つだけ更新しても残り二つは変わりません。

確認結果 次の確認事項
config がまだ古い値を示す 入力ファイルのパス、Shell の上書き、複数ファイルのマージを確認する
config は正しいが exec printenv は古い値を示す プロジェクト名、Docker context、コンテナ再作成を確認する
コンテナの値は正しいがアプリケーションの動作は変わらない 変数名、アプリケーション側の優先順位、読み取り時点、アクセス先インスタンスを確認する
exec が失敗し、コンテナが動いていない まず ps -a と該当サービスのログを確認する

実験では次を実行できます。

1
2
docker compose -p compose-env-lab ps -a
docker compose -p compose-env-lab logs --tail 100 probe

業務用イメージには printenv や Shell が含まれていない場合があります。 その場合はイメージが提供する診断コマンドを使うか、管理者がコンテナ設定を確認して機密情報を除去します。調査だけを目的に本番イメージへ多数のツールを追加しないでください。

パスワード、ロールバック、実験の後片付け

実際のパスワードをサンプルリポジトリに書き込んだり、config、inspect、全件の env 出力をそのまま貼り付けたりしないでください。 .env は通常のテキストファイルであり、暗号化機能はありません。 認証情報を含まない .env.example はコミットできます。実際のデプロイファイルはプロジェクトの要件に従って読み取り権限を制限し、バージョン管理から除外します。

アプリケーションがファイルからの認証情報読み取りに対応している場合は、Compose secrets を検討できます。 許可された secret はコンテナ内のファイルとして提供され、一般的な配置先は /run/secrets/<name> です。 _FILE 変数は一部のイメージで採用されている慣例であり、すべてのアプリケーションが自動的に対応する機能ではありません。 ローカルの元ファイルも保護が必要です。Compose secrets の公式説明 を参照してください。

本番設定を変更する前に、前の設定と環境入力を保存し、プロジェクト名、イメージのバージョン、コマンド引数を記録します。 戻す際はそれらのファイルを復元し、同じ引数で config -q を確認してから up -d を実行し、最後にアプリケーションの動作を検証します。 設定のロールバックはデータベースのバックアップに代わるものではなく、アプリケーションが実施済みのデータ移行を元に戻せる保証もありません。

実験が終わったら、compose-env-lab ディレクトリで実行します。

1
docker compose -p compose-env-lab down

この例はボリュームを宣言していないため、-v は不要です。 実験用のコマンドを全体のクリーンアップ操作に変更しないでください。容量の管理については Docker のディスク容量クリーンアップガイド を参照してください。

調査の最後に、解決後の設定が期待どおりであること、実行中のコンテナが新しい値を持つこと、アプリケーションの実際の動作が変わったことを個別に確認します。 これらは異なる三つの層です。順に確認すれば、原因を取り違えたまま .env を何度も編集する事態を防げます。