「DockerfileのARGに値を渡したいが、compose.ymlでどう書けばいいかわからない」
Composeを使い始めると、こうしたビルド周りの疑問が必ず出てきます。
Docker Composeには、コンテナの起動設定と同じcompose.ymlの中でDockerfileからのビルドを完全に制御できる
buildセクションがあります。コンテキストパスの指定・ビルド時引数の注入・キャッシュ戦略の構成まで、imageキーで既成イメージを使うだけでは実現できない柔軟な設計が可能になります。この記事では、buildセクションの主要パラメータである
context・args・cache_from/cache_to・targetを整理し、実サーバーの確認例を交えて解説します。動作確認環境: Rocky Linux 9.4 / Ubuntu 24.04 LTS(Docker Engine 26.x・Docker Compose Plugin v2.28)
この記事のポイント
・docker compose buildのbuildセクションでコンテキスト・Dockerfile・引数を一元管理できる
・argsとDockerfileのARGを対応させることでビルド時にcompose.ymlから値を注入できる
・cache_from/cache_toでCI/CDのビルドキャッシュをレジストリに保存・再利用し高速化できる
・--no-cacheフラグとtargetでビルドの再実行と対象ステージを明示的に制御できる
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
buildセクションとimageキーの使い分け
compose.ymlでイメージを指定する方法は2つあります。・image: Docker HubやプライベートレジストリのイメージIDを直接使う
・build: Dockerfileからイメージをビルドして使う
自分のアプリケーションをコンテナ化している場合はbuildセクションが必要です。
imageとbuildを両方指定した場合は、ビルドしたイメージにimageで指定した名前とタグが付きます。# buildとimageを併用する例 # docker compose buildでビルドしたイメージにタグが自動的に付く services: app: build: context: . image: ghcr.io/example/myapp:latest
1. buildセクションの最小構成
最もシンプルな書き方は、contextパスだけを指定するショートフォームです。# ショートフォーム:compose.ymlと同じディレクトリのDockerfileを使う services: app: build: .
build: . は context: . の省略形です。本番環境や複数チームでの共有を想定するなら、フルフォームで明示的に書くことを推奨します。# フルフォーム:各パラメータを明示する(推奨) services: app: build: context: . dockerfile: Dockerfile
contextでビルドコンテキストを指定する
contextは、Dockerfileのビルド時にDockerデーモンへ送信するファイル群(ビルドコンテキスト)のルートディレクトリを指定します。Dockerfile内の
COPYやADD命令で参照できるファイルの範囲がここで決まります。1. サブディレクトリのDockerfileを使う(モノレポ構成)
単一リポジトリに複数サービスを格納するモノレポ構成では、サービスごとにディレクトリを分けてDockerfileを配置します。# ディレクトリ構成例(モノレポ) myproject/ ├── compose.yml ├── frontend/ │ └── Dockerfile └── backend/ └── Dockerfile
# モノレポ向けcompose.yml services: frontend: build: context: ./frontend # frontendディレクトリ内のファイルがコンテキストになる dockerfile: Dockerfile # contextからの相対パスで指定 backend: build: context: ./backend dockerfile: Dockerfile
dockerfileに指定するパスはcontextからの相対パスです。contextの外側にDockerfileを配置することはできません。2. .dockerignoreでコンテキストサイズを削減する
ビルドコンテキストが大きいとデーモンへの転送だけで時間がかかります。contextと同じディレクトリに.dockerignoreを配置し、不要なファイルを除外してください。# .dockerignoreの例(node_modulesや.gitを除外する) node_modules .git *.log .env __pycache__
# ビルド前のコンテキストサイズを--progress=plainで確認する $ docker compose build --progress=plain 2>&1 | grep "build context" #1 [internal] load build context #1 transferring context: 1.23kB done # .dockerignore適用後は転送サイズが大幅に減る
argsでビルド時引数をDockerfileに渡す
argsは、DockerfileのARG命令に渡すビルド時引数を定義します。ENVと違いARGの値はビルド中にのみ存在し、コンテナ起動後の環境変数には残りません。APIキーやバージョン番号など、ビルド時だけ必要な値を外部から注入するのに使います。1. compose.ymlのargsとDockerfileのARGの対応関係
# Dockerfile側:ARGで受け取る変数名と型を定義する # デフォルト値を設定しておくとcompose.ymlからの指定がない場合のフォールバックになる ARG APP_VERSION=0.0.1 ARG BUILD_ENV=development RUN echo "Building version: ${APP_VERSION} for ${BUILD_ENV}"
# compose.yml側:Dockerfileと同じ変数名でargsに値を設定する services: app: build: context: . args: APP_VERSION: "1.2.3" BUILD_ENV: production
$ docker compose build --progress=plain #8 [3/5] RUN echo "Building version: 1.2.3 for production" #8 0.342 Building version: 1.2.3 for production #8 DONE 0.4s
2. .envファイルからargsに値を渡す
argsの値には変数展開が使えます。.envファイルに定義した変数を参照することで、機密情報をcompose.ymlに直書きせずに済みます。# .envファイル(リポジトリにはコミットしないこと) APP_VERSION=1.2.3 BUILD_ENV=production
# compose.yml:.envの変数を${}で参照する services: app: build: context: . args: APP_VERSION: ${APP_VERSION} BUILD_ENV: ${BUILD_ENV}
argsで渡す変数名はDockerfileのARG命令と完全に一致する必要があります。名前が一致しない場合はビルドで警告が出ますが、エラーにはならずDockerfile側のデフォルト値が使われます(値が渡っていないのに気づかないケースが多いので注意してください)。キャッシュ設定でビルドを高速化する
cache_fromとcache_toはBuildKitのキャッシュ機能を活用するパラメータです。CI/CDパイプラインでキャッシュをリモートレジストリに保存・再利用することで、変更のないレイヤーのビルド時間を大幅に削減できます。1. cache_fromでリモートキャッシュを参照する
cache_fromに指定したイメージをキャッシュソースとして使います。Docker Hubやプライベートレジストリのイメージのレイヤーを再利用するため、変更のない命令はスキップされます。# シンプルなimage参照形式(BuildKitが自動的にキャッシュを取り出す) services: app: build: context: . cache_from: - ghcr.io/example/myapp:latest
# ビルドログでキャッシュが使われているかを確認する $ docker compose build --progress=plain 2>&1 | grep -E "CACHED|RUN " #5 CACHED [2/5] RUN apt-get update && apt-get install -y build-essential #6 [3/5] RUN pip install -r requirements.txt # CAECHEDと表示された命令はスキップされ、RUNのみの命令は再実行されている
2. cache_toでキャッシュをレジストリに書き出す
cache_toはビルドしたキャッシュをどこに書き出すかを指定します。GitHub Container Registry(ghcr.io)やプライベートレジストリに保存しておくと、次回ビルド時にcache_fromで参照できます。# cache_fromとcache_toを組み合わせたCI/CD向け設計 services: app: build: context: . image: ghcr.io/example/myapp:latest cache_from: - type=registry,ref=ghcr.io/example/myapp:buildcache cache_to: - type=registry,ref=ghcr.io/example/myapp:buildcache,mode=max
mode=maxは全ステージのキャッシュを保存します(デフォルトのmode=minは最終ステージのみ)。マルチステージビルドではmode=maxの方が中間レイヤーも保存されるため、次回ビルドがより高速になります。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、docker compose buildのキャッシュ設計をはじめとするDockerの実践スキルを体系的に学べる講座を用意しています。
→ Dockerマスター講座の詳細はこちら >>
targetでマルチステージビルドの対象ステージを指定する
Dockerfileのマルチステージビルドを使っている場合、targetでどのステージまでビルドするかを指定できます。開発環境はdevステージ(デバッグツール入り)、本番環境はprodステージ(最小限のイメージ)とcompose.ymlで明示的に使い分けられます。
# Dockerfileのマルチステージ構成例 FROM python:3.12-slim AS base WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt FROM base AS dev # 開発用ツールを追加 RUN pip install debugpy pytest FROM base AS prod # 本番はbaseから引き継ぎ、追加ツールなしでコンパクトに COPY . . CMD ["python", "app.py"]
# compose.yml(開発用):devステージまでビルドする services: app: build: context: . target: dev volumes: - .:/app
# compose.prod.yml(本番用):prodステージでビルドする services: app: build: context: . target: prod
# 本番用設定を重ね合わせて起動する $ docker compose -f compose.yml -f compose.prod.yml up --build -d
docker compose buildの実行制御
1. --no-cacheで全レイヤーを強制再ビルドする
キャッシュが古くなっている場合や、apt-get・pip installなどで依存パッケージの最新版を取得したい場合は--no-cacheを使います。# 全サービスのキャッシュを無視して再ビルドする $ docker compose build --no-cache # 特定サービスだけ強制再ビルドする $ docker compose build --no-cache app # ビルド後にそのまま起動する場合(--buildは毎回リビルドを強制) $ docker compose up --build --no-cache -d
2. --parallelで複数サービスを並列ビルドする
サービスが複数ある場合、デフォルトでは逐次ビルドになります。--parallelフラグで並列ビルドに切り替えると、依存関係のないサービスが同時にビルドされます。# 複数サービスを並列でビルドする $ docker compose build --parallel # 並列ビルドのログは--progress=plainで各ステージを追いやすくなる $ docker compose build --parallel --progress=plain
トラブルシュート
argsの値がDockerfileに渡らない場合
最もよくある原因は、DockerfileのARG命令の位置です。FROMより前のARGはそのFROM命令にのみ適用され、FROM以降のステージでは再宣言が必要です。# NG: FROM以降でARGを再宣言していないため値が空になる ARG BASE_IMAGE=python:3.12-slim FROM ${BASE_IMAGE} RUN echo ${APP_VERSION} # → ARGがないので空になる # OK: FROM後にARGを再宣言する(compose.ymlのargsが受け取れる) ARG BASE_IMAGE=python:3.12-slim FROM ${BASE_IMAGE} ARG APP_VERSION # ← FROM後に再宣言する RUN echo ${APP_VERSION} # → compose.ymlのargsの値が入る
キャッシュが期待通りに効かない場合
apt-getやpip installなどの外部リポジトリへのアクセスは、RUN命令自体に変更がなければキャッシュが利用されます。パッケージを最新化したい場合は--no-cacheで強制再ビルドしてください。また、
COPY命令でコピーするファイルが変更されると、それ以降の命令は全てキャッシュが無効化されます。依存ファイル(requirements.txtなど)のCOPYをソースコードのCOPYより前に置く命令順序の設計が重要です。# キャッシュを活かす命令順序の設計(依存ファイルを先にCOPYする) FROM python:3.12-slim WORKDIR /app # requirements.txtだけを先にCOPYしてインストール(キャッシュが効く) COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # ソースコードは最後にCOPY(変更頻度が高いので最後に配置) COPY . . CMD ["python", "app.py"]
本記事のまとめ
compose.ymlのbuildセクションで使える主要設定と実行オプションを整理します。| やりたいこと | 設定キー / コマンド |
|---|---|
| ビルドコンテキストのルートを指定する | context: ./backend |
| 使用するDockerfileのパスを指定する | dockerfile: Dockerfile.prod |
| Dockerfileのビルド時引数を渡す | args: APP_VERSION: "1.2.3" |
| リモートキャッシュを参照してビルドを高速化する | cache_from: - ghcr.io/example/app:cache |
| ビルドキャッシュをレジストリに書き出す | cache_to: - type=registry,ref=ghcr.io/example/app:cache,mode=max |
| マルチステージビルドのステージを選択する | target: dev |
| キャッシュを無視して全レイヤーを再ビルドする | docker compose build --no-cache |
| 複数サービスを並列でビルドする | docker compose build --parallel |
argsで環境ごとにビルド時引数を切り替え、cache_from/cache_toでCI/CDのビルド時間を短縮し、targetで開発・本番のステージを明示的に使い分ける——これらを組み合わせることでDockerを使った開発・運用のボトルネックを解消できます。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、本記事で紹介したdocker compose buildのビルド設計をさらに深く学べる講座を用意しています。
→ Dockerマスター講座の詳細はこちら >>
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 前のページへ:Dockerのbind mountとtmpfsをどう使い分けるか|マウント種別ごとの性能・権限・バックアップ適性
- この記事の属するカテゴリ:Dockerへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます