2026年7月3日
2026年7月3日
DockerのARGとENVの違いと使い分け|ビルド時と実行時の変数、秘密情報の渡し方
Dockerfileの ARG は「イメージをビルドしている間だけ使う変数」、ENV は「ビルド中に加えて、できあがったイメージから起動したコンテナの中でも使える環境変数」です。バージョン番号のようにビルドの中身を切り替える値は ARG、アプリが実行時に読む設定は ENV か docker run -e で渡す、と分けると迷いません。この記事では、両者のスコープの違い、ARG から ENV へ値を引き継ぐ書き方、Docker Composeでの指定場所、パスワードやトークンをどちらにも書いてはいけない理由と代わりの方法を説明します。
内容はBuildKitを使う現在のDocker Engine / Docker Desktop(2026年10月現在)を前提にしています。
違いを一覧で押さえる
| ARG | ENV | |
|---|---|---|
| 使える期間 | ビルド中のみ(宣言したステージ内) | ビルド中の宣言以降と、コンテナ実行時 |
| 値の渡し方 | docker build --build-arg |
docker run -e / --env-file、Composeの environment |
| イメージに残るか | 環境変数としては残らない | イメージの設定に残り、docker inspect で見える |
| 典型的な用途 | ベースイメージのタグ、インストールするツールのバージョン | アプリの動作モード、タイムゾーン、PATH |
「ARGはイメージに残らない」と言っても、秘密にできるわけではありません。理由は後半で説明します。
ARGの基本とスコープ
# FROMより前のARGは FROM 行でだけ使える
ARG PHP_VERSION=8.3
FROM php:${PHP_VERSION}-fpm
# ステージ内で使うには、FROMの後で名前だけ再宣言する
ARG PHP_VERSION
ARG COMPOSER_VERSION=2
RUN echo "PHP ${PHP_VERSION} / Composer ${COMPOSER_VERSION}"
docker build --build-arg PHP_VERSION=8.2 -t myapp:php82 .
ここで一番つまずきやすいのがスコープです。FROM より前に書いた ARG は FROM 行の中でしか展開されず、そのままステージ内の RUN で参照すると空文字になります。ステージ内でも使いたい場合は、上の例のように FROM の後で ARG PHP_VERSION と名前だけ書き直すと、先ほどの値(デフォルト値か --build-arg で渡した値)を引き継ぎます。
マルチステージビルドでは、ARG の有効範囲はそれを宣言したステージの終わりまでです。次の FROM 以降で同じ値を使うなら、そのステージでもう一度宣言します。
--build-arg で渡した名前がDockerfileのどこにも宣言されていない場合、ビルドは止まらず警告が出るだけです。綴りの間違いに気づきにくいので、ビルドログの警告は読み飛ばさないようにします。
最初から定義されているARG
BuildKitでは、TARGETPLATFORM、TARGETOS、TARGETARCH、BUILDPLATFORM などのプラットフォーム情報が自動で用意されています。ただし、ステージ内で使うには ARG TARGETARCH のように宣言が要ります。arm64とamd64でダウンロードするバイナリを切り替えるときに便利です。
また、HTTP_PROXY や NO_PROXY などのプロキシ用の変数は、宣言しなくても --build-arg で渡せる特別扱いの名前です。
ENVの基本
FROM php:8.3-fpm
ENV TZ=Asia/Tokyo \
APP_ENV=production
ENV で設定した値は、以降の RUN で使えるうえ、イメージの設定として保存され、コンテナ起動時にも環境変数として入ります。実行時に上書きしたい場合は次のようにします。
docker run -e APP_ENV=staging myapp:latest
docker run --env-file ./app.env myapp:latest
書き方は ENV KEY=value の形を使います。ENV KEY value という古い形式も読み込めますが、非推奨扱いで、ビルド時に警告が出ることがあります。
ARGの値をENVに引き継ぐ
ビルド時に決めた値を実行時にも見せたいときは、ARG を受けて ENV に入れます。
ARG APP_VERSION=dev
ENV APP_VERSION=${APP_VERSION}
同じ名前の ARG と ENV がある場合、ENV で定義した値が優先されます。意図せず同名にすると --build-arg が効かないように見えるので、同名にするのは上のように引き継ぐ目的のときだけにします。
ビルドキャッシュへの影響
ARG の値を変えると、その ARG が最初に使われた命令からキャッシュが効かなくなります(宣言した行ではなく、使った行からです)。たとえばビルド日時やGitのコミットIDを ARG で渡し、それをDockerfileの先頭近くで使うと、毎回ほぼ全体がビルドし直しになります。こうした値は、LABEL などの形でDockerfileの末尾近くで使うと、重い RUN のキャッシュを生かせます。
ENV も同様で、値を変えると、その行以降のキャッシュは使われなくなります。頻繁に変わる値はDockerfileに書かず、実行時に -e で渡すほうが扱いやすくなります。
Docker Composeでの指定場所
Composeでは、ビルド時の値と実行時の値を書く場所が分かれています。
services:
app:
build:
context: .
args:
PHP_VERSION: "8.3" # Dockerfile の ARG に渡る
environment:
APP_ENV: production # コンテナの環境変数(実行時)
env_file:
- ./app.env # 実行時の環境変数をファイルから
混同しやすいのが、プロジェクト直下の .env ファイルです。これはComposeファイル内の ${VAR} を置き換えるための値で、そのままではコンテナに渡りません。コンテナに渡すには environment で参照するか、env_file で指定します。.env を書き換えたのにコンテナの中で値が変わらない、という問い合わせはたいていこの混同が原因です。実際に渡る値は docker compose config で展開後の内容を表示すると確かめられます。
パスワードやトークンをARG・ENVに入れない
ここが実務で一番大事な点です。
ENVに書いた値はイメージの設定に残るため、イメージを取得できる人ならdocker inspectで読めます。ARGは環境変数としては残りませんが、RUNで使った値はdocker historyなどのビルド履歴やメタデータに現れることがあります。
つまり、どちらもイメージを配布した時点で第三者に見える可能性があります。最近のBuildKitには、ARG や ENV に PASSWORD や TOKEN のような名前を使うと警告するビルドチェック機能もあります(チェックの名前や対象はバージョンで変わります)。
ビルド中にだけ秘密情報が要る場合(プライベートリポジトリからの取得など)は、シークレットマウントを使います。
# syntax=docker/dockerfile:1
FROM php:8.3-cli
RUN --mount=type=secret,id=composer_auth,target=/root/.composer/auth.json \
composer install --no-dev --no-interaction
docker build --secret id=composer_auth,src=$HOME/.composer/auth.json -t myapp .
マウントされたファイルはその RUN の間だけ存在し、イメージのレイヤーには残りません。target を省略すると /run/secrets/<id> に置かれます。
実行時に使うデータベースのパスワードなどは、Dockerfileに書かず、起動時に --env-file で渡すか、Docker SwarmやKubernetesのシークレット機能を使います。公式のMySQLやWordPressのイメージには、パスワードを環境変数ではなくファイルから読む _FILE で終わる変数(例:WORDPRESS_DB_PASSWORD_FILE)が用意されているものがあります。対応状況は各イメージの説明ページで確認してください。--env-file に使うファイルはGitにコミットしないよう .gitignore に加えておきます。
使い分けの判断基準
迷ったときは次の順で考えると整理できます。
- その値は秘密情報か。そうなら
ARGにもENVにも書かず、シークレットマウントか実行時の注入にする。 - ビルドの中身(ベースイメージ、インストールする物)を変える値か。そうなら
ARG。 - アプリが起動後に読む値か。環境ごとに変わるなら実行時に
-eやenv_fileで渡し、全環境で共通の既定値だけENVに書く。
WordPressの開発環境なら、PHPのバージョンは ARG、WORDPRESS_DEBUG のような動作設定はComposeの environment、データベースのパスワードは .gitignore 済みのファイルか _FILE 変数、という分け方が扱いやすい構成です。
まとめ
ARGはビルド中だけ、ENVはビルド中と実行時の両方で使える。FROMより前のARGはステージ内で使うには再宣言が要る。マルチステージではステージごとに宣言する。- 同名なら
ENVが優先される。ARGからENVへはENV X=${X}で引き継ぐ。 - Composeでは
build.argsがビルド時、environmentとenv_fileが実行時。.envは置き換え用で、そのままではコンテナに渡らない。 - 秘密情報は
ARGにもENVにも入れず、RUN --mount=type=secretや実行時の注入を使う。