【初心者向け】Docker Buildx入門:高速・効率的なビルド方法を解説

はい、承知いたしました。【初心者向け】Docker Buildx入門:高速・効率的なビルド方法を解説 の詳細な説明を含む記事を約5000語で記述します。


【初心者向け】Docker Buildx入門:高速・効率的なビルド方法を徹底解説

Dockerを使ってアプリケーションをコンテナ化する上で、欠かせないのがDockerイメージの「ビルド」です。docker buildコマンドにDockerfileを渡すことで、必要なファイルや設定が詰まったDockerイメージを作成できます。

しかし、プロジェクトが大規模になったり、複数のプラットフォーム(Intel Mac/PC, ARM Mac/Raspberry Piなど)に対応する必要が出てきたりすると、従来のdocker buildにはいくつかの限界が見えてきます。ビルドに時間がかかったり、マルチプラットフォーム対応が面倒だったり、キャッシュがうまく効かずに再ビルドに時間がかかったりといった問題に直面することがあります。

そこで登場するのがDocker Buildxです。

Buildxは、Dockerにおける次世代のビルドコマンドであり、そのバックエンドにはBuildKitという強力なビルドエンジンが使われています。Buildxを利用することで、ビルドの高速化効率化はもちろん、マルチプラットフォームイメージの簡単なビルド高度なキャッシュ管理セキュリティ機能など、様々なメリットを享受できます。

この記事では、「Docker Buildx入門」として、Buildxの基本的な使い方から、なぜ高速・効率的にビルドできるのか、そして実践的な活用方法までを、初心者の方にも分かりやすく徹底的に解説します。この記事を読めば、あなたのDockerビルドがより快適で強力になること間違いなしです。

この記事で学べること

  • 従来のdocker buildの限界とBuildxが必要な理由
  • Buildxの基盤であるBuildKitとは何か
  • Buildxの基本的な使い方
  • Buildxによるビルド高速化・効率化の仕組み(並列処理、キャッシュ)
  • Buildxを使ったマルチプラットフォームイメージのビルド方法
  • ビルダーインスタンスの管理と活用
  • Buildxの便利な機能(secrets, ssh, 出力形式)
  • CI/CDパイプラインでのBuildx活用方法

さあ、Buildxの世界に飛び込み、より良いDockerビルドをマスターしましょう!

1. なぜDocker Buildxが必要なのか?従来のdocker buildの限界

まずは、私たちが普段利用しているdocker buildがどのように動作し、どのような課題を抱えているのかを見ていきましょう。

1.1 docker buildの動作原理

従来のdocker buildコマンドは、内部でDockerデーモンが持つ従来のビルド機能(”classic builder”や”V1 builder”と呼ばれることもあります)を利用しています。

  1. コンテキストの送信: docker build .のように実行すると、指定されたパス(.など)にあるDockerfileや関連ファイルがDockerデーモンに送信されます。これを「ビルドコンテキスト」と呼びます。.dockerignoreファイルがある場合、そこに指定されたファイルは送信されません。
  2. Dockerfileの解析: Dockerデーモンは受け取ったDockerfileを1行ずつ解析します。
  3. ステップごとの実行: Dockerfileの各命令(FROM, RUN, COPY, ENVなど)を上から順番に実行します。
    • 各命令は、基本的に新しいコンテナを作成し、その中で操作を行い、結果を新しいイメージレイヤーとしてコミットするという流れを繰り返します。
    • 前のステップで作成されたイメージが、次のステップのベースイメージとなります。
  4. キャッシュの利用: 同じDockerfileで、かつ変更されていないステップがある場合、Dockerは前のビルドで作成された既存のイメージレイヤーを再利用します(キャッシュヒット)。これにより、ビルド時間を短縮します。キャッシュは、各命令とその入力(ファイルの内容など)に基づいて判断されます。
  5. 最終イメージの生成: 全てのステップが完了すると、最終的なDockerイメージが生成され、Dockerデーモンに保存されます。

1.2 従来のdocker buildが抱える課題

このシンプルで分かりやすい仕組みは、多くの場合で十分機能します。しかし、特定の状況では非効率性や限界が見えてきます。

  • ビルドの並列性の欠如: 基本的にDockerfileの命令は上から順に直列に実行されます。たとえ依存関係のないステップであっても、前のステップが完了するまで次のステップは開始されません。これにより、ビルド全体にかかる時間が長くなることがあります。
  • キャッシュの限界: 従来のキャッシュは、各ステップの「直前のレイヤー」と「現在の命令+引数」に基づいてキャッシュキーを生成します。COPY命令などの場合、コピー元ファイルの変更もキャッシュキーに含まれますが、キャッシュの判断粒度が荒い場合があります。また、特定のディレクトリ(例:パッケージマネージャーのキャッシュディレクトリ)をステップを跨いで効率的にキャッシュするのが難しい場合があります。
  • マルチプラットフォームビルドの複雑さ: 異なるCPUアーキテクチャ(例:x86-64とARM64)向けのイメージをビルドしたい場合、従来のdocker buildは通常、そのビルドを実行しているホストのアーキテクチャ向けのイメージしか生成できません。複数のアーキテクチャに対応するには、以下のようなワークアラウンドが必要でした。
    • 各アーキテクチャのホストマシンで個別にビルドする。
    • QEMUのようなエミュレーターを使ってクロスアーキテクチャビルドを行うが、設定が面倒だったりパフォーマンスが低かったりする。
    • 複雑なスクリプトを書いて、複数のビルドを自動化・統合する。
      これは非常に手間がかかり、エラーも発生しやすくなります。
  • 出力形式の制限: 従来のdocker buildは、ビルド結果を主にローカルのDockerデーモンにイメージとして保存することしかできませんでした。ビルド結果をtarファイルとして出力したり、直接レジストリにプッシュしたり、中間ファイルを検査したりといった柔軟な出力制御が困難でした。
  • セキュリティ機能の不足: ビルド中にAPIキーやパスワードなどの秘匿情報を扱う場合、--build-argを使う方法は履歴に残る可能性があったり、安全な方法とは言えませんでした。また、プライベートリポジトリのクローンなどにSSHキーを利用するのも容易ではありませんでした。
  • 実験的な機能の取り込み遅延: 新しいビルド機能(例:特定のファイルだけをステージ間でコピーする機能など)は、従来のビルダーにはなかなか取り込まれませんでした。

これらの課題を解決するために開発されたのが、BuildKitをバックエンドとするDocker Buildxです。

2. Docker Buildxとは? BuildKitとの関係

Docker Buildxは、これらの課題を解決するために設計された、Dockerの公式なビルドコマンド拡張です。そして、Buildxの裏側で実際にビルドを実行しているエンジンがBuildKitです。

2.1 BuildKitとは

BuildKitは、コンテナイメージをビルドするための新しい高性能で並列性の高いオープンソースのツールキットです。Mobyプロジェクト(Dockerの中核技術を開発するプロジェクト)の一部として開発されています。

BuildKitは従来のビルドエンジンを根本的に見直し、以下の特徴を持っています。

  • 高速な並列処理: Dockerfileの命令間の依存関係を解析し、可能な限り並列に実行します。
  • 効率的なキャッシュ管理: キャッシュの粒度を細かくし、より確実にキャッシュヒットするように改善されています。また、ビルドキャッシュを外部にエクスポート・インポートする機能も持ちます。
  • プラグイン可能なアーキテクチャ: フロントエンド(Dockerfileパーサーなど)やバックエンド(ビルダー実行環境)をプラグインとして拡張できるようになっています。
  • 高度なセキュリティ機能: ビルド中のsecrets管理やSSHエージェントフォワーディングなどの機能を提供します。
  • 多様な出力形式: ビルド結果をDockerイメージとして保存するだけでなく、OCIイメージ、tarファイル、ローカルディレクトリなど、様々な形式で出力できます。
  • マルチプラットフォーム対応: 複数のアーキテクチャ向けのイメージを効率的に同時にビルドできます。
  • Rootlessモード対応: root権限なしでビルドを実行できます。

2.2 Buildxの役割

Buildxは、このBuildKitの機能をdocker buildコマンドの使い慣れたインターフェースを通して利用可能にするためのCLI(コマンドラインインターフェース)ツールです。

簡単に言えば、Buildxは「BuildKitを使うための橋渡し役」です。

  • ユーザーはdocker buildx build ...のようにBuildxコマンドを実行します。
  • Buildxは、指定されたオプションやDockerfile、コンテキストを解析し、BuildKitに対してビルドジョブを依頼します。
  • BuildKitが実際のビルド処理を、その高性能な機能(並列処理、キャッシュ、マルチプラットフォーム対応など)を駆使して実行します。
  • BuildKitはビルド結果をBuildxに返します。
  • Buildxは受け取った結果をユーザーに提示したり、指定された出力先に保存したりします。

Buildxを利用することで、BuildKitの持つ先進的なビルド機能を、従来のdocker buildに近い感覚で簡単に使いこなせるようになります。

Docker Desktopを使っている場合、Buildxはデフォルトで有効になっており、内部的にBuildKitが使われています。コマンドラインでdocker buildx buildを実行することで、明示的にBuildKitの機能を利用できます。

3. BuildKitの基本概念:なぜ速い?なぜ効率的?

Buildxが高速で効率的なのは、バックエンドで動作するBuildKitのおかげです。ここでは、BuildKitがどのようにビルドを高速化・効率化しているのか、その基本概念を掘り下げてみましょう。

3.1 DAGベースの並列処理

BuildKitの最も重要な特徴の一つは、ビルドのステップをDAG (Directed Acyclic Graph:有向非巡回グラフ)として表現し、実行することです。

従来のdocker buildは、Dockerfileの命令を上から順に実行する「線形」な処理でした。

“`dockerfile

例:従来のビルドは直列

FROM ubuntu
RUN apt-get update -y # ステップA
RUN apt-get install -y some-package # ステップB
COPY ./app /app # ステップC
RUN make -C /app # ステップD
CMD [“/app/run”]
“`

この場合、A→B→C→D の順で実行されます。たとえCとDがAやBに直接依存していなくても、待つ必要がありました。

一方BuildKitは、Dockerfile(や他のBuildKitに対応した定義ファイル)を解析し、各ステップ間の依存関係をグラフ構造として構築します。

“`dockerfile

BuildKitは依存関係を解析

FROM ubuntu
RUN apt-get update -y # ステップA
RUN apt-get install -y some-package # ステップB (Aに依存)
COPY ./app /app # ステップC (FROMに依存)
RUN make -C /app # ステップD (B, Cに依存)
CMD [“/app/run”]
“`

この例では、BはAが完了しないと実行できませんが、CはFROMイメージが準備できればAやBと並列に実行開始できます。DはBとCの両方が完了しないと実行できません。

BuildKitは、このようなDAGを構築し、依存関係が満たされたステップから順番に、複数のステップを同時に実行します。これにより、特にDockerfileの中で独立した処理が多い場合に、ビルド時間を大幅に短縮できます。

3.2 高度なキャッシュ管理

BuildKitのもう一つの強力な機能は、洗練されたキャッシュ管理です。

  • きめ細かいキャッシュキー: BuildKitは、各ビルドステップのキャッシュキーを生成する際、入力となるファイル内容や命令の詳細をより正確にハッシュ化します。これにより、Dockerfileのちょっとした変更や、COPYするファイルの内容の微妙な変更でも、キャッシュミスすることなく、本当に必要なステップだけを再実行するようになります。
  • マウント可能なキャッシュ (--mount=type=cache): これまでDockerビルドで難しかったのが、パッケージマネージャーのキャッシュ(npm, yarn, pip, aptなど)やコンパイルの中間ファイルなどを効率的にキャッシュすることでした。
    例えば RUN apt-get update && apt-get install ... というステップがある場合、apt-get updateの結果やダウンロードしたパッケージファイルは、次のステップには引き継がれず、キャッシュにも残りませんでした。別のビルドで同じパッケージをインストールしようとすると、再度ダウンロードからやり直しになっていました。
    BuildKitでは、--mount=type=cacheオプションを使って、特定のディレクトリをキャッシュとして永続化できます。

    “`dockerfile

    Syntaxとして BuildKitの機能を有効化

    docker buildx build –progress=plain … で確認しやすい

    syntax=docker/dockerfile:1

    FROM ubuntu
    RUN apt-get update -y && apt-get install -y –no-install-recommends build-essential

    WORKDIR /app
    COPY package.json package-lock.json ./

    node_modules と npm cache をキャッシュとしてマウント

    RUN –mount=type=cache,target=/root/.npm \
    –mount=type=cache,target=/app/node_modules \
    npm ci

    COPY . .

    CMD [“node”, “index.js”]
    “`

    この例では、/root/.npm(npmのキャッシュディレクトリ)と/app/node_modulesをキャッシュとしてマウントしています。初めてビルドする際は通常のnpm ciが実行されますが、二回目以降、package.jsonpackage-lock.jsonに変更がなければ、node_modulesがキャッシュから復元され、npm ciが非常に高速に完了します。npmのキャッシュも同様に再利用されます。

    この機能は、ビルド時間のかなりの部分を占めることが多い依存ライブラリのダウンロードやインストールを劇的に高速化します。

  • 外部キャッシュ (--cache-to, --cache-from): BuildKitは、ビルド中に生成されたキャッシュを、Dockerレジストリ、ローカルのOCIイメージ、ローカルディレクトリなど、様々な場所にエクスポート(保存)できます。そして、別のビルドでそのキャッシュをインポートして利用できます。

    “`bash

    キャッシュをレジストリにプッシュ (例: ghcr.io/your-user/your-repo:cache)

    docker buildx build . \
    –cache-to type=registry,ref=ghcr.io/your-user/your-repo:cache,mode=max \
    –output type=registry,name=ghcr.io/your-user/your-repo:latest,push=true

    別の場所でキャッシュをインポートして高速ビルド

    docker buildx build . \
    –cache-from type=registry,ref=ghcr.io/your-user/your-repo:cache \
    –output type=registry,name=ghcr.io/your-user/your-repo:latest,push=true
    “`
    この機能は、CI/CD環境で非常に強力です。一度ビルドしたキャッシュを共有レジストリに保存しておけば、後続のビルドや別のエージェントでのビルドがそのキャッシュを利用でき、ビルド時間を大幅に短縮できます。

これらの高度なキャッシュ戦略により、BuildKitは不要な再ビルドを減らし、必要なビルドステップだけを効率的に実行します。

3.3 マルチプラットフォームビルドの容易化

前述の通り、BuildKitはマルチプラットフォームイメージのビルドをネイティブにサポートしています。Buildxの--platformオプションを使うだけで、複数のアーキテクチャ向けのイメージを単一のコマンドでビルドできます。

BuildKitは内部で、各ターゲットプラットフォーム(例:linux/amd64, linux/arm64)向けにビルドステップを実行し、最終的にそれらのイメージをまとめた「マニフェストリスト」(またはインデックス)を作成します。このマニフェストリストは、docker pullコマンドが実行されたホストのアーキテクチャに最適なイメージを自動的に選択するために使われます。

異なるアーキテクチャのバイナリを実行する必要がある場合(例:ARMホストでAMD64イメージをビルドする場合)、BuildKitはQEMUのようなエミュレーション機能と連携して、透過的にクロスアーキテクチャ実行を可能にします。このための設定は、多くの場合、binfmt_miscカーネル機能と、それを簡単にセットアップする軽量なコンテナ(例:tonistiigi/binfmt)で行えます。

“`bash

必要なエミュレーターをセットアップ (一度実行すればOK)

docker run –privileged –rm tonistiigi/binfmt –install all

複数のプラットフォーム向けにビルドしてプッシュ

docker buildx build . \
–platform linux/amd64,linux/arm64 \
–output type=registry,name=your-repo/your-image:latest,push=true
“`

このように、Buildxを使えば、マルチプラットフォーム対応の煩雑さが劇的に軽減されます。

3.4 その他のBuildKit機能

BuildKitは他にも多くの機能を持っています。

  • Frontend: BuildKitはDockerfileだけでなく、Buildpackなど他のビルド定義形式もサポートできます。# syntax=ディレクティブでFrontendを指定します。
  • Build Secret: --secretオプションを使って、ビルド中に環境変数として公開したくない秘匿情報を安全に渡せます。
  • SSH Forwarding: --sshオプションを使って、ビルドコンテナからホストのSSHエージェント経由でSSH接続できます。プライベートなGitリポジトリからのクローンなどに便利です。
  • Output形式の多様性: --outputオプションで、ローカルのDockerデーモン、tarファイル、ローカルディレクトリ、直接レジストリなど、様々な出力先を指定できます。
  • Attestations: ビルドに関するメタデータ(例:SBOM – Software Bill of Materials, ビルドの署名)をイメージに紐付ける機能(実験的)。

BuildKitはこれらの機能を組み合わせて、Dockerビルドをよりパワフルで柔軟、そして安全なものにしています。BuildxはこれらのBuildKit機能を簡単に利用するためのインターフェースなのです。

4. Buildxのインストールとセットアップ

Docker Buildxは、比較的新しいDockerのバージョンには標準で組み込まれています。

  • Docker Desktop (Windows, macOS): Docker DesktopにはBuildxが最初から含まれており、特に何もインストールする必要はありません。BuildKitもデフォルトで有効です。
  • Docker Engine (Linux): 最近のDocker Engineのバージョン(例えば 19.03 以降)には、Buildx CLIプラグインが含まれていることが多いです。インストールされているDockerが比較的新しいバージョンであれば、追加のインストールは不要な場合がほとんどです。
    古いバージョンのDocker Engineを使っている場合や、プラグインとしてインストールされていない場合は、手動でBuildx CLIプラグインをインストールする必要があるかもしれません。公式ドキュメントやGitHubリポジトリを参照してください。

確認方法

お使いの環境でBuildxが利用できるか確認するには、以下のコマンドを実行します。

bash
docker buildx version

Buildxのバージョン情報が表示されれば、インストールは完了しています。

github.com/docker/buildx v0.x.x ...

docker: 'buildx' is not a docker command.のようなエラーが出る場合は、Dockerのバージョンを確認するか、Buildxプラグインの手動インストールを検討してください。

4.1 ビルダーインスタンスの理解とセットアップ

Buildxは、ビルドを実行するための環境であるビルダーインスタンスを使用します。ビルダーインスタンスは、BuildKitデーモンを実行する場所や接続方法を定義します。

Buildxを初めて使うとき、通常はデフォルトのビルダーインスタンスが自動的に作成され、それが利用されます。このデフォルトビルダーは、多くの場合はdockerドライバーを使用し、ホストのDockerデーモン内でBuildKitを実行します(Docker Desktopの場合)。あるいは、より高機能なdocker-containerドライバーを使用し、BuildKitを独立したコンテナとして実行する場合もあります。

ビルダーインスタンスの確認

現在利用可能なビルダーインスタンスを確認するには、以下のコマンドを実行します。

bash
docker buildx ls

実行例:

NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
default * docker
default default running v0.11.6+b8542e50b https://github.com/moby/buildkit linux/amd64,linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/arm/v7,linux/arm/v6

  • NAME: ビルダーインスタンスの名前。defaultが現在のデフォルトインスタンスであることを示します。
  • DRIVER: BuildKitデーモンを実行する方法(docker, docker-container, kubernetes, remoteなど)。
  • ENDPOINT: BuildKitデーモンへの接続先。
  • STATUS: ビルダーの状態(running, inactiveなど)。
  • BUILDKIT: 使用されているBuildKitのバージョン。
  • PLATFORMS: このビルダーインスタンスがサポートするプラットフォーム。

*が付いているビルダーインスタンスが、現在アクティブに使用されるインスタンスです。

新しいビルダーインスタンスの作成 (必要に応じて)

ほとんどの場合、デフォルトのビルダーインスタンスで十分ですが、特定の要件(例:リモートのDockerデーモンでビルドしたい、Kubernetesクラスター上でBuildKitを実行したい)がある場合は、新しいビルダーインスタンスを作成します。

例えば、docker-containerドライバーを使用する新しいビルダーを作成する場合:

“`bash

新しいビルダーインスタンスを作成

docker buildx create –name mybuilder –driver docker-container

作成したビルダーを起動

docker buildx inspect mybuilder –bootstrap

そのビルダーを使用するように切り替える

docker buildx use mybuilder

確認

docker buildx ls
“`

docker-containerドライバーは、BuildKitを独立したコンテナとして実行するため、ホストのDockerデーモンに依存しない、よりクリーンでステートレスなビルド環境を提供できます。BuildKitの最新機能をより確実に利用したい場合や、CI環境などでの利用に適しています。

--bootstrapオプションは、ビルダーインスタンスを初めて使用する際に、関連するBuildKitコンテナなどを起動するために必要です。docker buildx build実行時にも自動的にブートストラップされますが、事前にinspect --bootstrapで起動しておくことも可能です。

ビルダーインスタンスの切り替え

複数のビルダーインスタンスがある場合、docker buildx useコマンドで、どのインスタンスを使うか切り替えられます。

bash
docker buildx use default # デフォルトに戻す
docker buildx use mybuilder # mybuilderに切り替える

ビルダーインスタンスの削除

不要になったビルダーインスタンスは削除できます。

bash
docker buildx rm mybuilder

ビルダーインスタンスの管理は、Buildxの高度な機能を利用する上で重要になりますが、まずはデフォルトのビルダーでBuildxの基本的な使い方に慣れることから始めましょう。

5. Buildxの基本的な使い方

Buildxの基本的な使い方は、従来のdocker buildと非常によく似ています。コマンド名の先頭にbuildxが付くだけです。

“`bash

従来のビルド

docker build -t myimage:latest .

Buildxを使ったビルド

docker buildx build -t myimage:latest .
“`

これだけでは、特に見た目の変化はないかもしれません。しかし、内部ではBuildKitが使用され、前述の高速化や効率化の恩恵を受けている可能性があります(特に並列処理やキャッシュの改善)。

5.1 シンプルなビルド例

簡単なDockerfileを用意して、Buildxでビルドしてみましょう。

“`dockerfile

Dockerfile

FROM ubuntu:latest

RUN apt-get update && apt-get install -y –no-install-recommends fortune-mod cowsay

CMD [“/usr/games/cowsay”, “Moo! I’m a cow!”]
“`

このDockerfileをDockerfileという名前で保存し、同じディレクトリで以下のコマンドを実行します。

bash
docker buildx build -t my-fortune-cow:latest .

--tag (または -t) オプションは従来のdocker buildと同じく、ビルドしたイメージに名前とタグを付けます。.はビルドコンテキストのパスです。

ビルドの進捗表示も、従来のコマンドと少し異なる場合があります。BuildKitはより詳細な進捗情報を提供できます。デフォルトではシンプルな表示ですが、--progress=plainオプションを付けると、各ステップの詳細なログを確認できます。

bash
docker buildx build -t my-fortune-cow:latest . --progress=plain

ビルドが完了すると、デフォルトではローカルのDockerデーモンにイメージが保存されます。これは、docker buildx buildのデフォルトの出力形式がtype=imageであるためです。

5.2 --platformオプションによるシングルプラットフォームビルド

特定のプラットフォーム向けのイメージをビルドしたい場合、--platformオプションを使用します。

“`bash

AMD64 Linux 向けのイメージをビルド

docker buildx build –platform linux/amd64 -t myimage:amd64 .

ARM64 Linux 向けのイメージをビルド

docker buildx build –platform linux/arm64 -t myimage:arm64 .
“`

--platformに指定できる値は、docker buildx lsコマンドの出力のPLATFORMS列に表示されているものです。一般的なものとしては linux/amd64, linux/arm64, linux/arm/v7, linux/386 などがあります。ホストOSのアーキテクチャに関わらず、指定したアーキテクチャ向けのイメージをビルドしようとします。必要に応じてBuildKitがQEMUエミュレーションを利用します。

5.3 --outputオプションの基本:プッシュとローカル保存

Buildxの強力な機能の一つが、ビルド結果の出力先を細かく制御できる--outputオプションです。デフォルトはtype=imageで、従来のdocker buildのようにローカルのDockerデーモンにイメージを保存します。

  • レジストリへのプッシュ: ビルド完了後にすぐにレジストリにイメージをプッシュしたい場合に使います。これは特にCI/CDで便利です。

    bash
    docker buildx build . \
    -t your-registry/your-image:latest \
    --output type=registry

    または、より簡潔に --push フラグを使っても同じことができます (type=registryがデフォルトで使われます)。

    bash
    docker buildx build . \
    -t your-registry/your-image:latest \
    --push

  • tarファイルとしての出力: ビルドしたイメージをローカルファイルとして保存したい場合に便利です。

    bash
    docker buildx build . \
    --output type=tar,dest=/tmp/myimage.tar

    このコマンドは、ビルド結果を/tmp/myimage.tarというtarファイルとして保存します。このファイルはdocker load -i /tmp/myimage.tarで別のDocker環境にロードできます。

--outputオプションは非常に柔軟で、type=で出力形式を指定し、,区切りで追加のオプション(例:dest=, name=, push=)を指定します。詳細は後述します。

これらの基本的な使い方をマスターするだけでも、Buildx(BuildKit)の内部的な最適化の恩恵を受けることができます。次のセクションでは、Buildxの主要なメリットである高速化と効率化の仕組みをさらに深掘りします。

6. 高速化の秘密:BuildKitの並列処理とキャッシュ戦略の詳細

Buildxを使ったビルドがなぜ速くなるのか、BuildKitの心臓部である並列処理と高度なキャッシュの仕組みを、具体的な例を交えながら見ていきましょう。

6.1 並列処理:DAGによる魔法

従来のDockerビルドは、Dockerfileの各行を上から順番に実行していました。これはまるで、料理のレシピを最初から最後まで忠実に、一度に一つの工程だけを行うようなものです。

BuildKitは、Dockerfileを解析して「このステップはあのステップが終わったらできる」「このステップは他のステップに影響しないから、並行してできる」といった依存関係を理解します。そして、可能な限り多くのステップを同時に実行します。

並列処理の例:

以下のDockerfileを考えてみましょう。

“`dockerfile

syntax=docker/dockerfile:1

FROM ubuntu:latest

ステップ1: パッケージリストの更新

RUN apt-get update -y

ステップ2a: 必要なツールのインストール (ビルドツール)

RUN apt-get install -y –no-install-recommends make gcc

ステップ2b: 別途必要なツールのインストール (ランタイムツール)

RUN apt-get install -y –no-install-recommends fortune-mod

ステップ3: アプリケーションソースコードのコピー

COPY ./app /app

ステップ4: アプリケーションのビルド (makeを使う) – ステップ2aと3に依存

RUN make -C /app

ステップ5: fortune-modの確認 – ステップ2bに依存

RUN fortune
“`

従来のビルドでは、ステップ1から5までが順番に実行されます。
1 → 2a → 2b → 3 → 4 → 5

BuildKitでは、以下のように依存関係を解析します。

  • ステップ1 (apt-get update) は最初に行う必要がある。
  • ステップ2a (install make gcc) はステップ1に依存。
  • ステップ2b (install fortune-mod) はステップ1に依存。
  • ステップ3 (COPY) はFROMイメージがあれば実行可能。
  • ステップ4 (make) はステップ2aとステップ3が完了しないと実行できない。
  • ステップ5 (fortune) はステップ2bが完了しないと実行できない。

BuildKitはこれらの関係を見て、以下のような並列実行のプランを立てる可能性があります(実際のプランはBuildKitのスケジューリングによりますが、概念として)。

  1. ステップ1 (apt-get update) を実行。
  2. ステップ1が完了したら、ステップ2a (install make gcc) とステップ2b (install fortune-mod) を同時に実行開始。
  3. ステップ1が完了したら、ステップ3 (COPY) も並列に実行開始。
  4. ステップ2aとステップ3が完了したら、ステップ4 (make) を実行開始。
  5. ステップ2bが完了したら、ステップ5 (fortune) を実行開始。
  6. 全てのステップが完了したら、最終イメージを生成。

この例では、ステップ2a, 2b, 3が並列に実行される可能性があるため、従来の直列実行に比べてビルド時間が短縮されることが期待できます。

--progress=plainオプションを使ってBuildxビルドのログを見ると、複数のステップが同時にrunningdownloading状態になっていることが確認できます。

6.2 高度なキャッシュ戦略:キャッシュの賢い使い方

BuildKitのキャッシュは、単に「前のステップと同じ命令なら再利用」というだけでなく、より賢く、より柔軟に利用できます。

6.2.1 より賢いキャッシュキー

BuildKitは、各ステップのキャッシュキーを生成する際に、命令そのものだけでなく、その入力(例:COPYのコピー元ファイルのコンテンツハッシュ、RUNコマンドで参照されるファイルの内容など)をより正確に考慮します。これにより、不必要にキャッシュが外れるのを防ぎつつ、変更があった場合は確実に再ビルドされるようになります。

6.2.2 マウント可能なキャッシュ (--mount=type=cache) の詳細

これはBuildKitのキャッシュ機能の中でも特に強力で、ビルドのパフォーマンスを劇的に改善する可能性があります。特定のディレクトリを「キャッシュボリューム」のように扱い、ビルドステップを跨いで状態を維持できます。

構文: --mount=type=cache,target=<キャッシュしたいディレクトリの絶対パス>[,option=value...]

よくある利用例:

  • Node.js (npm/yarn): node_modulesとnpm/yarnのグローバルキャッシュディレクトリをキャッシュ。

    “`dockerfile

    syntax=docker/dockerfile:1

    FROM node:lts
    WORKDIR /app
    COPY package.json package-lock.json ./

    node_modulesディレクトリとnpmのグローバルキャッシュをキャッシュ

    RUN –mount=type=cache,target=/app/node_modules,id=node_modules \
    –mount=type=cache,target=/root/.npm,id=npm_cache \
    npm ci

    COPY . .
    CMD [“node”, “index.js”]
    ``id=`オプションは、複数のキャッシュマウントを使う場合に、それぞれを区別するために付けると良いでしょう。

  • Python (pip): pipのキャッシュディレクトリをキャッシュ。

    “`dockerfile

    syntax=docker/dockerfile:1

    FROM python:3.9
    WORKDIR /app
    COPY requirements.txt ./

    pipキャッシュをキャッシュ

    RUN –mount=type=cache,target=/root/.cache/pip \
    pip install –no-cache-dir -r requirements.txt

    COPY . .
    CMD [“python”, “app.py”]
    ``–no-cache-dirはpip自身のファイルキャッシュを無効にしますが、–mount=type=cache`で指定したディレクトリへのキャッシュは有効になります。

  • Maven (Java): Mavenのローカルリポジトリをキャッシュ。

    “`dockerfile

    syntax=docker/dockerfile:1

    FROM maven:latest
    WORKDIR /app
    COPY pom.xml ./

    Mavenローカルリポジトリをキャッシュ

    RUN –mount=type=cache,target=/root/.m2 \
    mvn dependency:go-offline -B

    COPY . .
    RUN mvn package
    CMD [“java”, “-jar”, “target/my-app.jar”]
    “`

  • Go: Goモジュールキャッシュとビルドキャッシュをキャッシュ。

    “`dockerfile

    syntax=docker/dockerfile:1

    FROM golang:latest
    WORKDIR /app
    COPY go.mod go.sum ./

    Goモジュールキャッシュとビルドキャッシュをキャッシュ

    RUN –mount=type=cache,target=/go/pkg/mod \
    –mount=type=cache,target=/root/.cache/go-build \
    go mod download

    COPY . .
    RUN –mount=type=cache,target=/root/.cache/go-build \
    go build -o myapp

    CMD [“./myapp”]
    “`

--mount=type=cacheを使う際の注意点:
* これはBuildKit固有の機能です。Dockerfileの先頭に# syntax=docker/dockerfile:1のようなディレクティブを書いておくことが推奨されます。これにより、BuildKitをサポートしていない環境でビルドしようとした場合にエラーになるなど、互換性の問題を防ぐのに役立ちます。
* キャッシュディレクトリのパスは、ビルドコンテナ内のパスです。適切なパーミッションでマウントされているか確認してください。
* キャッシュは、ビルドの実行者(BuildKitデーモン)によって管理されます。デフォルトでは、特定のビルダーインスタンスに関連付けられたキャッシュとして保存されます。

この機能は、依存関係の解決やコンパイルなど、時間がかかりやすく、かつ同じ入力に対しては結果が変わらないステップに対して非常に効果的です。

6.2.3 外部キャッシュ (--cache-to, --cache-from)

ビルドキャッシュを外部に保存・復元する機能は、特にCI/CD環境で真価を発揮します。ビルドエージェントが使い捨てであったり、複数のエージェントでビルドが実行されたりする場合でも、共通のキャッシュを利用できるようになります。

構文:
--cache-to type=<タイプ>[,option=value...]
--cache-from type=<タイプ>[,option=value...]

タイプ例:
* registry: DockerレジストリにキャッシュをOCIイメージとして保存/読み込み。
* local: ローカルファイルシステムにキャッシュを保存/読み込み。
* gha: GitHub Actionsのキャッシュ機能を利用(Buildx actionなど)。

レジストリキャッシュの例:

“`bash

CI環境などで、ビルドと同時にキャッシュをレジストリにプッシュ

docker buildx build . \
–platform linux/amd64 \
-t your-repo/your-image:latest \
–cache-to type=registry,ref=your-repo/your-image:buildcache,mode=max \
–push # イメージ本体もプッシュ

別のCIジョブやエージェントで、レジストリからキャッシュを読み込んでビルド

docker buildx build . \
–platform linux/amd64 \
-t your-repo/your-image:latest \
–cache-from type=registry,ref=your-repo/your-image:buildcache \
–push # イメージ本体をプッシュ
“`

  • ref=: キャッシュイメージの名前とタグを指定します。イメージ本体とは別のタグ(例: :buildcache)を使うのが一般的です。
  • mode=max: キャッシュのエクスポートモードを指定します。maxは可能な限り多くのキャッシュデータをエクスポートしようとします。minは最終イメージに必要なデータのみをエクスポートします(キャッシュヒット率が下がる可能性があります)。maxが推奨されることが多いです。

この仕組みを利用するには、レジストリへの認証が必要です(docker loginなど)。

ローカルキャッシュの例:

“`bash

キャッシュをローカルディレクトリに保存

docker buildx build . \
–cache-to type=local,dest=/tmp/buildx-cache

別のビルドで、ローカルディレクトリからキャッシュを読み込み

docker buildx build . \
–cache-from type=local,src=/tmp/buildx-cache
“`

これは、ローカルマシンで頻繁にビルドするが、Dockerデーモンのキャッシュが不安定な場合や、特定のプロジェクトのキャッシュだけを管理したい場合などに役立つ可能性があります。

これらのキャッシュ戦略を適切に組み合わせることで、特に依存関係の多いアプリケーションや複雑なビルドプロセスを持つプロジェクトにおいて、ビルド時間を劇的に短縮できます。

7. 効率化の秘密:マルチプラットフォームビルド

Docker Buildxのもう一つの大きな利点は、マルチプラットフォームイメージのビルドが非常に簡単になることです。これは、アプリケーションを様々なデバイス(例:サーバー、ラップトップ、Raspberry Pi、クラウドインスタンスなど)で実行したい場合に不可欠な機能です。

7.1 従来の課題の再確認

前述の通り、従来のdocker buildは基本的にホストのアーキテクチャ向けのイメージしかビルドできませんでした。例えば、Intel Mac (x86-64) でビルドしたイメージは、そのままではRaspberry Pi (ARM32v7) や新しいARM Mac (ARM64) でネイティブなパフォーマンスで実行することはできません。

マルチプラットフォーム対応のためには、以下のような手間が必要でした。

  • 異なるアーキテクチャのハードウェアを用意し、それぞれのマシンでビルドする。
  • Docker公式が提供するbuildpack-depsなどのマルチアーキテクチャ対応ベースイメージを利用し、Dockerデーモンの実験的機能やqemuなどのエミュレーターを手動で設定してクロスビルドを試みる。
  • Dockerfileのステップ内で、ターゲットアーキテクチャに応じて異なるコマンドを実行するような複雑な記述を行う。

これらの方法は、設定が複雑でエラーが発生しやすく、メンテナンスも大変でした。

7.2 Buildxによる解決

Buildxは、--platformオプションに複数のプラットフォームを指定するだけで、この問題を鮮やかに解決します。

bash
docker buildx build . \
--platform linux/amd64,linux/arm64,linux/arm/v7 \
-t your-repo/your-multiarch-image:latest \
--push

この単一のコマンドで、指定された3つの異なるアーキテクチャ向けのイメージがビルドされ、最終的にそれらをまとめたマニフェストリストが作成され、指定されたタグ(your-repo/your-multiarch-image:latest)に関連付けられてレジストリにプッシュされます(--pushがあるため)。

このマニフェストリストは、異なるアーキテクチャの環境からdocker pull your-repo/your-multiarch-image:latestを実行した際に、Dockerクライアントが自動的にその環境に最適なアーキテクチャのイメージを選択してダウンロードできるようにするメタデータです。

7.3 QEMUエミュレーションの活用

Buildx(BuildKit)は、指定されたプラットフォームでビルドを行う際に、必要に応じてQEMUのようなエミュレーターを自動的に利用します。例えば、AMD64のLinuxマシンで--platform linux/arm64を指定してビルドする場合、BuildKitはARM64のバイナリを実行するステップ(RUN命令など)でQEMUを利用してそのコマンドを実行します。

このエミュレーション機能を利用するためには、ホストOSに必要なバイナリフォーマットを登録しておく必要があります。これは、通常、binfmt_miscカーネル機能と、それを簡単にセットアップする軽量なコンテナイメージ(例: tonistiigi/binfmt)を使って行います。

“`bash

必要なプラットフォーム向けのエミュレーターをインストール (通常、各ホストで一度だけ実行)

–privileged が必要なので注意。信頼できるイメージのみ実行すること。

docker run –privileged –rm tonistiigi/binfmt –install all
“`

このコマンドは、システムの/proc/sys/fs/binfmt_miscに、様々なアーキテクチャのバイナリを検知したらQEMUを使って実行するように設定を登録します。これにより、BuildKitは異なるアーキテクチャ向けのRUN命令などを透過的に実行できるようになります。

多くのCI環境では、この設定が既にされているか、あるいはCIパイプラインの初期ステップで実行されるようになっています。Docker Desktopを使っている場合も、通常この設定は既に行われています。

7.4 マルチステージビルドと組み合わせる

マルチプラットフォームビルドは、マルチステージビルドとも組み合わせて利用できます。例えば、Goアプリケーションのように、ビルドステージで特定のアーキテクチャ向けのバイナリをコンパイルし、それを軽量な実行ステージにコピーする場合、BuildKitは各ターゲットプラットフォーム向けにビルドステージと実行ステージの両方をビルドします。

“`dockerfile

syntax=docker/dockerfile:1

ビルドステージ

FROM golang:latest AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN –mount=type=cache,target=/go/pkg/mod \
–mount=type=cache,target=/root/.cache/go-build \
go mod download

COPY . .

ビルドアーティファクトをコンパイル(ターゲットアーキテクチャによってコンパイル結果が変わる)

ARG TARGETOS TARGETARCH
RUN –mount=type=cache,target=/root/.cache/go-build \
CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -o myapp .

実行ステージ

FROM alpine:latest
WORKDIR /app
COPY –from=builder /app/myapp . # ビルドステージからアーティファクトをコピー
CMD [“./myapp”]
“`

このDockerfileを--platform linux/amd64,linux/arm64でビルドすると、BuildKitは以下を行います。

  1. linux/amd64向けのビルドステージを実行します。その際、TARGETOS=linux, TARGETARCH=amd64 のビルド引数が自動的に渡されます。go buildコマンドはAMD64向けのバイナリをコンパイルします。
  2. linux/arm64向けのビルドステージを実行します。その際、TARGETOS=linux, TARGETARCH=arm64 のビルド引数が自動的に渡されます。go buildコマンドはARM64向けのバイナリをコンパイルします。
  3. linux/amd64向けの実行ステージを作成し、AMD64ビルドステージからコンパイルされたAMD64バイナリをコピーします。
  4. linux/arm64向けの実行ステージを作成し、ARM64ビルドステージからコンパイルされたARM64バイナリをコピーします。
  5. 最終的に、AMD64イメージとARM64イメージを含むマニフェストリストを生成します。

このように、Buildxはマルチステージビルドにおけるクロスコンパイルも透過的にサポートします。ARG TARGETOS TARGETARCH をDockerfileに追加することで、ビルド中のスクリプトやコマンド内でターゲットOS/アーキテクチャを参照できるようになり、より柔軟なマルチプラットフォーム対応が可能になります。

Buildxによるマルチプラットフォームビルドは、異なるアーキテクチャ対応の複雑さを解消し、単一のコマンドで様々な環境で動作するイメージを効率的に提供することを可能にします。

8. ビルダーインスタンスの管理と活用

Buildxのビルドは、すべてビルダーインスタンスを介して行われます。ビルダーインスタンスは、BuildKitデーモンを実行する環境(ローカルのDockerデーモン、Dockerコンテナ、リモートホスト、Kubernetesクラスターなど)と、それに接続するための設定をカプセル化したものです。

8.1 ビルダーインスタンスの種類 (ドライバー)

Buildxはいくつかのドライバーをサポートしており、それぞれ異なる実行環境を提供します。

  • docker: これは従来のDockerデーモンに組み込まれているBuildKitを利用します。Docker Desktopのデフォルトや、BuildKitが有効化されたLinuxのDocker Engineで使われます。手軽に使えますが、BuildKitの機能の一部に制限がある場合があります(特にネットワークやボリューム関連)。
  • docker-container: BuildKitデーモンを、別の特権コンテナとして実行します。これが推奨されるドライバーであり、BuildKitの最新機能や全機能を最も安定して利用できます。ローカル環境での開発、CI/CD環境での利用に適しています。ステートレスな運用が可能で、ビルド間の分離性が高いです。
  • kubernetes: Kubernetesクラスター上でBuildKitを実行します。大規模なチームやCI/CD環境で、ビルド環境をスケーラブルに提供したい場合に利用できます。
  • remote: リモートホスト上のBuildKitデーモンに接続してビルドを実行します。

8.2 ビルダーインスタンスのライフサイクル

ビルダーインスタンスは以下のコマンドで管理します。

  • docker buildx ls: 既存のビルダーインスタンスを一覧表示します。
  • docker buildx create: 新しいビルダーインスタンスを作成します。
    bash
    # docker-container ドライバーで新しいビルダーを作成
    docker buildx create --name my-container-builder --driver docker-container
  • docker buildx use: 現在使用するビルダーインスタンスを切り替えます。
    bash
    docker buildx use my-container-builder
  • docker buildx inspect: ビルダーインスタンスの詳細情報(ドライバー、エンドポイント、サポートプラットフォーム、状態など)を表示します。--bootstrapオプションを付けると、必要に応じてBuildKitデーモンを起動します。
    bash
    # my-container-builder を検査し、起動していなければ起動
    docker buildx inspect my-container-builder --bootstrap

    Buildxビルドコマンドを実行した際も、自動的に使用するビルダーがブートストラップされます。
  • docker buildx stop: 起動中のビルダーインスタンスを停止します(docker-containerドライバーの場合など)。
    bash
    docker buildx stop my-container-builder
  • docker buildx rm: ビルダーインスタンスを削除します。関連するコンテナなども削除されます。
    bash
    docker buildx rm my-container-builder

8.3 docker-containerドライバーの活用

多くの場合、デフォルトのdockerドライバーでBuildxの基本的な恩恵は受けられますが、BuildKitの機能を最大限に活用するにはdocker-containerドライバーのビルダーを作成して使用するのが推奨されます。

docker-containerビルダーの利点:

  • BuildKitの全機能を利用可能: --mount=type=cacheや多様な--output形式など、BuildKitの最新かつ全ての機能にアクセスできます。
  • 分離性: BuildKitがホストのDockerデーモンとは別のコンテナ内で実行されるため、ホストのDockerデーモンへの影響を最小限に抑えられます。
  • ステートレス: ビルダーコンテナは停止・削除が容易で、クリーンな状態で再起動できます。CI環境などでの信頼性向上に繋がります。
  • 柔軟な設定: BuildKitデーモンの設定を細かく調整できます。

docker-containerビルダーの設定例:

CI環境のセットアップスクリプトなどで、最初に以下を実行することが多いです。

“`bash

BuildKitをコンテナとして実行するビルダーを作成 (存在しなければ)

docker buildx create –name mybuilder –driver docker-container –use

ビルダーがサポートするプラットフォームを確認し、必要ならブートストラップ

docker buildx inspect –bootstrap
“`

この設定により、その後のdocker buildx buildコマンドは作成したmybuilderインスタンス(BuildKitコンテナ)を使って実行されるようになります。

ビルダーインスタンスは、Buildxの柔軟性とパワーの基盤となります。最初はデフォルトビルダーで十分ですが、より高度な機能(特にマルチプラットフォームや外部キャッシュ)を利用する際には、docker-containerドライバーのビルダーを積極的に活用することを検討しましょう。

9. その他の便利な機能

Buildx/BuildKitは、ビルドプロセスをよりセキュアに、より柔軟にするための様々な追加機能を提供します。

9.1 ビルド secrets の利用 (--secret)

ビルド中に、外部サービスへのAPIキー、プライベートリポジトリのパスワードなどの秘匿情報が必要になることがあります。これらをDockerfileに直接書いたり、--build-argで渡したりするのはセキュリティ上好ましくありません(レイヤーに情報が残る可能性があるため)。

BuildKitは--secretオプションを使って、安全にビルドプロセスに秘匿情報を渡す機能を提供します。

まず、Dockerfile側でsecretを利用することを宣言します。

“`dockerfile

syntax=docker/dockerfile:1

FROM alpine:latest

secretをID ‘mysecret’ としてマウントすることを宣言

マウントポイントはデフォルトで /run/secrets/

RUN –mount=type=secret,id=mysecret \
apk add –no-cache curl \
# マウントされたsecretファイルを読み取って利用
&& curl -H “Authorization: token $(cat /run/secrets/mysecret)” https://api.github.com/…
“`

次に、Buildxコマンドでsecretファイルや環境変数を渡します。

  • ファイルから渡す:
    bash
    # secret_file.txt にAPIキーなどが書かれているとする
    docker buildx build . \
    --secret id=mysecret,src=secret_file.txt
  • 標準入力から渡す:
    bash
    # 環境変数からパイプで渡す例 (注意: 履歴に残らないように注意)
    cat secret_file.txt | docker buildx build . \
    --secret id=mysecret,src=/dev/stdin
    # あるいは、環境変数自体を渡す
    API_TOKEN="your_api_key" docker buildx build . \
    --secret id=mysecret,env=API_TOKEN

    src=/dev/stdin は標準入力をsecretとして読み込む指定です。env=ENV_VAR_NAME は指定した環境変数の値をsecretとして渡します。

BuildKitは、これらのsecret情報をビルドコンテナ内の指定されたマウントポイントに一時的に公開しますが、ビルドが完了するとその情報は破棄され、最終的なイメージレイヤーには含まれません。これにより、秘匿情報を安全に扱うことができます。

9.2 SSH エージェント転送 (--ssh)

ビルド中に、プライベートなGitリポジトリをクローンしたり、SSH経由でリソースにアクセスしたりする必要がある場合があります。これにはSSHキーが必要ですが、DockerfileにSSHキーを埋め込むのは非常に危険です。

BuildKitは--sshオプションを使って、ビルドコンテナからホストのSSHエージェントを利用できるようにします。

Dockerfile側でSSHマウントを宣言します。

“`dockerfile

syntax=docker/dockerfile:1

FROM alpine:latest

RUN apk add –no-cache git openssh-client

SSHマウントを宣言 (デフォルトIDは default)

RUN –mount=type=ssh \
git clone [email protected]:myorg/private-repo.git /app/private
“`

次に、BuildxコマンドでSSH転送を有効にします。

“`bash

ホストのSSHエージェントを利用してビルド

docker buildx build . –ssh default
“`

これで、ビルド中のRUN命令からSSHエージェントが利用可能になり、ホストに登録されているSSHキーを使ってプライベートリポジトリにアクセスできます。これもsecretと同様、SSHキー自体がイメージレイヤーに含まれることはありません。

9.3 多様な出力形式 (--output) の詳細

--outputオプションはBuildxの柔軟性を高める重要な機能です。前述のtype=image, type=tar, type=registry に加えて、いくつかの便利なタイプがあります。

  • type=local: ビルド結果を、イメージとしてではなく、指定したローカルディレクトリにファイルとして出力します。Dockerfileで生成した特定のファイル(例:コンパイルされたバイナリ、設定ファイル、レポートなど)だけを取り出したい場合に便利です。

    “`bash

    ビルド結果を作業ディレクトリの ‘output’ サブディレクトリに出力

    docker buildx build . –output type=local,dest=./output
    ``.はビルドコンテキストを指しますが、dest=./output`はホスト側のローカルファイルシステム上のパスを指します。

  • type=cacheonly: イメージ本体は生成せず、ビルド中に得られたキャッシュデータのみをエクスポートします。これは、キャッシュを更新するだけのビルドパイプラインなどに使えます。

    “`bash

    ビルドは実行し、得られたキャッシュだけをレジストリにプッシュ

    docker buildx build . \
    –cache-to type=registry,ref=your-repo/your-image:buildcache,mode=max \
    –output type=cacheonly
    “`

--outputオプションでは、カンマ区切りで複数のオプションを指定できます。

  • name=: 出力するイメージ名/タグを指定します。type=imagetype=registryで使います。複数の名前を指定することも可能です(例: name=image:latest,image:v1.0)。
  • push=true/false: type=registryの場合、ビルド完了後にイメージをプッシュするかどうかを指定します。--pushフラグは--output type=registry,push=trueのショートカットです。
  • dest=: type=tartype=localの場合、出力先のパスを指定します。
  • mode=: type=cacheonlytype=registry (キャッシュエクスポート時) でキャッシュのエクスポートモードを指定します (maxまたはmin)。
  • oci=true/false: type=tartype=localtype=registryの場合、OCI形式で出力するかDocker形式で出力するかを指定します。デフォルトはドライバに依存しますが、明示的に指定できます。

--outputオプションを組み合わせることで、Buildxビルドの成果物を非常に柔軟に制御できます。例えば、マルチプラットフォームイメージをビルドしてプッシュしつつ、ビルドキャッシュも同時にプッシュするといったことが、単一のdocker buildx buildコマンドで実現可能です。

bash
docker buildx build . \
--platform linux/amd64,linux/arm64 \
-t your-repo/your-image:latest \
--cache-to type=registry,ref=your-repo/your-image:buildcache,mode=max \
--output type=registry,push=true

このコマンドは、まず指定されたプラットフォーム向けのイメージをビルドし、ビルド中に生成されたキャッシュをyour-repo/your-image:buildcacheとしてレジストリにプッシュします。そして、ビルドされたマルチプラットフォームイメージ本体をyour-repo/your-image:latestとしてレジストリにプッシュします。

10. 実践的なシナリオ:CI/CDでのBuildx活用

Buildxの真価は、CI/CDパイプラインのような自動化されたビルド環境で最大限に発揮されます。高速化、効率化、マルチプラットフォーム対応といったBuildxのメリットは、CI/CDの実行時間を短縮し、パイプラインの信頼性を向上させ、様々な環境へのデプロイを容易にします。

10.1 CI/CDでのBuildx導入ステップ

CI/CDパイプラインでBuildxを導入する一般的なステップは以下のようになります。

  1. Buildx CLIのインストール/有効化: CIエージェント/ランナーに必要なDockerバージョンがインストールされており、Buildxが利用可能であることを確認します。多くのマネージドCIサービス(GitHub Actions, GitLab CI, CircleCIなど)では、Docker EngineとともにBuildxも利用できるようになっています。
  2. ビルダーインスタンスのセットアップ: BuildKitの機能をフルに活用するため、docker-containerドライバーを使ったビルダーインスタンスを作成して使用するのが推奨されます。多くのCI環境向けのBuildx Action/Orb/Extensionは、このセットアップを自動的に行ってくれます。
    “`yaml
    # GitHub Actions の例 (docker/setup-buildx-action を使用)

    • name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v2
      “`
      これにより、ジョブ内でBuildxコマンドが利用できるようになり、BuildKitコンテナがバックエンドとしてセットアップされます。
  3. Dockerレジストリへのログイン: ビルドしたイメージをプッシュしたり、レジストリキャッシュを利用したりするために、CI環境からターゲットとなるDockerレジストリへの認証を行います。
    “`yaml
    # GitHub Actions の例 (docker/login-action を使用)

    • name: Log in to Docker Hub
      uses: docker/login-action@v2
      with:
      username: ${{ secrets.DOCKER_HUB_USERNAME }}
      password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}

    または GHCR (GitHub Container Registry)

    • name: Log in to the Container registry
      uses: docker/login-action@v2
      with:
      registry: ghcr.io
      username: ${{ github.actor }}
      password: ${{ secrets.GITHUB_TOKEN }}
      “`
    • Buildx ビルドコマンドの実行: docker buildx buildコマンドを実行します。
    • マルチプラットフォームビルド: --platformオプションでターゲットプラットフォームを指定します。
    • レジストリへのプッシュ: --pushオプション(または--output type=registry,push=true)でビルド完了後にイメージをプッシュします。
    • キャッシュの活用: --cache-fromで既存のキャッシュを読み込み、--cache-toで新しいキャッシュを保存します。レジストリキャッシュがCI/CDでは一般的です。

    “`yaml

    GitHub Actions での Buildx ビルド例

    • name: Build and Push Docker image
      uses: docker/build-push-action@v4
      with:
      context: .
      platforms: linux/amd64,linux/arm64
      push: true
      tags: ghcr.io/${{ github.repository }}:latest
      cache-from: type=registry,ref=ghcr.io/${{ github.repository }}:buildcache
      cache-to: type=registry,ref=ghcr.io/${{ github.repository }}:buildcache,mode=max
      ``
      このGitHub Actionsの例では、
      docker/build-push-action`という公式アクションを利用しています。これは内部でBuildxコマンドを実行しており、キャッシュやマルチプラットフォームプッシュを簡単に設定できます。

10.2 CI/CDにおけるBuildxのメリット

  • ビルド時間の短縮:
    • BuildKitの並列処理により、ビルドステップ全体が高速化されます。
    • --mount=type=cacheと外部キャッシュ (--cache-to/--cache-from) により、依存ライブラリのダウンロードやコンパイル済みの成果物を再利用でき、特に変更が少ない場合のビルドが大幅に高速化されます。CIの実行時間はコストに直結するため、これは大きなメリットです。
  • マルチプラットフォーム対応の簡素化: 単一のCIジョブで複数のアーキテクチャ向けのイメージをビルドし、マニフェストリストとしてまとめてプッシュできるため、パイプラインの複雑性が軽減されます。これにより、異なる環境へのデプロイ戦略がシンプルになります。
  • パイプラインの信頼性向上: docker-containerビルダーはステートレスで、ビルド間の分離性が高いため、CIエージェントの状態に依存しにくく、より信頼性の高いビルドが実現できます。ビルドキャッシュも外部で管理されるため、エージェントが入れ替わってもキャッシュを利用できます。
  • セキュリティ: --secret--sshオプションにより、APIキーやSSHキーなどの秘匿情報を安全にビルドプロセスに渡せます。
  • 多様な出力: ビルド結果を直接レジストリにプッシュしたり、別のステージで利用するためにファイルとして出力したりと、パイプラインの設計に合わせて柔軟な出力が可能です。

CI/CDパイプラインでBuildxを導入することは、Dockerビルドのモダンなベストプラクティスと言えます。多くのCIサービスがBuildxとの連携をサポートしているため、比較的容易に導入を進めることができます。

11. トラブルシューティングとよくある質問

Buildxを利用する上で遭遇する可能性のある問題や疑問点について説明します。

  • docker: 'buildx' is not a docker command. と表示される
    • お使いのDockerのバージョンが古い可能性があります。BuildxはDocker Engine 19.03 以降、またはDocker Desktopに含まれています。Dockerを最新版にアップデートしてみてください。
    • Linux環境の場合、BuildxがCLIプラグインとして正しくインストールされていない可能性があります。Dockerのインストール方法やBuildxの公式インストールガイドを確認してください。
  • docker buildx ls を実行しても何も表示されない、あるいは default ビルダーがない
    • Buildxがインストールされていても、まだ一度もビルダーインスタンスが作成されていない可能性があります。docker buildx create --name mybuilder --use のようにコマンドを実行して、新しいビルダーを作成し、使用するように設定してみてください。
  • ビルダーインスタンスが inactive または error 状態になる
    • docker-container ドライバーを使用している場合、BuildKitコンテナが停止しているか、起動に失敗している可能性があります。docker buildx inspect --bootstrap コマンドで起動を試み、エラーメッセージを確認してください。
    • 権限の問題かもしれません。特にLinuxでdocker-containerドライバーや--privilegedが必要なコマンド(tonistiigi/binfmtなど)を実行する場合、ユーザーがdockerグループに所属しているか、sudoが必要ないか確認してください。
    • デフォルトのdockerドライバーの場合、ホストのDockerデーモンに問題がある可能性があります。docker infoやデーモンログを確認してください。
  • マルチプラットフォームビルドが遅い、または exec user process caused: exec format error のようなエラーが出る
    • これは、異なるアーキテクチャのバイナリを実行しようとして失敗している典型的なエラーです。QEMUエミュレーションが正しく設定されていない可能性が高いです。
    • docker run --privileged --rm tonistiigi/binfmt --install all コマンドを実行して、必要なエミュレーターがホストOSに登録されているか確認してください。このコマンドは、ホストOSのbinfmt_misc設定を更新するため、多くの場合--privileged権限が必要です。
    • Docker Desktopや一部のCI環境では自動的に設定されますが、セルフホストのDocker Engineなどでは手動設定が必要です。
  • --mount=type=cache を使ってもキャッシュが効かない
    • Dockerfileの先頭に# syntax=docker/dockerfile:1のようなBuildKitシンタックス指定を忘れていませんか?
    • --mountオプションは特定のRUN命令に付随します。同じDockerfileでも、別のRUN命令ではそのキャッシュは利用できません。
    • キャッシュ対象のディレクトリが正しいか(例:npmキャッシュなら/root/.npmなど、使用しているイメージやユーザーによってパスが異なります)確認してください。
    • 依存するファイル(例:package.jsonrequirements.txtなど)が変更された場合、キャッシュは無効になります。
    • ビルダーインスタンスを変更したり再作成したりすると、以前のキャッシュが利用できなくなることがあります。docker buildx du コマンドでキャッシュの使用状況を確認できます。
  • ビルド後のイメージが docker images で見えない
    • docker buildx build のデフォルト出力はtype=imageですが、--pushオプションを使うと、デフォルト出力がtype=registryになり、ローカルデーモンには保存されません。ローカルにも保存したい場合は、--output type=image,type=registry,push=trueのように複数指定が必要です。
  • ディスク容量が不足する
    • BuildKitのキャッシュは、適切に管理しないとディスク容量を消費します。
    • docker buildx du コマンドでBuildKitキャッシュの使用量を確認できます。
    • docker buildx prune コマンドで不要なキャッシュを削除できます。
      bash
      docker buildx prune --all --force

      --allは全て(停止中のビルダー関連含む)、--forceは確認プロンプトなしで削除を実行します。注意して実行してください。

これらのトラブルシューティングのヒントは、Buildx利用時に遭遇しやすい問題に対処するのに役立つでしょう。

12. まとめ:Buildxで未来のDockerビルドへ

この記事では、Docker Buildxがなぜ必要とされているのか、そのバックエンドであるBuildKitの強力な機能(並列処理、高度なキャッシュ、マルチプラットフォーム対応)がどのようにビルドを高速化・効率化するのか、そしてBuildxの基本的な使い方から高度な機能、CI/CDでの活用法までを詳細に解説しました。

従来のdocker buildはシンプルで多くの用途に十分ですが、現代の開発ワークフロー、特に高速なCI/CDや多様なプラットフォームへの対応が求められる環境では、Buildxが提供する機能は必須となりつつあります。

Buildxを利用することで:

  • ビルド時間が大幅に短縮されます。
  • マルチプラットフォームイメージのビルドが驚くほど簡単になります。
  • ビルドキャッシュを効率的に管理し、CI/CDパイプラインを高速化できます。
  • 秘匿情報を安全にビルドプロセスに渡せます。
  • ビルド成果物を柔軟な形式で出力できます。

BuildxとBuildKitは、Dockerビルドの未来を担う技術です。最初は少し慣れが必要かもしれませんが、一度そのパワーを知れば、従来のビルド方法には戻れなくなるでしょう。

この記事が、あなたのBuildx入門の一助となり、より快適で強力なDockerビルドライフを送るための一歩となれば幸いです。ぜひ今日からBuildxを使ってみて、その違いを体感してください。

13. 付録:関連リソース


以上で、約5000語の詳細なDocker Buildx入門記事となります。初心者の方にも理解しやすいように、各機能の目的や仕組み、具体的なコマンド例、実践的なシナリオなどを盛り込みました。

コメントする

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

上部へスクロール