Docker Composeのビルド設計|buildセクションのcontext・args・キャッシュでイメージ更新を制御する

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)Docker > Docker Composeのビルド設計|buildセクションのcontext・args・キャッシュでイメージ更新を制御する
「docker compose upするたびにイメージが更新されない」
「DockerfileのARGに値を渡したいが、compose.ymlでどう書けばいいかわからない」
Composeを使い始めると、こうしたビルド周りの疑問が必ず出てきます。

Docker Composeには、コンテナの起動設定と同じcompose.ymlの中でDockerfileからのビルドを完全に制御できるbuildセクションがあります。コンテキストパスの指定・ビルド時引数の注入・キャッシュ戦略の構成まで、imageキーで既成イメージを使うだけでは実現できない柔軟な設計が可能になります。

この記事では、buildセクションの主要パラメータであるcontextargscache_from/cache_totargetを整理し、実サーバーの確認例を交えて解説します。

動作確認環境: 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でビルドの再実行と対象ステージを明示的に制御できる


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

buildセクションとimageキーの使い分け

compose.ymlでイメージを指定する方法は2つあります。

image: Docker HubやプライベートレジストリのイメージIDを直接使う
build: Dockerfileからイメージをビルドして使う

自分のアプリケーションをコンテナ化している場合はbuildセクションが必要です。imagebuildを両方指定した場合は、ビルドしたイメージに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内のCOPYADD命令で参照できるファイルの範囲がここで決まります。

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

実際のビルドログでARGの値が正しく渡っていることを確認できます。

$ 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_fromcache_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
buildセクションを適切に設計すると、Dockerfileの変更をcompose.ymlから柔軟に制御できるようになります。
argsで環境ごとにビルド時引数を切り替え、cache_from/cache_toでCI/CDのビルド時間を短縮し、targetで開発・本番のステージを明示的に使い分ける——これらを組み合わせることでDockerを使った開発・運用のボトルネックを解消できます。

現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、本記事で紹介したdocker compose buildのビルド設計をさらに深く学べる講座を用意しています。
Dockerマスター講座の詳細はこちら >>

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。