目次

Docker 環境変数チュートリアル:.env と secrets で設定・機密情報を管理する

同じイメージでも、開発環境、テスト環境、本番環境では接続先のデータベースや設定が異なります。こうした設定は環境変数に入れ、コンテナの実行時に渡すのが一般的です。

-e で設定する

$ docker run --rm -e NODE_ENV=production -e PORT=8080 alpine:3.23 sh -c "echo \$NODE_ENV \$PORT"
production 8080

$ export API_KEY=abc123 && docker run --rm -e API_KEY alpine:3.23 sh -c "echo API_KEY=\$API_KEY"
API_KEY=abc123
  • -e 名前=値 で値を直接設定します。
  • 値を指定せず -e 名前 だけを書くと、ホストにある同名の環境変数を引き継ぎます。

--env-file でファイルを読み込む

変数が多いと、コマンドに直接書くのは管理しにくくなります。ファイルにまとめましょう。

$ cat app.env
# app.env
NODE_ENV=production
PORT=8080
GREETING="hello world"
DATABASE_URL=postgres://app:secret@db:5432/app

$ docker run --rm --env-file app.env alpine:3.23 env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=e311730363f7
NODE_ENV=production
PORT=8080
GREETING="hello world"
DATABASE_URL=postgres://app:secret@db:5432/app
HOME=/root

GREETING の行に注目してください。ファイルに書いた値が "hello world" の場合、コンテナ内の値にも引用符が含まれます。docker run --env-file のルールは次のとおりです。

  • 1 行に KEY=VALUE を 1 つ書きます。# で始まる行はコメントです。
  • 値を引用符で囲まないでください。引用符も値の一部として扱われます。
  • $OTHER_VAR による変数展開には対応していません。

(後で見るように、Compose で同じファイルを読み込むと引用符が取り除かれます。動作が異なります。)

Dockerfile でデフォルト値を設定する

ENV NODE_ENV=production \
    PORT=3000

ENV はデフォルト値を設定します。docker run -e で上書きできます。変わることが少なく、機密情報でもない設定に適しています。

優先順位

環境変数の優先順位:docker run -e または compose environment が最も高く、次に env-file、Dockerfile ENV。.env は compose.yaml 内の変数置換に使用
環境変数の優先順位と .env の異なる用途

優先順位の高い順です。

  1. docker run -e
  2. docker run --env-file
  3. Dockerfile の ENV
  4. ベースイメージの ENV

環境変数は見える?

環境変数は便利ですが、安全な保管場所ではありません。docker inspect を実行できる人なら誰でも値を確認できます。

$ docker run -d --name envdemo -e SECRET_TOKEN=abc123 alpine:3.23 sleep 60
431168d97dc8187ec79e420638155b2f53fd78a9d82f8a6d13eb6bd9aec09bcb

$ docker inspect --format '{{json .Config.Env}}' envdemo
["SECRET_TOKEN=abc123","PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"]

$ docker rm -f envdemo
envdemo

また、プログラムのエラー時に環境変数がログへ出力されることがあり、子プロセスにも引き継がれます。パスワードや API キーには、「機密情報を扱う」の方法を使ってください。

Docker Compose の環境変数

Compose には混同しやすい「環境変数」が 2 種類あります。例を見てみましょう。compose.yaml:

services:
  app:
    image: alpine:3.23
    command: ["sh", "-c", "env | sort | grep -E 'APP_|DATABASE|NODE_ENV|PORT|GREETING'"]
    environment:
      APP_VERSION: ${APP_VERSION}
      DATABASE_PASSWORD: ${DB_PASSWORD}
    env_file:
      - app.env

1. コンテナに渡す変数:environment と env_file

environment は compose.yaml に直接記述します。env_file はファイルを読み込みます(ここでは先ほどの app.env を使います)。

2. compose.yaml の内容を置換する変数:.env

Compose はプロジェクトフォルダー内の .env ファイルを自動的に読み込み、compose.yaml 内の ${...} を置換します。docker compose config を使うと、置換後の最終設定を確認できます。

$ cat .env
APP_VERSION=1.4.2
DB_PASSWORD=change-me

$ docker compose config app
name: ch15
services:
  app:
    command:
      - sh
      - -c
      - env | sort | grep -E 'APP_|DATABASE|NODE_ENV|PORT|GREETING'
    environment:
      APP_VERSION: 1.4.2
      DATABASE_PASSWORD: change-me
      DATABASE_URL: postgres://app:secret@db:5432/app
      GREETING: hello world
      NODE_ENV: production
      PORT: "8080"
    image: alpine:3.23
    networks:
      default: null
networks:
  default:
    name: ch15_default

$ docker compose run --rm app
[+] run 1/1
 ✔ Network ch15_default Created                                                                 0.0s
Container ch15-app-run-dfbcf95b7271 Creating
Container ch15-app-run-dfbcf95b7271 Created
APP_VERSION=1.4.2
DATABASE_PASSWORD=change-me
DATABASE_URL=postgres://app:secret@db:5432/app
GREETING=hello world
NODE_ENV=production
PORT=8080
  • ${APP_VERSION} と ${DB_PASSWORD} が .env の値に置換されました。
  • app.env の GREETING="hello world" は、Compose で読み込むと引用符が取り除かれます。docker run --env-file とは異なります。
  • PORT: "8080" は文字列であることを示すため、引用符が付いています(環境変数はすべて文字列です)。

.env の内容は自動的にはコンテナに渡されません。.env は compose.yaml 内の置換に使われるだけです。コンテナに渡すには、environment で参照する(例:APP_VERSION: ${APP_VERSION})か、env_file: .env を指定します。

デフォルト値と必須項目のチェック

書き方意味
${VAR}VAR の値に置換
${VAR:-デフォルト値}未設定または空の場合にデフォルト値を使用
${VAR:?エラーメッセージ}未設定または空の場合にエラーで停止

${VAR:?} は、パスワードのように「必ず設定する」変数に適しています。設定を忘れるとすぐに処理が停止し、空のパスワードで起動するのを防げます。

services:
  db:
    image: postgres:18
    environment:
      POSTGRES_PASSWORD: ${MISSING_PASSWORD:? .env で MISSING_PASSWORD を設定してください}
$ docker compose -f compose.required.yaml config
error while interpolating services.db.environment.POSTGRES_PASSWORD: required variable MISSING_PASSWORD is missing a value: .env で MISSING_PASSWORD を設定してください

機密情報を扱う

  • パスワードを Dockerfile の ENV や ARG に書かないでください。イメージ内に残ります(ARG の検証結果はDockerfile 命令リファレンスを参照してください)。
  • .env を Git にコミットしないでください。.gitignore に .env を追加し、実際の値を含まない .env.example を別途用意します。
  • .dockerignore に .env を追加し、COPY . . でイメージに含まれないようにします。

ファイルで機密情報を渡す(Compose secrets)

多くの公式イメージは、_FILE で終わる変数を使ってファイルからパスワードを読み込めます。

services:
  db:
    image: postgres:18
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password

secrets:
  db_password:
    file: ./secrets/db_password.txt
$ docker compose up -d db
[+] up 1/1
 ✔ Container ch15-db-1 Started                                                                  0.3s

$ docker compose exec db sh -c "ls -l /run/secrets; cat /run/secrets/db_password; echo; env | grep POSTGRES"
total 4
-rw-rw-r-- 1 1001 1001 16 Oct 12 14:25 db_password
s3cret-from-file
POSTGRES_PASSWORD_FILE=/run/secrets/db_password

$ docker compose down
[+] down 2/2
 ✔ Container ch15-db-1  Removed                                                                 0.1s
 ✔ Network ch15_default Removed                                                                 0.1s

機密情報は /run/secrets/db_password にファイルとしてコンテナ内に置かれます。環境変数に入るのはファイルパス POSTGRES_PASSWORD_FILE だけなので、docker inspect でパスワード自体を見ることはできません。

ビルド時に必要な機密情報

たとえば、プライベートパッケージのインストールにトークンが必要な場合は、BuildKit の secret マウントを使います。

# syntax=docker/dockerfile:1
RUN --mount=type=secret,id=npm_token \
    NPM_TOKEN=$(cat /run/secrets/npm_token) npm ci
docker build --secret id=npm_token,env=NPM_TOKEN -t myapp .

トークンはこの RUN の実行中だけ利用でき、どのレイヤーにも残りません。

まとめ

  • 優先順位:-e/environment > --env-file/env_file > Dockerfile ENV。
  • .env は compose.yaml 内の ${VAR} の置換に使われ、コンテナには自動で渡されません。
  • docker run --env-file は値の引用符を取り除きませんが、Compose は取り除きます。
  • 機密情報はファイル(secrets)で渡し、イメージに書き込まないでください。

練習問題

練習 1:イメージに ENV MODE=prod が設定されています。docker run -e MODE=dev を実行した場合、コンテナ内の MODE は何になりますか?

解答

dev です。-e は Dockerfile の ENV より優先されます。

練習 2:compose.yaml に POSTGRES_PASSWORD: ${DB_PASSWORD:?DB_PASSWORD is required} と書かれていますが、.env に DB_PASSWORD がありません。docker compose up を実行するとどうなりますか?

解答

Compose は DB_PASSWORD is required と表示してエラーで停止します。空のパスワードでデータベースを作成することはありません。

よくある質問

.env を変更したのにコンテナの環境変数が変わらないのはなぜですか?

環境変数はコンテナの作成時に決まります。変更を反映するにはコンテナを再作成してください。Compose では docker compose up -d を使います。restart では反映されません。

docker inspect でパスワードが見えてしまいますか?

はい。-e で渡した値はすべて docker inspect に表示されます。機密情報はファイル(secrets)で渡してください。

${VAR:-デフォルト値} と ${VAR:?メッセージ} の違いは何ですか?

前者は未設定の場合にデフォルト値を使います。後者は未設定の場合にエラーで停止します。空文字列で起動するのを防げるため、必須のパスワードに適しています。

更新日 2026年10月14日