docker-compose build の使い方:初心者向け解説

Docker Compose build の使い方:初心者向け徹底解説

はじめに

Docker は、アプリケーションをコンテナという独立した環境で実行するための強力なプラットフォームです。そして Docker Compose は、複数のコンテナで構成されるアプリケーション(例えば、Web サーバー、データベース、キャッシュサーバーなど)をまとめて定義し、管理するためのツールです。

Docker Compose を使うことで、複雑なアプリケーションの構築、実行、停止、削除といった一連の操作を、一つの設定ファイル(docker-compose.yml)を使って簡単に行えるようになります。

Docker Compose でアプリケーションを動かすためには、まず使用するコンテナの「設計図」である Docker Image を準備する必要があります。Docker Image は、Docker Hub のような公開リポジトリからダウンロードすることもできますが、多くの場合、自分たちのアプリケーションに合わせてカスタマイズした独自の Image を作成する必要があります。

この、独自の Docker Image を作成する際に中心的な役割を果たすのが、今回詳しく解説する docker-compose build コマンドです。

この記事では、Docker や Docker Compose を初めて使う方でも理解できるように、docker-compose build コマンドの基本的な使い方から、その内部で行われていること、様々なオプション、そして実践的な活用方法、さらにはトラブルシューティングまで、約5000語をかけて徹底的に解説します。

この記事を読めば、あなたは以下のことができるようになります。

  • docker-compose build コマンドが何のためにあるのかを理解する。
  • docker-compose.yml ファイルで Image をビルドする方法を定義する。
  • 基本的な docker-compose build コマンドを実行し、出力内容を理解する。
  • さまざまなオプションを使って、ビルドをカスタマイズ・制御する。
  • 特定のサービスだけをビルドしたり、ビルド引数を渡したりする方法を学ぶ。
  • ビルドキャッシュの仕組みを理解し、効率的なビルドを行うためのヒントを得る。
  • ビルド時の一般的な問題に対処できるようになる。
  • より実践的な Dockerfile や Docker Compose の書き方を知る。

さあ、Docker Compose を使った Image ビルドの世界へ飛び込みましょう!

Docker と Docker Compose の基本(超初心者向け)

docker-compose build を理解するためには、まず Docker と Docker Compose の基本的な考え方を抑えておくことが重要です。

Docker とは何か?

Docker は、アプリケーションとその実行に必要なすべてのもの(ライブラリ、フレームワーク、設定ファイルなど)を一つにまとめて「コンテナ」という形で提供するプラットフォームです。

  • コンテナ: アプリケーションを分離して実行するための軽量な仮想化技術です。OS 全体を仮想化する従来の仮想マシン(VMware, VirtualBox など)とは異なり、ホストOS のカーネルを共有するため、起動が速く、リソース消費も少ないのが特徴です。コンテナは、どこでも同じように実行できるポータブルな環境を提供します。
  • Docker Image: コンテナを実行するための「設計図」であり、ファイルシステムの構成、実行するプログラム、設定などが含まれています。Image は不変(Immutable)であり、一度作成されると変更できません。Image からコンテナを「生成」して実行します。
  • Dockerfile: Docker Image を作成するための手順を記述したテキストファイルです。「FROM (ベースイメージを指定)」「COPY (ファイルをコピー)」「RUN (コマンドを実行)」などの命令を順番に記述します。Docker Engine はこの Dockerfile を読み込み、ステップごとに実行して Docker Image をビルド(構築)します。
  • Docker Engine: Docker Image をビルドしたり、コンテナを実行したりする中心的なプログラムです。CLI コマンド(docker build, docker run, docker ps など)を受け付け、実際の処理を行います。

要するに、私たちは Dockerfile を書いて Docker Engine に渡すことで Docker Image をビルドし、その Image から コンテナ を起動してアプリケーションを実行する、というのが Docker の基本的な流れです。

Docker Compose とは何か?

単一のコンテナで完結するシンプルなアプリケーションもたくさんありますが、多くの実用的なアプリケーションは複数のコンポーネント(例: Web アプリ、データベース、API サーバー、キュー)で構成されています。これらのコンポーネントはそれぞれ異なるコンテナで実行されることが一般的です。

例えば、Python の Web アプリケーションを動かすには、Python アプリケーションを動かすコンテナと、データを保存するための PostgreSQL データベースコンテナ、さらにキャッシュとして Redis コンテナが必要になるかもしれません。これら3つのコンテナを個別に管理するのは手間がかかります。

Docker Compose は、このように複数の関連するコンテナ(サービス)をまとめて定義し、管理するためのツールです。

  • docker-compose.yml: Docker Compose が使う設定ファイルです。YAML 形式で記述され、アプリケーションを構成する各サービス(コンテナ)の名前、使用する Docker Image、ポートマッピング、ボリュームマッピング、環境変数、サービス間の依存関係などを定義します。

docker-compose.yml ファイルを用意すれば、docker-compose up コマンド一つで、定義されたすべてのサービスをまとめて起動したり、停止したり、削除したりといった操作が可能になります。手作業で個別の docker run コマンドを何回も実行する必要がなくなります。

Docker Compose は、開発環境の構築や、本番環境でのアプリケーションデプロイを効率化するための強力なツールなのです。

docker-compose.yml ファイルの基本構造(build に関連する部分にフォーカス)

docker-compose build コマンドを使うには、まず docker-compose.yml ファイルで、どのサービスに対してどのような方法で Docker Image をビルドするかを定義する必要があります。

docker-compose.yml ファイルの基本的な構造は以下のようになります。

“`yaml
version: ‘3.8’ # Compose ファイルフォーマットのバージョンを指定

services: # アプリケーションを構成するサービスを定義するセクション
web: # サービス名(任意)
# このサービスのコンテナに使用する Docker Image を指定する方法は2通り
# 1. 既存のイメージを使う場合: image: ‘nginx:latest’
# 2. Dockerfile から自分でビルドする場合:
build:
context: . # Dockerfile やビルドに必要なファイルがあるディレクトリを指定
dockerfile: Dockerfile # Dockerfile のファイル名を指定 (デフォルトは ‘./Dockerfile’)
args: # ビルド引数を渡す場合
APP_VERSION: ‘1.0’
# cache_from: # キャッシュ元を指定 (応用)
# target: # マルチステージビルドのターゲットを指定 (応用)
ports: # ホストとコンテナ間のポートマッピング
– “80:80”
volumes: # ホストとコンテナ間のボリュームマッピング
– ./html:/usr/share/nginx/html
depends_on: # サービス間の依存関係
– app

app: # 別のサービス(例: アプリケーション本体)
build:
context: ./app
dockerfile: Dockerfile.app
ports:
– “5000:5000”
volumes:
– ./app:/app
environment: # 環境変数
DATABASE_URL: ‘postgresql://user:password@db:5432/mydb’

db: # データベースサービス
image: ‘postgres:13’ # このサービスは既存のイメージを使用
volumes:
– db_data:/var/lib/postgresql/data

volumes: # 永続化するボリュームの定義
db_data:
“`

このファイルの中で、docker-compose build コマンドに最も関連が深いのは、各サービス定義の中にある build キーです。

image vs build

サービス定義において、そのサービスに使用する Docker Image を指定する方法は主に以下の2つです。

  1. image キーを使う:

    • すでに Docker Hub やプライベートレジストリに存在する Docker Image を利用する場合に使います。
    • 例: image: 'nginx:latest' (Docker Hub から nginx:latest イメージをプルして使用)
    • この場合、docker-compose build コマンドを実行しても、このサービスに対しては何も行われません(ビルドする必要がないため)。docker-compose pull でイメージを取得します。
  2. build キーを使う:

    • ローカルの Dockerfile から独自の Docker Image をビルドして利用する場合に使います。
    • 例: 上記の web サービスや app サービスのように定義します。
    • この場合、docker-compose build コマンドを実行すると、このサービス定義に基づいて Docker Image がビルドされます。

build キーを使うことで、アプリケーションのソースコードや必要な設定を含んだ、オリジナルの Docker Image を作成できます。これが docker-compose build コマンドが活躍する場面です。

build キーの詳細

build キーの下には、Image をビルドするための様々な設定を記述できます。

  • context (必須):

    • 意味: Docker ビルドを実行する際に、Dockerfile とともに Docker Engine に送信されるローカルファイル群のパス(ビルドコンテキスト)を指定します。通常は、Dockerfile が置いてあるディレクトリ、またはその親ディレクトリを指定します。
    • 重要性: Dockerfile の COPYADD 命令は、この context で指定されたディレクトリからの相対パスでファイルを指定します。もし context: . (カレントディレクトリ) と指定した場合、DockerfileCOPY ./app /app と書くと、カレントディレクトリ直下の app ディレクトリの内容がイメージにコピーされます。
    • 注意: 必要のないファイル(大きなデータファイル、Git リポジトリ情報、ビルド生成物など)がコンテキストに含まれると、ビルド速度が遅くなったり、不要な情報がイメージに含まれたりする可能性があります。.dockerignore ファイルを使って、コンテキストに含めないファイルを指定することが推奨されます。
    • 指定方法: ローカルファイルシステムのパス(例: ../app/path/to/docker/dir)または Git リポジトリの URL を指定できます(後者は応用)。
  • dockerfile (任意):

    • 意味: context で指定したディレクトリ内にある、使用する Dockerfile のファイル名を指定します。
    • デフォルト: 指定しない場合、デフォルトで context ディレクトリ直下の Dockerfile というファイルが使用されます。
    • 指定方法: ファイル名(例: Dockerfile.app./prod/Dockerfile)。context からの相対パスで指定します。
  • args (任意):

    • 意味: Dockerfile 内の ARG 命令で定義されたビルド時変数に値を渡すために使用します。ビルド中に動的に値を変更したい場合(例: アプリケーションのバージョン番号、ダウンロードするパッケージのバージョン)に便利です。
    • 指定方法: キーバリュー形式でリストまたはマップとして指定します。
      “`yaml
      args:

      • APP_VERSION=1.0.0
      • BUILD_DATE=2023-10-27

      または

      args:
      APP_VERSION: 1.0.0
      BUILD_DATE: 2023-10-27
      “`

    • これらの値は、Dockerfile の ARG 命令で受け取ります。
      dockerfile
      # Dockerfile
      ARG APP_VERSION
      ARG BUILD_DATE
      LABEL version=$APP_VERSION build_date=$BUILD_DATE
      ...
    • docker-compose build コマンド実行時にも --build-arg オプションで値を上書きできます。
  • cache_from (任意):

    • 意味: ビルドキャッシュとして利用する既存のイメージを指定します。これにより、リモートリポジトリにあるイメージをキャッシュとして活用し、ビルド時間を短縮できます。特に CI/CD 環境などで有効です。
    • 指定方法: イメージ名のリストを指定します。
      “`yaml
      cache_from:

      • ‘your-registry/your-image:latest’
      • ‘ubuntu:latest’
        “`
    • この機能は、BuildKit という新しいビルドバックエンドでより強力に機能します。
  • labels (任意):

    • 意味: ビルドされる Docker Image にメタデータ(ラベル)を付与します。バージョン情報、作成者、ライセンス情報などを埋め込むのに便利です。
    • 指定方法: キーバリュー形式のマップとして指定します。
      yaml
      labels:
      maintainer: "Your Name <[email protected]>"
      version: "1.0"
      org.opencontainers.image.licenses: "MIT"
    • これらのラベルは docker image inspect <image_id> コマンドなどで確認できます。
  • target (任意):

    • 意味: Dockerfile でマルチステージビルドを行っている場合に、最終的にビルドするステージ(ターゲット)を指定します。
    • 例:
      “`dockerfile
      # Dockerfile
      FROM node:18 as builder # ビルダーステージ
      WORKDIR /app
      COPY package*.json ./
      RUN npm ci
      COPY . .
      RUN npm run build # アプリをビルド

      FROM nginx:alpine as production # 本番用ステージ
      COPY –from=builder /app/dist /usr/share/nginx/html # ビルダーステージから成果物をコピー
      COPY nginx.conf /etc/nginx/nginx.conf
      CMD [“nginx”, “-g”, “daemon off;”]
      この Dockerfile で本番用イメージだけをビルドしたい場合、`docker-compose.yml` に以下のように記述します。yaml
      services:
      web:
      build:
      context: .
      dockerfile: Dockerfile
      target: production # production ステージのみビルドする
      ports:
      – “80:80”
      “`
      * これにより、ビルダーステージでインストールした大量の開発ツールやソースコードが最終イメージに含まれるのを防ぎ、イメージサイズを小さく保つことができます。

これらの build キー配下の設定を適切に使うことで、あなたのアプリケーションに最適な Docker Image を効率的にビルドできるようになります。

docker-compose build コマンドの基本

docker-compose.yml ファイルでサービスの build 設定が完了したら、いよいよ docker-compose build コマンドを使って Docker Image をビルドします。

コマンドの書式

bash
docker-compose build [OPTIONS] [SERVICE...]

  • [OPTIONS]: 後述する様々なオプションを指定します。
  • [SERVICE...]: オプションで、ビルドしたいサービス名を指定します。省略した場合、docker-compose.yml ファイル内で build キーが定義されているすべてのサービスの Image がビルドされます。

何をするコマンドか?

docker-compose build コマンドを実行すると、Docker Compose は以下の処理を行います。

  1. カレントディレクトリ、または指定された Compose ファイル(-f オプションなどで指定した場合)内の docker-compose.yml ファイルを読み込みます。
  2. ファイル内で定義されているサービスの中から、build キーが指定されているサービス、またはコマンドラインで指定されたサービスの定義を探します。
  3. それぞれのサービス定義にある build 設定(context, dockerfile, args など)を確認します。
  4. 各サービスに対して、指定された context を Docker Engine にビルドコンテキストとして送信します(.dockerignore があれば考慮されます)。
  5. 指定された dockerfile(またはデフォルトの Dockerfile)を使って、Docker Engine に Image のビルドを指示します。このビルドプロセスは、通常の docker build コマンドで行われることと同じです。
  6. ビルドが成功すると、Docker Compose はサービス名と関連付けられたタグ(例: myproject_web, myproject_app のような形式)を Image に自動で付けます。これにより、後続の docker-compose up コマンドなどで、このビルドされた Image を簡単に参照できるようになります。
  7. ビルドの進捗や結果がコンソールに出力されます。

docker build との違い

docker-compose build は、内部的に docker build コマンドを呼び出していますが、単に docker build を実行するのとはいくつかの違いがあります。

  • 複数のサービスを一括管理: docker-compose.yml ファイルを見ることで、複数のサービスの Image ビルドをコマンド一つで実行できます。各サービスに対して個別に docker build コマンドを実行する必要がありません。
  • 設定の一元化: ビルドに関する設定(コンテキストパス、Dockerfile 名、ビルド引数など)を docker-compose.yml ファイルに記述しておけます。これにより、ビルド手順が文書化され、チーム内で共有しやすくなります。
  • 自動的なタグ付け: Docker Compose は通常、プロジェクト名とサービス名を組み合わせた形式で Image にタグを自動で付けます。これにより、Compose プロジェクト内でどのサービスがどの Image を使うかが明確になります。
  • サービス間の連携: docker-compose.yml にはサービス間の依存関係やネットワーク設定なども記述されていますが、build コマンド自体は Image をビルドするだけで、依存関係に基づいてビルド順序を調整したりはしません(ただし、後述の up --build は依存関係を考慮します)。

基本的な実行例

最も基本的な docker-compose build コマンドの実行例です。

  1. プロジェクトディレクトリに移動します。
  2. docker-compose.yml ファイルと、各サービスが必要とする Dockerfile やソースコードが配置されていることを確認します。
  3. 以下のコマンドを実行します。

bash
docker-compose build

このコマンドは、docker-compose.yml ファイルに build キーが設定されているすべてのサービスの Image をビルドします。

もし特定のサービスだけをビルドしたい場合は、サービス名を指定します。

bash
docker-compose build web app # web と app サービスのみビルド

ビルドが開始されると、各サービスのビルドプロセスが順番に(または並行して、Compose バージョンや設定による)実行され、docker build と同様の出力が表示されます。各ステップ(Dockerfile の各命令)が実行されるたびに、その進捗と結果が示されます。

成功すると、「Successfully built 」のようなメッセージが表示され、ビルドされた Image には自動でタグが付けられていることが確認できます。

例: docker image ls コマンドで確認すると、myproject_webmyproject_app のようなタグが付いた Image が見つかるはずです(myproject はカレントディレクトリ名などから自動で決まるプロジェクト名)。

“`bash
$ docker-compose build
[+] Building 2.0s (10/10) FINISHED
=> [web internal] load build definition from Dockerfile
=> => transferring dockerfile: 32B
=> [web internal] load .dockerignore
=> => transferring context: 34B
=> [web internal] load metadata for docker.io/library/nginx:alpine
=> [web 1/3] FROM docker.io/library/nginx:alpine
=> [web internal] load build context
=> => transferring context: 1.21kB
=> [web 2/3] COPY html /usr/share/nginx/html
=> [web 3/3] COPY nginx.conf /etc/nginx/nginx.conf
=> [web] Exporting fs layers
=> => exporting layers
=> => writing image sha256:xxxxxxxxxxxxxxx
=> => naming to docker.io/library/myproject_web:latest

[+] Building 3.5s (12/12) FINISHED
=> [app internal] load build definition from Dockerfile.app
=> => transferring dockerfile: 38B
=> [app internal] load .dockerignore
=> => transferring context: 45B
=> [app internal] load metadata for docker.io/library/python:3.9-slim
=> [app 1/7] FROM docker.io/library/python:3.9-slim
=> [app internal] load build context
=> => transferring context: 5.67kB
=> [app 2/7] WORKDIR /app
=> [app 3/7] COPY requirements.txt ./
=> [app 4/7] RUN pip install –no-cache-dir -r requirements.txt
=> [app 5/7] COPY . .
=> [app 6/7] EXPOSE 5000
=> [app 7/7] CMD [“python”, “app.py”]
=> [app] Exporting fs layers
=> => exporting layers
=> => writing image sha256:yyyyyyyyyyyyyyy
=> => naming to docker.io/library/myproject_app:latest
“`

上記の例は、Compose V2 のビルド出力例です。ステップごとの詳細な情報と、最後に成功した Image ID が表示されます。

docker-compose build コマンドの詳細オプション

docker-compose build コマンドには、ビルドプロセスをより細かく制御するための様々なオプションが用意されています。ここでは主なオプションを紹介します。

--help, -h

コマンドの使い方やオプションリストを表示します。
bash
docker-compose build --help

--compress

ビルドコンテキスト(Dockerfile と一緒に送信されるファイル群)を Docker Engine に送信する際に gzip で圧縮します。コンテキストが非常に大きい場合に、ネットワーク転送時間を短縮できる可能性があります。

bash
docker-compose build --compress

--force-rm

ビルドプロセス中に作成される中間コンテナ(Dockerfile の各 RUN 命令などが実行される際に一時的に作成されるコンテナ)を、ビルド成功後でも強制的に削除します。通常、エラーが発生した場合にデバッグのために中間コンテナが残されることがありますが、このオプションを使うと成功・失敗に関わらずクリーンアップされます。ディスクスペースを節約したい場合に有用ですが、デバッグが少し難しくなることがあります。

bash
docker-compose build --force-rm

--no-cache

Image ビルド時に、既存のビルドキャッシュを一切使用しません。Dockerfile の各ステップはすべて最初から実行されます。

bash
docker-compose build --no-cache

  • いつ使うか?
    • ビルドキャッシュが原因で予期しない動作(例: 新しいファイルがコピーされない、古い依存関係が使われる)が発生していると思われる場合。
    • クリーンな状態で Image をビルドしたい場合(例: 本番環境用の Image をビルドする際)。
    • Dockerfile やソースコードを大幅に変更し、キャッシュがほとんど役に立たないと考えられる場合。
  • 注意点: --no-cache を使うと、ビルド時間が大幅に長くなる可能性があります。通常の開発中はキャッシュを活用するのが効率的です。

--pull

Image ビルドの前に、Dockerfile の FROM 命令で指定されているベースイメージを常に最新版としてプル(ダウンロード)します。

bash
docker-compose build --pull

  • いつ使うか?
    • ベースイメージ(例: ubuntu:latest, python:3.9) が頻繁に更新され、常に最新の状態からビルドを開始したい場合。
  • 注意点: ベースイメージのタグに :latest のような「可変」なタグを使っている場合、このオプションを使うと意図せずベースイメージが変更され、ビルド結果が変わる可能性があります。特定のバージョン(例: ubuntu:22.04, python:3.9.18) を指定している場合は、そのバージョンがローカルに存在しない場合にのみプルが行われます。再現性を重視する場合は、可変タグの使用は避け、固定バージョンを指定し、必要に応じて手動でプルするのが安全です。

--quiet, -q

ビルドプロセスの詳細な出力を抑制し、最終的な Image ID のみを表示します。CI/CD 環境など、ログが大量になるのを避けたい場合に便利です。

bash
docker-compose build -q

--parallel (Compose V2 以降推奨)

docker-compose.yml で定義されている複数のサービスを並行してビルドします。これにより、ビルド時間が短縮される可能性があります(ただし、サービスの数やシステムリソースによります)。Compose V2 以降ではデフォルトで並行ビルドが有効になっていることが多いですが、明示的に指定することもできます。

bash
docker-compose build --parallel # 明示的に並行ビルドを有効にする

--no-parallel (Compose V1 の場合)

Compose V1 では、デフォルトで並行ビルドが行われるため、それを無効にしてサービスを順番にビルドしたい場合にこのオプションを使いました。Compose V2 では --parallel がデフォルトまたは推奨のため、あまり使いません。

“`bash

Compose V1 の場合

docker-compose build –no-parallel
“`

--build-arg key=value

docker-compose.ymlbuild.args で指定したビルド引数の値を、コマンドラインから上書き、または追加します。複数の引数を渡す場合は、オプションを複数回指定します。

“`bash

docker-compose.yml の args を上書きまたは追加

docker-compose build –build-arg APP_VERSION=1.1.0 –build-arg ENVIRONMENT=production app
“`

このオプションで指定された値は、docker-compose.yml で同じ名前の引数が定義されていればその値を上書きし、定義されていなければ新しい引数として渡されます(Dockerfile で ARG で受け取っている必要があります)。

リソース制限オプション (--memory, --memswap, --cpu-shares, etc.)

これらのオプションは、ビルドプロセス自体(具体的には、Dockerfile の RUN 命令などが実行される際の一時的なコンテナ)が使用できるシステムリソースを制限します。ビルドホストのリソースが限られている場合や、特定のビルドがリソースを過剰に消費するのを防ぎたい場合に利用できます。これらは Docker Engine のビルドオプションを Compose 経由で渡しているものです。

  • --memory SIZE: ビルドコンテナが使用できるメモリの最大値を設定します(例: --memory 1g, --memory 512m)。
  • --memswap SIZE: メモリとスワップ領域を合わせた最大値を設定します。-1 を指定すると、メモリ制限のみが適用され、スワップは無制限になります。
  • --cpu-shares SHARES: CPU の使用率の相対的な重みを設定します(デフォルトは 1024)。数値が大きいほど、他のコンテナと比較して多くの CPU 時間が割り当てられやすくなります。
  • --cpu-period PERIOD, --cpu-quota QUOTA: CPU 使用率を絶対値で制限します。--cpu-period を 100000 (1秒) とした場合、--cpu-quota を 50000 に設定すると、そのコンテナは CPU 時間の最大 50% を使用できます。
  • --cpuset-cpus CPUS: ビルドコンテナを実行する CPU コアを指定します(例: --cpuset-cpus 0,1, --cpuset-cpus 0-3)。
  • --shm-size SIZE: /dev/shm のサイズを設定します。特定のアプリケーション(例: 一部のビルドツール)が共有メモリを大量に使う場合に必要になることがあります(例: --shm-size 2g)。

これらのリソース制限オプションは、主にビルドホストの安定性を保つために使用され、ビルドされる最終イメージに影響を与えるものではありません。

--progress string (Compose V2 以降)

ビルドの進捗表示の形式を指定します。

  • auto: 環境に応じて ‘tty’ または ‘plain’ を自動選択します。
  • plain: 進捗がテキスト形式で表示されます。これは、CI/CD 環境などでログをファイルに保存する場合や、非対話的な環境で便利です。
  • tty: 対話的なターミナルに適した、リッチな表示形式です(デフォルト)。

bash
docker-compose build --progress plain

--ssh string (Compose V2 以降)

BuildKit が SSH エージェントに接続して、ビルド中にリモートリソース(プライベート Git リポジトリなど)にアクセスできるようにします。これは Dockerfile の RUN --mount=type=ssh ... 命令と組み合わせて使用します。

“`bash

ローカルのSSHエージェントに接続を許可

docker-compose build –ssh default web
“`

このオプションは、SSH 経由でコードをクローンしたり、プライベートパッケージをインストールしたりするビルドステップがある場合に便利です。

実践的な使い方とシナリオ

ここでは、より具体的なシナリオを通して docker-compose build コマンドの使い方を見ていきましょう。

シナリオ1:初めてのビルド

簡単な Node.js アプリケーションを例に、初めてビルドする手順を解説します。

ディレクトリ構成:
my-node-app/
├── docker-compose.yml
├── app/
│ ├── Dockerfile
│ ├── package.json
│ └── server.js
└── nginx/
├── Dockerfile
└── nginx.conf

app/package.json:
json
{
"name": "my-node-app",
"version": "1.0.0",
"description": "A simple node app",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"dependencies": {
"express": "^4.17.1"
}
}

app/server.js:
“`javascript
const express = require(‘express’);
const app = express();
const port = 3000;

app.get(‘/’, (req, res) => {
res.send(‘Hello from Node.js App!’);
});

app.listen(port, () => {
console.log(App listening at http://localhost:${port});
});
“`

app/Dockerfile:
“`dockerfile

ベースイメージの指定

FROM node:18-alpine

作業ディレクトリの設定

WORKDIR /app

package.json と package-lock.json をコピー

これらを先にコピーして依存関係をインストールすることで、

ソースコードの変更があっても依存関係のインストールステップがキャッシュされやすくなる

COPY package*.json ./

依存関係のインストール

RUN npm install

アプリケーションのソースコードをコピー

COPY . .

アプリケーションが待ち受けるポートを指定 (ドキュメント用)

EXPOSE 3000

コンテナ起動時に実行されるコマンド

CMD [“npm”, “start”]
“`

nginx/Dockerfile:
“`dockerfile

ベースイメージ

FROM nginx:alpine

カスタム設定ファイルをコピー

COPY nginx.conf /etc/nginx/nginx.conf

デフォルトのindex.htmlを削除し、静的コンテンツディレクトリを作成

RUN rm /usr/share/nginx/html/index.html
RUN mkdir /usr/share/nginx/html/static

静的ファイルをコピーする場合(例)

COPY static/ /usr/share/nginx/html/static/

デフォルトのポート80を公開

EXPOSE 80

CMDはベースイメージで設定済みなので不要

“`

nginx/nginx.conf: (簡単な設定例)
“`nginx
events {
worker_connections 1024;
}

http {
server {
listen 80;
server_name localhost;

    location / {
        # リクエストを Node.js アプリコンテナに転送
        proxy_pass http://app:3000; # 'app' は docker-compose.yml で定義するサービス名
    }

    location /static/ {
        # 静的ファイルは Nginx が直接配信
        root /usr/share/nginx/html;
    }
}

}
“`

docker-compose.yml:
“`yaml
version: ‘3.8’

services:
app:
build:
context: ./app # app サービスのビルドコンテキストは ./app ディレクトリ
dockerfile: Dockerfile # ./app/Dockerfile を使用
ports:
– “3000:3000” # 開発中は直接アクセスできるようにポートを公開
volumes:
– ./app:/app # ソースコードをマウント(開発中のホットリロード用)
– /app/node_modules # node_modules はマウントしない(コンテナ内でインストールしたものを使う)

nginx:
build:
context: ./nginx # nginx サービスのビルドコンテキストは ./nginx ディレクトリ
dockerfile: Dockerfile # ./nginx/Dockerfile を使用
ports:
– “80:80” # Nginx が待ち受けるポートをホストの80番ポートにマッピング
# static ディレクトリをマウントする場合
# volumes:
# – ./nginx/static:/usr/share/nginx/html/static
depends_on: # app サービスが起動してから nginx サービスを起動する
– app
“`

ビルドの実行:

my-node-app ディレクトリに移動し、以下のコマンドを実行します。

bash
cd my-node-app
docker-compose build

Docker Compose は docker-compose.yml を読み込み、app サービスと nginx サービスの build 設定を見つけます。

  1. まず app サービスのビルドが開始されます。context: ./app なので、./app ディレクトリ以下のファイルがビルドコンテキストとして Docker Engine に送られます。dockerfile: Dockerfile なので、./app/Dockerfile の内容に従って Image がビルドされます。
  2. 次に nginx サービスのビルドが開始されます。context: ./nginx なので、./nginx ディレクトリ以下のファイルがコンテキストとして送られ、./nginx/Dockerfile に従って Image がビルドされます。

ビルドの進捗がコンソールに表示され、各 RUN, COPY などのステップが実行されていく様子がわかります。

成功すると、以下のような Image が作成されていることを確認できます(プロジェクト名が my-node-app の場合)。

bash
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
my-node-app_app latest <app_image_id> X minutes ago XXXMB
my-node-app_nginx latest <nginx_image_id> X minutes ago XXMB
... (ベースイメージなど)

これで、アプリケーションを実行するためのカスタム Docker Image が準備できました。次は docker-compose up コマンドでこれらの Image を使ってコンテナを起動できます。

シナリオ2:Dockerfile やソースコードの変更と再ビルド

アプリケーション開発では、頻繁にソースコードや Dockerfile を変更します。変更後、どのように Image を再ビルドすればよいでしょうか?

  • ソースコード (server.js など) を変更した場合:
    DockerfileCOPY . . ステップ以降のキャッシュが無効になります。COPY より前のステップ(ベースイメージの指定、依存関係のインストールなど)に変更がなければ、その部分はキャッシュが使われるため、ビルドは比較的速く完了します。
    この場合も、単に docker-compose build を再度実行すればOKです。Compose は変更を検知し、キャッシュが利用できる部分はスキップしてくれます。

  • package.json (依存関係) を変更した場合:
    DockerfileCOPY package*.json ./ ステップ以降のキャッシュが無効になります。特に RUN npm install のステップは必ず再実行され、新しい依存関係がインストールされます。これも docker-compose build を実行すれば自動的に処理されます。

  • Dockerfile を変更した場合:
    変更した命令以降のステップのキャッシュが無効になります。例えば、新しい RUN 命令を追加したり、既存の命令の順番を変えたりした場合、その変更がキャッシュキーに影響を与え、キャッシュが使われなくなります。もちろん、docker-compose build コマンドで変更が反映されます。

再ビルドの実行:

“`bash

ソースコードなどを変更した後

docker-compose build app # 特定のサービスだけ再ビルドする場合

または

docker-compose build # すべてのサービスを再ビルドする場合
“`

Compose は賢くキャッシュを利用してくれるため、変更があった部分だけが再実行されるのが一般的です。

シナリオ3:ビルドキャッシュを使わないクリーンビルド

前述の --no-cache オプションを使います。何らかの問題が発生している場合や、本番リリース用の Image をビルドする場合などに使用します。

“`bash
docker-compose build –no-cache app # app サービスのみキャッシュなしでビルド

または

docker-compose build –no-cache # すべてのサービスをキャッシュなしでビルド
“`

これにより、すべてのビルドステップが最初からやり直されるため、時間がかかりますが、最も確実な方法です。

シナリオ4:特定のサービスのみビルド

アプリケーションに複数のサービスがあり、そのうち一部だけ Image を再ビルドしたい場合。

bash
docker-compose build web # web サービスのみビルド
docker-compose build app db # app と db サービスをビルド (db が image でなく build 定義なら)

コマンドの最後にビルドしたいサービス名を指定するだけです。依存関係はビルド時には考慮されませんが(Image があるかどうかは関係なくビルド自体を実行)、docker-compose up --build の場合は依存関係を見て起動順序などが調整されます。

シナリオ5:ビルド引数 (args) の活用

アプリケーションのバージョン番号を Image に埋め込みたい、開発環境と本番環境で異なる設定をビルド時に渡したい、といった場合にビルド引数が役立ちます。

app/Dockerfile:
“`dockerfile
FROM node:18-alpine
ARG APP_VERSION=”development” # デフォルト値を指定
ARG BUILD_ENV=”development”

WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .

アプリケーションのバージョン情報をファイルに書き出す例

RUN echo “Version: ${APP_VERSION}, Environment: ${BUILD_ENV}” > /app/version.txt

EXPOSE 3000
CMD [“npm”, “start”]
“`

docker-compose.yml:
“`yaml
version: ‘3.8’

services:
app:
build:
context: ./app
dockerfile: Dockerfile
args: # docker-compose.yml でデフォルト値を指定
APP_VERSION: ‘1.0.0’
BUILD_ENV: ‘staging’ # デフォルトは staging としておく
# … 他の設定
“`

ビルド引数を指定してビルド:

“`bash

docker-compose.yml のデフォルト値 (APP_VERSION=1.0.0, BUILD_ENV=staging) でビルド

docker-compose build app

コマンドラインオプションで上書きしてビルド (APP_VERSION=1.1.0, BUILD_ENV=production)

docker-compose build –build-arg APP_VERSION=1.1.0 –build-arg BUILD_ENV=production app

コマンドラインオプションで追加の引数を渡す(DockerfileでARGで受け取っている必要あり)

docker-compose.yml に BUILD_USER がなくても渡せる

docker-compose build –build-arg BUILD_USER=me app
“`

ビルド後に Image 内の /app/version.txt を確認すると、渡した引数の値が反映されていることがわかります。

ビルド引数は、環境ごとに異なる設定ファイルを選択してコピーしたり、特定のフラグを立てたり、インストールするパッケージのバージョンを制御したり、といった高度な用途にも利用できます。

シナリオ6:マルチステージビルドとの連携 (target)

前述の nginx サービスの例で、もし静的ファイルをコピーするステップがあり、そのファイルを何らかのビルドプロセス(例: Webpack, Gulp など)で生成する必要がある場合、マルチステージビルドが有効です。

Dockerfile (nginx 用 – マルチステージ化):
“`dockerfile

Stage 1: アセットビルドステージ

FROM node:18-alpine as asset_builder # asset_builder という名前を付ける
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build-assets # 静的ファイルを生成するスクリプトを実行 (例: dist ディレクトリに生成される)

Stage 2: 最終的な Nginx イメージステージ (軽量)

FROM nginx:alpine as production # production という名前を付ける

asset_builder ステージからビルド成果物をコピー

COPY –from=asset_builder /app/dist /usr/share/nginx/html/static/

カスタム設定ファイルをコピー

COPY nginx.conf /etc/nginx/nginx.conf

… 他の設定

“`

docker-compose.yml:
“`yaml
version: ‘3.8’

services:
nginx:
build:
context: ./nginx
dockerfile: Dockerfile
target: production # production ステージのみを最終イメージとする
ports:
– “80:80”
# … 他の設定
“`

ビルドの実行:

bash
docker-compose build nginx

このコマンドを実行すると、Docker Engine は Dockerfile 全体を解析し、production ステージをビルドするために必要な asset_builder ステージも自動的にビルドします。しかし、最終的に Image として保存されるのは production ステージの結果のみになります。asset_builder ステージで使用したビルドツールや中間ファイルは最終イメージに含まれないため、Image サイズを小さく保てます。

もし開発中に asset_builder ステージだけをテストしたい場合などがあれば、一時的に target: asset_builder に変更してビルドすることも可能です。

トラブルシューティング

docker-compose build コマンドの実行中にエラーが発生した場合、原因と対処法を知っておくと迅速に解決できます。

ビルドエラーが発生した場合の確認点

ビルドエラーが発生すると、通常はエラーが発生した Dockerfile のステップ番号と、そのステップで実行された命令が表示されます。エラーメッセージをよく読んで、何が問題なのかを特定することが重要です。

  • Dockerfile の構文エラー:

    • unknown instruction, invalid argument などのメッセージが表示されます。
    • Dockerfile の記述ミス(命令のスペルミス、不正な引数、形式の誤りなど)を確認します。各命令の正しい使い方を Dockerfile の公式ドキュメントで参照しましょう。
    • YAML インデントなどの問題は docker-compose.yml ではなく Dockerfile 自体の問題として現れます。
  • ファイルが見つからない (COPYADD 命令):

    • failed to compute cache key: ... no such file or directory のようなメッセージが表示されます。
    • DockerfileCOPYADD 命令で指定したファイルのパスが、docker-compose.ymlbuild.context で指定したディレクトリからの相対パスとして正しいか確認します。
    • ビルドコンテキストとして送られているか確認します。context ディレクトリ内に目的のファイルが存在するか、.dockerignore で除外されていないか確認します。
  • コマンド実行エラー (RUN 命令):

    • The command '/bin/sh -c ...' returned a non-zero code: <エラーコード> のようなメッセージが表示されます。
    • RUN 命令で実行しているコマンド自体に問題があります。
    • コマンドのスペルミス、引数の間違い、必要なファイルやコマンドがコンテナイメージ内に存在しない、ネットワークの問題(apt-get updatenpm install でパッケージダウンロードに失敗)、パーミッションの問題などが考えられます。
    • エラーが発生した直前のステップまでで中間イメージが作成されている場合、そのイメージからコンテナを起動して、手動でコマンドを実行してみると原因を特定しやすいです。例えば、エラーが RUN npm install で発生したら、その直前の COPY package*.json まで実行された中間イメージを使って docker run -it <intermediate_image_id> bash のようにコンテナに入り、手動で npm install を実行してみます。
  • リソース不足:

    • no space left on device (ディスク容量不足)、out of memory (メモリ不足) など。
    • ビルドホストのディスク容量やメモリが不足している可能性があります。不要な Docker Image やコンテナを削除するか、ビルド時にリソース制限オプションを試すか、よりリソースの多いホストでビルドします。

--no-cache を試す

上記のような特定のエラーメッセージが出ないものの、なぜかビルドがうまくいかない、期待通りの結果にならない、という場合は、ビルドキャッシュが悪影響を与えている可能性があります。docker-compose build --no-cache を実行して、キャッシュを使わないクリーンなビルドを試してみてください。時間がかかりますが、問題がキャッシュにあるのか、Dockerfile やコード自体にあるのかを切り分けるのに役立ちます。

詳細出力を見る

デフォルトのビルド出力はかなり詳細ですが、-q オプションを使っている場合はそれを外します。より詳細なデバッグ情報を得るためには、Dockerfile の各 RUN 命令の前に set -eux を追記して、実行されたコマンドとエラーコードを明示的に表示させるなどのテクニックもあります。

Compose ファイルや Dockerfile のパスを確認

docker-compose.ymlbuild.contextbuild.dockerfile のパス指定が正しいか、また Dockerfile 内の COPYADD 命令のパス指定が context からの相対パスとして正しいか、改めて確認します。

Docker Engine の状態確認

Docker Engine 自体が正常に動作しているか確認します。docker info, docker version などのコマンドを実行したり、Docker デーモンを再起動したりしてみることも有効です。

build コマンドの注意点とベストプラクティス

docker-compose build コマンドを効果的に使うために、いくつかの注意点とベストプラクティスがあります。

ビルドコンテキスト (context) の範囲

  • 必要最低限のファイルだけを含める: build.context で指定したディレクトリ内のファイルは、すべて Docker Engine に送信されます(.dockerignore で除外したものを除く)。関係ない大きなファイル(別のプロジェクト、ダウンロードした ISO イメージ、動画ファイルなど)が含まれていると、コンテキスト送信に時間がかかり、ビルド速度が遅くなります。また、意図しない情報(.git ディレクトリなど)が Image に含まれる可能性もあります。
  • .dockerignore の活用: .gitignore と同様に、.dockerignore ファイルを context ディレクトリに配置することで、ビルドコンテキストから除外したいファイルやディレクトリを指定できます。これにより、転送量を減らし、不要なファイルを Image に含めないようにできます。必ず .dockerignore を使いましょう。例:
    gitignore
    .git
    .vscode
    node_modules
    dist
    *.log
    temp/

Dockerfile のベストプラクティス

docker-compose build は内部で docker build を実行するため、Dockerfile の書き方はビルドの効率や最終的な Image の品質に直結します。

  • 小さいイメージを作る: ベースイメージとして Alpine Linux のような軽量なディストリビューションを選ぶ、マルチステージビルドを活用して最終イメージに必要なものだけを含める、不要なパッケージをインストールしない、インストール後にキャッシュファイルを削除する(apt-get clean, rm -rf /var/lib/apt/lists/* など)といった工夫でイメージサイズを小さく保ちます。
  • キャッシュを最大限活用する: Docker は Dockerfile の各命令をレイヤーとしてキャッシュします。ある命令とその前の命令からのファイルシステムの状態が変わっていなければ、その命令以降はキャッシュが使われます。これを意識して Dockerfile を書くことが重要です。
    • 変更頻度の低いもの(依存関係のファイル package.json, requirements.txt など)を先に COPY し、その後に依存関係のインストール (RUN npm install, RUN pip install など) を行うと、ソースコード (COPY . .) を変更しても依存関係のインストールステップがキャッシュでスキップされやすくなります。
    • 複数の RUN 命令を && で連結して一つにまとめると、中間レイヤーの数を減らせます。ただし、読みやすさとのバランスも重要です。
  • 各命令の役割を理解する:
    • FROM: ベースイメージを指定。
    • WORKDIR: その後の命令を実行する作業ディレクトリを設定。
    • COPY: ローカルファイルやディレクトリをイメージにコピー。.dockerignore を考慮。
    • ADD: COPY と似ているが、リモート URL からファイルをダウンロードしたり、アーカイブを自動展開したりする機能もある。通常は COPY を使うのが推奨されます。
    • RUN: イメージ内でコマンドを実行し、新しいレイヤーを作成。パッケージインストールなどで使う。
    • CMD: コンテナ起動時にデフォルトで実行されるコマンド。Dockerfile に一つだけ。
    • ENTRYPOINT: コンテナ起動時に必ず実行される命令。CMDENTRYPOINT の引数として扱われることが多い。
    • ENV: 環境変数を設定。
    • ARG: ビルド時変数。RUN 命令などで利用できる。ENV と異なり、最終イメージには引き継がれません。
    • EXPOSE: コンテナがリッスンするポートをドキュメントとして公開。ネットワーク設定ではありません。
    • VOLUME: 永続化するデータを格納する場所を指定(ドキュメントや初期化用)。
  • 公式ドキュメントやベストプラクティスガイドを参照する: Docker 公式ドキュメントには、効率的で安全な Dockerfile を作成するための詳細なベストプラクティスが掲載されています。これらを参考にしましょう。

docker-compose.ymlimagebuild を混在させる場合の注意

一つの docker-compose.yml ファイル内で、あるサービスは build を使い、別のサービスは image を使うのはよくあるパターンです(例: アプリケーションコードはビルド、データベースは公式 Image)。

docker-compose build コマンドは、build キーが定義されているサービスのみを対象とします。image キーのみが定義されているサービスは無視されます。これらのサービスの Image を取得するには、別途 docker-compose pull コマンドを実行する必要があります。

通常は docker-compose up --build コマンドを使うことが多いでしょう。このコマンドは、Image が存在しないか、build 設定に変更があった場合に自動的にビルドを実行し、image が指定されている場合はプルを行います。

CI/CD パイプラインでの build コマンド

CI/CD パイプラインで Docker Image をビルドする場合、いくつか考慮点があります。

  • ビルドキャッシュ: パイプラインの実行速度を上げるために、ビルドキャッシュをどのように扱うかが重要です。パイプラインによっては、前回のビルドで作成された Image をキャッシュとして利用できる機能(例: GitLab CI/CD の Docker in Docker with cache、BuildKit のリモートキャッシュ)があります。cache_from オプションや BuildKit の機能を活用しましょう。
  • イメージのリポジトリへのプッシュ: ビルドした Image は、次のステップ(デプロイなど)や他の環境で利用できるように、Docker Registry (Docker Hub, GitLab Container Registry, AWS ECR など) にプッシュするのが一般的です。ビルド成功後に docker-compose push コマンドを実行したり、パイプラインの機能を使ったりします。
  • 再現性: CI 環境でのビルドの再現性を確保するために、Dockerfile で使用するベースイメージのタグは :latest のような可変タグではなく、特定のバージョンを固定すること(例: node:18.18.0-alpine)が強く推奨されます。

まとめ

この記事では、Docker Compose を使って独自の Docker Image をビルドするための docker-compose build コマンドについて、初心者向けに詳細な解説を行いました。

  • docker-compose build は、docker-compose.yml ファイルの build 設定に基づいて Docker Image をビルドするコマンドです。
  • docker-compose.ymlbuild キーでは、ビルドコンテキスト (context)、Dockerfile の指定、ビルド引数 (args) などを設定できます。
  • 基本的な使い方は docker-compose build または docker-compose build [SERVICE...] です。
  • --no-cache, --pull, --build-arg などのオプションを使うことで、ビルドプロセスを制御・カスタマイズできます。
  • ビルドキャッシュの仕組みを理解し、Dockerfile の書き方を工夫することで、ビルド時間を大幅に短縮できます。
  • エラーメッセージをよく確認し、--no-cache を試すことがトラブルシューティングの基本的なアプローチです。
  • .dockerignore を適切に使い、Dockerfile のベストプラクティスに従うことで、より効率的でメンテナブルなビルドを実現できます。

docker-compose build は、Docker Compose を使ったアプリケーション開発において非常に重要なコマンドです。この記事で学んだ知識を活かして、あなたのプロジェクトで独自の Docker Image を構築し、Docker Compose の利便性を最大限に引き出してください。

ビルドした Image を使ってコンテナを起動するには、引き続き docker-compose updocker-compose run コマンドを学ぶことになります。これらのコマンドも合わせて習得し、Docker と Docker Compose を活用した快適な開発・運用ワークフローを構築しましょう!

参考資料

これらの公式ドキュメントも合わせて参照すると、より深い理解が得られます。

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール