
Dockerコンテナを開発環境や本番環境で運用する際、多くのエンジニアが直面するのが「環境変数が反映されない」「社内プロキシ環境下でビルドがタイムアウトする」「コンテナ内のログがUTC(世界協定時)になって時刻が9時間ズレる」というトラブルです。
特に ARG と ENV のスコープの違いや、マルチステージビルドにおける変数の消失、社内プロキシ(HTTP_PROXY)の引き回し、そして機密情報(APIキーやトークン)の安全な注入方法は、Docker初学者から実務エンジニアまで頻出のつまずきポイントとなっています。
この記事では、Dockerfileにおける環境変数の設定ルール(ARG と ENV の使い分け)、企業ネットワークでのプロキシ透過設定、OS別のタイムゾーン(JST: Asia/Tokyo)設定、そしてBuildKitを活用したシークレット管理までをコード例付きで体系的にまとめました。
この記事で行うこと
- ビルド時限定の
ARGとコンテナ実行時も永続化するENVの違いと使い分けを理解します - マルチステージビルドで
FROMごとにARGのスコープがリセットされる罠と回避策を学びます - 社内プロキシをDockerfileに直書きせず、
--build-argで安全に注入する手順を整理します - Ubuntu/Debian系およびAlpine Linuxでタイムゾーンを日本時間(
Asia/Tokyo)に設定します - BuildKitの
--mount=type=secretを使い、イメージ履歴に機密情報を残さないビルド手法を把握します
前提条件・対象読者
- 対象環境:Docker Engine / Docker Desktop / WSL2コンテナ環境(BuildKit有効環境)
- 対応バージョン:Docker 20.10以降(BuildKit標準搭載バージョン、最終確認:2026年11月)
- バージョン確認コマンド:
docker --versionおよびdocker buildx version
1. Dockerfile環境変数・プロキシ・タイムゾーン早見表
まずは、現場ですぐにコピペして使える各種設定のベストプラクティス早見表です。
| 設定項目 | 推奨される記述方法 | 備考・適用スコープ |
|---|---|---|
ビルド時の一時変数(ARG) | ARG NODE_VERSION=20.x | ビルド時のみ有効。コンテナ実行時には残らない |
コンテナ永続環境変数(ENV) | ENV NODE_ENV=production | ビルド時および実行時(ランタイム)の両方で有効 |
| タイムゾーン設定(Ubuntu/Debian) | ENV TZ=Asia/TokyoRUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime | tzdata パッケージを導入してシンボリックリンク作成 |
| タイムゾーン設定(Alpine Linux) | RUN apk add --no-cache tzdata && cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime | Alpine用の軽量なJST設定手順 |
| ビルド時プロキシ引数渡し | docker build --build-arg HTTP_PROXY=$HTTP_PROXY . | Dockerfile内へのハードコードを避けポータビリティを維持 |
| 機密情報の安全なマウント | RUN --mount=type=secret,id=token cat /run/secrets/token | イメージレイヤーに秘密情報を残さないBuildKit機能 |
2. ARGとENVの決定的な違いと使い分け
Dockerfileで変数を定義する際、最も混同しやすいのが ARG と ENV です。
ARG:ビルド時のみ有効な引数
ARG で宣言した変数は、docker build コマンド実行中にのみ参照できます。コンテナが起動した後のランタイム環境には引き継がれません。
# 基本的なARGの宣言とデフォルト値
ARG APP_VERSION=1.0.0
# ビルド時に外部から上書き可能
# docker build --build-arg APP_VERSION=2.0.0 .
注意点として、ARG の値はコンテナ起動後の環境変数には残りませんが、docker history コマンドを実行するとイメージレイヤーのビルド履歴として平文で閲覧可能です。そのため、パスワードや秘密鍵を ARG で渡すのはセキュリティ上避ける必要があります。
ENV:コンテナ実行時にも残る永続環境変数
ENV で設定した変数は、ビルド中だけでなく、コンテナが起動してアプリケーションが動作している間もOSの環境変数として永続化されます。
ENV PORT=8080
ENV NODE_ENV=production
# 実行時コマンドで参照可能
EXPOSE $PORT
CMD ["node", "server.js"]
マルチステージビルドでの落とし穴:FROMごとのスコープリセット
マルチステージビルドを使用する場合、ARG の有効範囲(スコープ)は各 FROM 命令の直下でリセットされます。
# グローバルスコープのARG(FROM行でのみ使用可能)
ARG BASE_TAG=20-slim
FROM node:${BASE_TAG} AS builder
# ここで再度ARGを宣言しないとBUILD_TARGETは空になる
ARG BUILD_TARGET=production
RUN echo "Building for: ${BUILD_TARGET}"
FROM node:${BASE_TAG} AS runner
# runnerステージでも再度宣言が必要
ARG BUILD_TARGET=production
ENV TARGET=${BUILD_TARGET}
「1行目で ARG を書いたのに後続ステージで参照できない」という場合は、該当ステージの FROM 直下で再宣言されているか確認してください。
3. 社内プロキシ環境下でのDockerfileビルド設定
企業の社内ネットワークやVPN環境では、外部インターネットへのアクセスにプロキシサーバーの経由が必須となるケースがあります。
DockerfileにプロキシURLをハードコードしない
初心者がやりがちなアンチパターンが、Dockerfile内に直接プロキシURLを書き込んでしまうことです。
# ❌ 間違い例(社内環境専用のURLが固定化され、社外やCI/CDでビルドできなくなる)
ENV http_proxy=http://proxy.company.local:8080
これを行うと、リポジトリをクラウドCI/CD(GitHub Actions等)や自宅環境でビルドした際にプロキシ接続エラーで失敗します。
⭕ 正しい手順:ビルド引数(–build-arg)で外部から注入する
プロキシ情報はDockerfile内には記述せず、ビルドコマンドの引数として渡します。Dockerは標準定義されたプロキシ用Build-time変数(HTTP_PROXY, HTTPS_PROXY, NO_PROXY および小文字版)を自動認識します。
# プロキシ環境変数を渡してビルド(イメージ履歴にも残らない標準予約変数)
docker build \
--build-arg HTTP_PROXY="http://proxy.example.com:8080" \
--build-arg HTTPS_PROXY="http://proxy.example.com:8080" \
--build-arg NO_PROXY="localhost,127.0.0.1,.example.com" \
-t my-app .
パッケージマネージャーごとの追加設定
OSの基本パッケージ(apt 等)をインストールする際、環境によっては明示的なプロキシ設定が必要になる場合があります。
Debian / Ubuntu系でビルド時のみプロキシを適用し、設定痕跡を残さない書き方:
ARG HTTP_PROXY
ARG HTTPS_PROXY
RUN if [ -n "$HTTP_PROXY" ]; then \
echo "Acquire::http::Proxy \"$HTTP_PROXY\";" > /etc/apt/apt.conf.d/01proxy; \
echo "Acquire::https::Proxy \"$HTTPS_PROXY\";" >> /etc/apt/apt.conf.d/01proxy; \
fi && \
apt-get update && apt-get install -y --no-install-recommends curl && \
rm -rf /var/lib/apt/lists/* && \
rm -f /etc/apt/apt.conf.d/01proxy
ビルド終了時に /etc/apt/apt.conf.d/01proxy を削除しておくことで、完成したイメージに社内プロキシ情報を残さないクリーンな設計が実現できます。
4. タイムゾーン(JST: Asia/Tokyo)の正しい設定方法
Docker公式のベースイメージの多くは、タイムゾーンがデフォルトでUTC(世界協定時)に設定されています。
コンテナ内のログ記録、日次バッチ処理、データベースのタイムスタンプを日本時間(JST = UTC+9)に合わせるには、OSに応じたタイムゾーン設定を適用します。
Debian / Ubuntu系ベースイメージでの設定
FROM ubuntu:24.04
# 対話型プロンプトの抑止とタイムゾーン環境変数の指定
ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=Asia/Tokyo
RUN apt-get update && apt-get install -y --no-install-recommends \
tzdata && \
ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
echo $TZ > /etc/timezone && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
ポイントは DEBIAN_FRONTEND=noninteractive を指定することです。これを忘れると、tzdata のインストール中に地域選択の対話プロンプトが表示され、ビルドが途中で停止してしまいます。
Alpine Linuxベースイメージでの設定
軽量なAlpineイメージでは、パッケージマネージャーが apk となり、以下の手順で設定します。
FROM alpine:3.20
ENV TZ=Asia/Tokyo
RUN apk add --no-cache tzdata && \
cp /usr/share/zoneinfo/$TZ /etc/localtime && \
echo $TZ > /etc/timezone && \
apk del tzdata
Alpineでは /usr/share/zoneinfo/Asia/Tokyo を /etc/localtime にコピーした後、不要になった tzdata パッケージを削除(apk del tzdata)することで、イメージサイズを小さく保てます。
5. 機密情報を安全に渡すBuildKit Secretsの活用
GitHubのプライベートリポジトリから依存パッケージを取得する際や、社内パッケージレジストリ(npm, pip)へアクセスする際、認証トークンが必要になります。
❌ やってはいけない例:ARGによるトークン渡し
# ❌ 危険:イメージのレイヤー履歴(docker history)にトークンが残る
ARG GITHUB_TOKEN
RUN git clone https://${GITHUB_TOKEN}@github.com/myorg/private-repo.git
この方法で作成されたイメージは、docker history --no-trunc を実行するだけでトークン文字列が平文で見えてしまいます。
⭕ 推奨される方法:BuildKitのシークレットマウント
Docker BuildKitの RUN --mount=type=secret を使用すると、該当の RUN ステップ実行中のみ一時ファイル(デフォルトは /run/secrets/<id>)としてメモリ上にマウントされ、完成したイメージレイヤーには一切データや履歴が残りません。
Dockerfile側の記述:
# syntax=docker/dockerfile:1
FROM python:3.12-slim
# シークレットを一時ファイルとしてマウントしてpip認証に利用
RUN --mount=type=secret,id=pip_conf \
PIP_CONFIG_FILE=/run/secrets/pip_conf pip install --no-cache-dir my-private-package
ビルドコマンド実行時の記述:
# ローカルの秘密設定ファイルをシークレットとして渡す
docker build --secret id=pip_conf,src=$HOME/.pip/pip.conf -t my-app .
6. よくある質問(FAQ)
Q1. ARGやENVで設定した値がCMDやENTRYPOINTで展開されません。
CMD や ENTRYPOINT をJSON配列形式(exec形式: ["node", "$START_FILE"])で記述した場合、シェルを介さずに直接プロセスが起動されるため、環境変数($START_FILE)が展開されません。変数を展開したい場合は、明示的にシェル(sh -c)を呼び出す形式で記述します。
# ❌ exec形式そのままでは変数が展開されない
CMD ["node", "$START_FILE"]
# ⭕ sh -c を経由させることで変数が展開され、シグナルもexecで引き継げる
CMD ["sh", "-c", "exec node $START_FILE"]
Q2. /etc/localtime を変更したのにアプリ側の時刻がUTCのままです。
JavaやNode.js、Pythonなどのランタイムによっては、環境変数 TZ が明示されていないとUTCへフォールバックする場合があります。Dockerfile内に必ず ENV TZ=Asia/Tokyo を記述しておいてください。
まとめ
Dockerfileにおける環境変数・プロキシ・タイムゾーン設定の要点は以下の4つです。
- ビルド時限定の値は
ARG、コンテナ実行時も必要な値はENVを使い分ける - 社内プロキシはDockerfileに直書きせず、
--build-arg HTTP_PROXY=...で外部から渡す - タイムゾーンは
ENV TZ=Asia/Tokyoと/etc/localtimeの設定をセットで行う - 認証トークン等の機密情報は
ARGではなくRUN --mount=type=secretで安全にマウントする
次に読むおすすめ記事
WSL2とDockerを組み合わせたWindows開発環境の構築手順や頻出トラブルの解決策を体系的に学びたい方は、以下のまとめ記事もあわせて参考にしてください。

Dockerfileのビルドエラー対策やマルチステージビルドのキャッシュ最適化については、以下の個別記事で詳しく解説しています。

