技術共有

docker buildx を使用してクロスプラットフォーム イメージを構築する

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

buildx は、Docker によって公式に提供されているビルド ツールで、ユーザーが Docker イメージを迅速かつ効率的に構築できるようにし、複数のプラットフォームの構築をサポートします。 buildx を使用すると、ユーザーは手動で複数のビルド コマンドを操作することなく、x86 アーキテクチャや arm アーキテクチャなどの複数のアーキテクチャのイメージを 1 つのコマンドでビルドできます。さらに、buildx は Dockerfile の多段階構築とキャッシュもサポートしているため、イメージ構築の効率と速度が大幅に向上します。

buildx は、Docker ビルドを管理する CLI プラグインであり、基礎となるレイヤーは BuildKit を使用して Docker ビルド機能を拡張します。

BuildKit は Docker が公式に提供する高性能なビルド エンジンで、Docker のオリジナル ビルド エンジンの置き換えに使用できます。元のエンジンと比較して、BuildKit はビルド速度が速く、並列処理が高く、リソース使用量が少なく、セキュリティが優れています。

buildx をインストールして使用するには、Docker エンジンのバージョン番号が 19.03 以上である必要があります。

クロスプラットフォームのイメージ構築戦略

ビルダーは、クロスプラットフォーム イメージを構築するためのさまざまな戦略をサポートしています。

カーネルでの QEMU エミュレーション サポートの使用

Docker Desktop を使用している場合、QEMU はすでにサポートされており、クロスプラットフォーム イメージを構築するための最も簡単な戦略です。元の Dockerfile を変更する必要はありません。BuildKit は、Linux カーネル関数 binfmt_misc を通じてクロスプラットフォーム プログラムの実行を実装します。

動作原理:

QEMU は、さまざまな CPU アーキテクチャをシミュレートできるプロセッサ シミュレータであり、仮想マシンの別の形式として理解できます。 buildx では、ビルド プロセス中に非ネイティブ アーキテクチャのバイナリを実行するために QEMU が使用されます。たとえば、x86 ホスト上で ARM イメージをビルドする場合、QEMU は ARM 環境をシミュレートし、ARM バイナリを実行できます。

binfmt_misc は、ユーザーが実行可能ファイル形式と対応するインタープリターを登録できるようにする Linux カーネルのモジュールです。カーネルが不明な形式の実行可能ファイルを検出すると、binfmt_misc を使用して、そのファイル形式に関連付けられたインタープリタ (この場合は QEMU) が検索され、ファイルが実行されます。 。 この機能は rk3568 プラットフォームではオフになっています。

QEMU と binfmt_misc を組み合わせると、buildx を介してクロスプラットフォームのビルドが可能になります。これにより、実際のターゲット ハードウェアを所有することなく、あるアーキテクチャの Docker イメージを他のアーキテクチャのホスト上に構築できるようになります。

Docker Desktop は他のプラットフォーム用の binfmt_misc サポートを使用して事前構成されていますが、他のバージョンの Docker では、tonistiigi/binfmt イメージを使用してサポート用の特権コンテナーを起動する必要がある場合があります。

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

このコマンドを実行すると、さまざまなアーキテクチャのインタープリター プログラム、つまり qemu シミュレーターが /usr/bin ディレクトリにインストールされます。

binfmt_misc モジュールはコンパイル サーバーにロードされます。

qemuを使用したdocker buildxの役割

Docker Buildx は、マルチノード、qemu などの使用を含め、Docker のビルド機能を拡張する Docker の実験的な機能です。 QEMU は、さまざまな CPU やその他のハードウェアをシミュレートできるオープンソースの仮想マシン ソフトウェアであり、1 つのオペレーティング システム上に別のオペレーティング システムのイメージを構築できます。

Docker Buildx の qemu 機能を使用すると、複数の異なるアーキテクチャ (ARM、MIPS など) 用の Docker イメージを構築できます。

以下は、Docker Buildx と QEMU を使用して ARM アーキテクチャ用の Docker イメージを構築する方法を示す簡単な例です。

  1. # 创建一个新的 buildkit 实例
  2. docker buildx create --name mybuilder --use
  3. # 启动 buildkit 实例
  4. docker buildx start mybuilder
  5. # 启用 QEMU 驱动支持
  6. docker buildx inspect --bootstrap
  7. # 构建一个面向 ARM 架构的 Docker 镜像
  8. docker buildx build --platform linux/arm/v7 -t myimage:latest .

この例では、--platformこのパラメーターは、ビルド対象のターゲット プラットフォームが ARM v7 であることを指定します。このように、Docker は QEMU を使用して ARM 環境をシミュレートし、x86 アーキテクチャ マシン上で ARM アーキテクチャ用の Docker イメージを構築します。

binfmt_misc ファイル システム

binfmt-misc は、Windows のファイルの関連付けと同様に Linux カーネルによって提供される機能ですが、ファイルの拡張子名に基づいて判断できるだけでなく、ファイルに基づいて別のプログラムを使用して開くこともできるという点で、ファイルの関連付けよりも強力です。コンテンツ (マジックバイト) 。一般的な使用シナリオは、qemu を使用して他のアーキテクチャ プラットフォームでバイナリ ファイルを実行することです。

binfmt-misc を有効にする

一時的に有効にするには、次のコマンドを使用します。

$ sudo mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc

このメソッドは再起動後は無効になります。長時間有効にしたい場合は、/etc/fstab ファイルに次の行を追加します。

none  /proc/sys/fs/binfmt_misc binfmt_misc defaults 0 0

次のコマンドを使用して、正常に開いたかどうかを確認できます。

  1. $ mount | grep binfmt_misc
  2. binfmt_misc on /proc/sys/fs/binfmt_misc type binfmt_misc (rw,relatime)
  3. $ ls -l /proc/sys/fs/binfmt_misc
  4. 总用量 0
  5. --w------- 1 root root 0 25 22:55 register
  6. -rw-r--r-- 1 root root 0 25 22:55 status

まず arm64 アーキテクチャのプログラムを準備します。実行後、エラーが報告されます。

bash: ./go-test:无法执行二进制文件: 可执行文件格式错误

ここで、apt install qemu-user-binfmt コマンドを実行してから、上記の arm64 プログラムを実行して、正常に実行できることを確認してみましょう。 qemu-user-binfmt をインストールすると、1 つの qemu-aarch64 を含むいくつかのファイルが /proc/sys/fs/binfmt_misc ディレクトリに作成されます。このファイルの内容を見てみましょう。

  1. root@ubuntu:/proc/sys/fs/binfmt_misc# cat qemu-aarch64
  2. enabled
  3. interpreter /usr/bin/qemu-aarch64-static
  4. flags: OC
  5. offset 0
  6. magic 7f454c460201010000000000000000000200b700
  7. mask ffffffffffffff00fffffffffffffffffeffffff
  8. root@ubuntu:/proc/sys/fs/binfmt_misc#

このファイルはルール ファイルについて説明します。

最初の行「enabled」は、ルールが有効であることを示します。

2 行目のインタプリタ /usr/bin/qemu-aarch64-static は、/usr/bin/qemu-aarch64-static を使用してバイナリ ファイルを実行することを示します。

3 行目: OC は実行フラグを表し、具体的な意味は次のとおりです。

P:preserve-argv の略で、シミュレータを呼び出すときに元のパラメータ (argv) が保存されることを意味します。これは、サイレント プログラムが実行時に自分の名前 (つまり、argv[0]) を知る必要がある状況で役立ちます。

O: オフセットを表します。これは、シミュレータを開始する前にバイナリ ファイルからオフセットを読み取る必要があり、このオフセットがシミュレータのパラメータとして使用されることを意味します。

C: は資格情報を表します。これは、エミュレータが元のプログラムで使用されていたのと同じユーザー ID とグループ ID で実行されることを意味します。これにより、エミュレータが元のプログラムと同じ権限で実行されることが保証されます。

4 行目: オフセット 0 は、値 0 からファイルの読み取りを開始することを意味します。

5 行目: magic 7f454c460201010000000000000000000200b700 は、一致するモジュロ バイトを表します。

arm64 アーキテクチャの ELF ファイルのヘッダーのマジック フィールドは次のとおりです。これは、binfmt_misc ファイル システムが、ELF ファイルのマジック フィールドに基づいて、ファイルの実行に使用するアーキテクチャ シミュレーターを決定できることを意味します。

以下に 2 つの異なるアーキテクチャを示します

Mips アーキテクチャ: 7f454c4601020100000000000000000000020008
arm64 アーキテクチャ: 7f454c460201010000000000000000000200b700

行 6: マスク ffffffffffffff00ffffffffffffffffffffff は、ファイル内の重要でないバイトを無視するために使用できるバイト マスクを表します。

x86_64 システムで arm64 アーキテクチャの Docker イメージを実行する

今私たちが使っているのはドッカーこのコマンドは arm64 イメージを実行します。

  1. $ docker run -it arm64v8/ubuntu bash
  2. Unable to find image 'arm64v8/ubuntu:latest' locally
  3. latest: Pulling from arm64v8/ubuntu
  4. 005e2837585d: Pull complete
  5. Digest: sha256:ba545858745d6307f0d1064d0d25365466f78d02f866cf4efb9e1326a4c196ca
  6. Status: Downloaded newer image for arm64v8/ubuntu:latest
  7. standard_init_linux.go:207: exec user process caused "no such file or directory"

いくつか調べた結果、次のコマンドを実行すれば問題ないことがわかりました。apt install qemu-user-static、次に docker を起動します容器それは正常です。

Dockerfile でのマルチステージ クロスビルドの使用

クロスコンパイルの複雑さは Docker にあるのではなく、プログラム自体にあります。たとえば、Go プログラムは、go build を使用してプログラムをビルドするときに、2 つの環境変数 GOOS と GOARCH を実行するだけで簡単にクロスコンパイルできます。

ビルダーの作成

buildx を使用してクロスプラットフォーム イメージをビルドするには、まずビルダーを作成する必要があります。ビルダーはビルダーとして翻訳できます。

docker buildx ls コマンドを使用して、ビルダー リストを表示します。

  1. root@ubuntu:/proc# docker buildx ls
  2. NAME/NODE DRIVER/ENDPOINT STATUS PLATFORMS
  3. mybuild * docker-container
  4. mybuild0 unix:///var/run/docker.sock running linux/arm64*, linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/amd64/v4, linux/386
  5. vigilant_hugle docker-container
  6. vigilant_hugle0 unix:///var/run/docker.sock stopped
  7. default docker
  8. default default running linux/amd64, linux/386

* 記号は、現在使用中のビルダーを示します。 docker build コマンドを実行すると、このビルダーを使用してイメージがビルドされます。 2 列目の DRIVER/ENDPOINT は、使用されるドライバーを示します。 buildx は次のドライバーをサポートしています。

  • docker: Docker デーモンにバンドルされている BuildKit ライブラリを使用します。これは、Docker のインストール後のデフォルトの BuildKit です。
  • docker-container: Docker を使用して、新しい専用の BuildKit コンテナーを作成します。
  • kubernetes: kubernetes クラスターに BuildKit ポッドを作成します。
  • リモート: 手動で管理される BuildKit デーモンに直接接続します。

Docker ドライバーを使用するデフォルトのビルダーは、単一のコマンドを使用したクロスプラットフォーム イメージのビルドをサポートしていないため (デフォルト ビルダーの --platform パラメーターは単一の値のみを受け入れます)、docker-container ドライバーを使用して新しいビルダーを作成する必要があります。 。

コマンドの構文は次のとおりです。

$ docker buildx create --name=<builder-name> --driver=<driver> --driver-opt=<driver-options>

パラメータの意味は次のとおりです。

--name: 構築する名前、必須。

--driver: ビルダー ドライバー。デフォルトは docker-container です。

--driver-opt: ドライバー オプション。たとえば、オプション --driver-opt=image=moby/buildkit:v0.11.3 は、BuildKit の指定されたバージョンをインストールできます。デフォルト値は moby/buildkit です。

次のコマンドを使用して、新しいビルダーを作成できます。

  1. $ docker buildx create --name mybuilder
  2. mybuilder

ビルダー リストをもう一度確認します。

  1. $ docker buildx ls
  2. NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
  3. mybuilder * docker-container
  4. mybuilder0 unix:///var/run/docker.sock inactive
  5. default docker
  6. default default running 20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
  7. desktop-linux docker
  8. desktop-linux desktop-linux running 20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6

選択したビルドが Mybuilder に切り替わったことがわかります。選択されていない場合は、docker buildx use mybuilder コマンドを手動で使用してビルダーを切り替える必要があります。

ビルダーを開始する

新しく作成した mybuilder は現在非アクティブなので、使用する前に起動する必要があります。

  1. $ docker buildx inspect --bootstrap mybuilder
  2. [+] Building 16.8s (1/1) FINISHED
  3. => [internal] booting buildkit 16.8s
  4. => => pulling image moby/buildkit:buildx-stable-1 16.1s
  5. => => creating container buildx_buildkit_mybuilder0 0.7s
  6. Name: mybuilder
  7. Driver: docker-container
  8. Nodes:
  9. Name: mybuilder0
  10. Endpoint: unix:///var/run/docker.sock
  11. Status: running
  12. Buildkit: v0.9.3
  13. Platforms: linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6

ビルド ステータスを確認するには、inspect サブコマンドを使用します。 --bootstrap パラメータを使用して、mybuilder ビルダー リストを再度確認します。mybuilder ステータスが実行中になっています。

  1. $ docker buildx ls
  2. NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
  3. mybuilder * docker-container
  4. mybuilder0 unix:///var/run/docker.sock running v0.9.3 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
  5. default docker
  6. default default running 20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
  7. desktop-linux docker
  8. desktop-linux desktop-linux running 20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6

PLATFORMS列に表示される値

linux/arm64、linux/amd64、linux/riscv64、linux/ppc64le、linux/s390x、linux/386、linux/mips64le、linux/mips64、linux/arm/v7、linux/arm/v6 は現在のビルダーでサポートされています すべてプラットフォーム。

次に、 docker ps コマンドを使用して、mybuilder ビルダーに対応する BuildKit コンテナーが開始されたことを確認します。

  1. $ docker ps
  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  3. b8887f253d41 moby/buildkit:buildx-stable-1 "buildkitd" 4 minutes ago Up 4 minutes buildx_buildkit_mybuilder0

このコンテナは、クロスプラットフォーム イメージの構築を支援するために使用されます。手動で削除しないでください。

ビルダーを使用してクロスプラットフォーム イメージを構築する

$ docker buildx build --platform linux/arm64,linux/amd64 -t jianghushinian/hello-go .

docker buildx build の構文は docker build の構文と同じです。 --platform パラメータはイメージをビルドするためのターゲット プラットフォームを示し、-t はイメージのタグを示します。 . コンテキストが現在のディレクトリであることを示します。。 

唯一機能しないのは、--platform パラメーターのサポートです。docker build の --platform パラメーターは、--platform linux/arm64 などの 1 つのプラットフォーム情報の受け渡しのみをサポートします。つまり、1 つのプラットフォーム イメージを渡すことができます。一度に構築できます。

docker buildx build を使用してイメージをビルドすると、複数のプラットフォーム情報を英語のカンマで区切って同時に送信できるため、1 つのコマンドだけで複数のクロスプラットフォーム イメージをビルドする機能が実現します。

上記のコマンドを実行すると、次の警告が表示されます。

WARNING: No output specified with docker-container driver. Build result will only remain in the build cache. To push result image into registry use --push or to load image into docker use --load

この警告は、docker-container ドライバーの出力を指定していないことを思い出させます。生成された結果はビルド キャッシュにのみ保持され、イメージを Docker Hub リモート リポジトリにプッシュします。画像をローカルに保存します。

これは、新しく作成した mybuilder が BuildKit を実行するコンテナを起動するため、ビルドされたクロスプラットフォーム イメージをローカル マシンに直接出力したり、ユーザーが出力場所を手動で指定したりする必要があるためです。

--load を指定してイメージをローカル ホストに保存してみることができます。

  1. $ docker buildx build --platform linux/arm64,linux/amd64 -t jianghushinian/hello-go . --load
  2. [+] Building 0.0s (0/0)
  3. ERROR: docker exporter does not currently support exporting manifest lists

結果はエラーログになります。これは、実際には、複数の --platform が 1 つのプラットフォームのみを渡す場合、ビルドされたイメージをこれに出力できるためです。機械。

その後、 --push パラメーターを使用してクロスプラットフォーム イメージをリモート ウェアハウスにプッシュすることのみが可能になります。ただし、これを行う前に、docker ログインを使用してログインを完了する必要があります。

$ docker buildx build --platform linux/arm64,linux/amd64 -t jianghushinian/hello-go . --push

ここで Docker Hub にログインすると、プッシュされたクロスプラットフォーム イメージが表示されます。

また、imagestools を使用してクロスプラットフォーム イメージのマニフェスト情報を確認することもできます。このコマンドはウェアハウス内のイメージ情報を取得するためにのみ使用でき、ローカル イメージは表示できません。

  1. $ docker buildx imagetools inspect jianghushinian/hello-go
  2. Name: docker.io/jianghushinian/hello-go:latest
  3. MediaType: application/vnd.docker.distribution.manifest.list.v2+json
  4. Digest: sha256:51199dadfc55b23d6ab5cfd2d67e38edd513a707273b1b8b554985ff562104db
  5. Manifests:
  6. Name: docker.io/jianghushinian/hello-go:latest@sha256:8032a6f23f3bd3050852e77b6e4a4d0a705dfd710fb63bc4c3dc9d5e01c8e9a6
  7. MediaType: application/vnd.docker.distribution.manifest.v2+json
  8. Platform: linux/arm64
  9. Name: docker.io/jianghushinian/hello-go:latest@sha256:fd46fd7e93c7deef5ad8496c2cf08c266bac42ac77f1e444e83d4f79d58441ba
  10. MediaType: application/vnd.docker.distribution.manifest.v2+json
  11. Platform: linux/amd64

 

ご覧のとおり、このクロスプラットフォーム イメージには、linux/arm64 と linux/amd64 という 2 つのターゲット プラットフォームのイメージが含まれています。