🐋

雰囲気でbuildx/BuildKitを使っていたので調べました

2024/01/11に公開

tl;dr

  • BuildKitのお陰で様々なbuildでの恩恵が受けられている
  • buildxのお陰で今まで利用していたdockercliのままBuilkdKitが使えている
  • もっと有効活用したい機能が沢山ある。。。
  • 長いです。。。こちらのNTTの徳永さんのスライドがとてもわかり易い & 纏まっていておすすめです

はじめに

相当前ですが、dockerにbuildxコマンドが入ったことでなんとなくBuildKitというものを認識して使っていました。

ただ、その中でもmulti-platform buildを雰囲気で使っていたくらいで、
他にどういう機能があるのか、そもそもBuildKitって何?みたいなことはあまり考えていませんでした。

先日、--mount=type=sshを使うときに少し嵌って調べたところ、様々な機能や重要なconceptを知らなかったことに気づいたので調べたことをまとめたいと思います。

出てくる用語について

buildxとBuildKitの関係性も怪しいのでそこから調べました。

また、その際に出てきた重要そう、かつ知らなかった用語のMobyやbuildxの用語のbuild driver, builder instance等についてもここで纏めます。

用語の理解を深めるために軽く手を動かした詳細についても記載します。

buildx

buildx is a Docker CLI plugin for extended build capabilities with BuildKit.
https://github.com/docker/buildx

とのことで、BuildKitをDockerから利用するための拡張のようです。
(プラスbakeなどのBuildKit利用以外の機能も含まれている。)

また、build driver(後述)の1つであるdocker driverの説明にはこの様に書かれていて、

The Buildx Docker driver is the default driver. It uses the BuildKit server components built directly into the Docker engine.
https://docs.docker.com/build/drivers/docker/

BuildKitサーバはDocker engineに組み込まれて提供されていること。
defaultではその組み込まれたBuildKitサーバコンポーネントを利用することが分かりました。

build driver

先程出てきましたBuild driverについてです。

Build drivers are configurations for how and where the BuildKit backend runs.
https://docs.docker.com/build/drivers/

BuildKitバックエンドをどこでどの様に動かすのかを定める定義とのことです。
ここでのBuildKit backendはプロセスと同じような意味で使われていると思われます。

ここにDocker Buildに関するbuildxとBuildKitの関係図とシーケンス図が記載されています。

build driverは以下の4種類のdriverをサポートしています。

  1. docker
    1. default driver
    2. DockerデーモンにバンドルされたBuildKitライブラリを使う
  2. docker-container
    1. BuildKitコンテナをDocker上で動かして使う
  3. kubernetes
    1. BuildKitポッドをKubernetes cluster上に動かして使う
  4. remote
    1. 別に管理されたBuildKitデーモンに直接接続して使う

また、以下の図のようにそれぞれのdriverごとに微妙にできることも変わってくるようです。


https://docs.docker.com/build/drivers/ より参照

builder instance

builder instanceについては明確に説明されている文章を見つけられなかったのですが、
builder instanceを作成するbuildx createの説明から想像して書きます。

builder instanceは実際にbuildx build時に使うdriver, buildkitd flag,BuildKit config,platformなどの設定の集合体かと思われます。

[確認] build driver/builder instance

builder instanceを確認するbuildx lsコマンドの出力を見てみます。

$ docker buildx ls
NAME/NODE       DRIVER/ENDPOINT  STATUS  BUILDKIT             PLATFORMS
desktop-linux * docker
  desktop-linux desktop-linux    running v0.11.6+616c3f613b54 linux/arm64, linux/amd64, linux/amd64/v2, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6

docker driverをつかうdesktop-linux builder instanceが設定されていますね。
ここは何もいじっていないのでDocker Desktopインストール時にbuildxがdefaultでこのあたりを定義してくれているということでしょうか。

試しに別のbuilder instanceを作成し動かしてみます。

$ docker buildx use $(docker buildx create --name new)
$ docker buildx ls
NAME/NODE       DRIVER/ENDPOINT  STATUS   BUILDKIT             PLATFORMS
new *           docker-container
  new0          desktop-linux    inactive
desktop-linux   docker
  desktop-linux desktop-linux    running  v0.11.6+616c3f613b54 linux/arm64, linux/amd64, linux/amd64/v2, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6

定義したnew builder instanceが増えて、かつ現在はそちらを向いていそうですね。
ただ、STATUSinactiveとなっています。これはBuildKit containerがまだ起動してない状態かと思われます。

buildx create--driverオプションには、

Driver to use (available: docker-container, kubernetes, remote)

と記載されていて、docker driverは2つ目は定義できなさそうでした。
また、指定しなかった場合はdocker-container driverが選択されましたね。

実際にbuildをしようと思います。build中の動きを少し見れるように以下のdockerfileを使います。

dockerfile
FROM alpine

RUN sleep 30s
$ docker buildx build .
[+] Building 41.3s (6/6) FINISHED                                                                                            docker-container:new
 => [internal] booting buildkit                                                                                                              8.2s
 => => pulling image moby/buildkit:buildx-stable-1                                                                                           7.4s
 => => creating container buildx_buildkit_new0                                                                                               0.8s
 => [internal] load build definition from dockerfile                                                                                         0.0s
 => => transferring dockerfile: 64B                                                                                                          0.0s
 => [internal] load metadata for docker.io/library/alpine:latest                                                                             2.2s
 => [internal] load .dockerignore                                                                                                            0.0s
 => => transferring context: 2B                                                                                                              0.0s
 => [1/2] FROM docker.io/library/alpine:latest@sha256:51b67269f354137895d43f3b3d810bfacd3945438e94dc5ac55fdac340352f48                       0.5s
 => => resolve docker.io/library/alpine:latest@sha256:51b67269f354137895d43f3b3d810bfacd3945438e94dc5ac55fdac340352f48                       0.0s
 => => sha256:c303524923177661067f7eb378c3dd5277088c2676ebd1cd78e68397bb80fdbf 3.35MB / 3.35MB                                               0.3s
 => => extracting sha256:c303524923177661067f7eb378c3dd5277088c2676ebd1cd78e68397bb80fdbf                                                    0.1s
 => [2/2] RUN sleep 30s                                                                                                                     30.1s
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

最初に

[internal] booting buildkit
=> => pulling image moby/buildkit:buildx-stable-1

と見えましたね。docker-container driverなので、BuildKitのcontainer imageを取得し、動かしてくれているログのようです。

containerを確認してみると、たしかにBuildKit containerが動いていますね。

$ docker ps
CONTAINER ID   IMAGE                           COMMAND                  CREATED         STATUS                PORTS                                                                      NAMES
2f4c6351ca39   moby/buildkit:buildx-stable-1   "buildkitd"              4 seconds ago   Up 3 seconds                                                                                     buildx_buildkit_new0

最初はinactiveであったSTATUSactiveになりました。

$ docker buildx ls
NAME/NODE       DRIVER/ENDPOINT  STATUS   BUILDKIT             PLATFORMS
new *           docker-container
  new0          desktop-linux    running  v0.12.4              linux/arm64, linux/amd64, linux/amd64/v2, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
desktop-linux   docker
  desktop-linux desktop-linux    running  v0.11.6+616c3f613b54 linux/arm64, linux/amd64, linux/amd64/v2, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6

また、buildログの最後に出力された

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

については、build driver 項目に貼った表のとおり、
Automitically load Imagedocker driverだけの機能なので、それ以外のdriverを使う場合にはbuild結果をどうしたいかを記載しないとだめなようですね。

buildx buildのoptionに--pushを指定してregistryにpushするか、--loadを指定してdockerにloadさせる方法をWARNINGとして提案してくれています。

BuildKit

BuildKitに辿り着く前が長くなってしまいましたがようやくBuildKitです。
ここまででおおよそ分かってきましたが、buildxの内部でも利用されているbuildを高機能にしてくれるツールキットのようです。

BuildKit is a toolkit for converting source code to build artifacts in an efficient, expressive and repeatable manner.
https://github.com/moby/buildkit/tree/master

Key featuresとして以下が挙げられています。

  1. Automatic garbage collection
  2. Extendable frontend formats
  3. Concurrent dependency resolution
  4. Efficient instruction caching
  5. Build cache import/export
  6. Nested build job invocations
  7. Distributable workers
  8. Multiple output formats
  9. Pluggable architecture
  10. Execution without root privileges

いくつかのすぐに使いそうな機能は後で纏めます。

BuildKitは以下で使われていると自身のREADMEに書いています。

  • Moby & Docker (DOCKER_BUIDKIT=1 docker build)
  • Docker buildx
  • Tekton Pipelines(formerly Knative Build Templates)
  • Gitpod
  • Dagger
  • などなど

そのためBuildKitの機能を勉強すると、Dockerからだけでなく、
様々なcontainer buildツールから利用でき、便利になっていきますね。

また、repository organizationにmobyが出てきました。

https://github.com/moby/buildkit

最後にmobyについて纏めます。

Moby

Moby is an open framework created by Docker to assemble specialized container systems without reinventing the wheel.
https://mobyproject.org/

The Moby Project is a new open-source project to advance the software containerization movement and help the ecosystem take containers mainstream. It provides a library of components, a framework for assembling them into custom container-based systems and a place for all container enthusiasts to experiment and exchange ideas.
https://www.docker.com/blog/introducing-the-moby-project/

MobyはDocker社が作ったソフトウェアのコンテナ化を加速させるOSSプロジェクトを指すようです。

その中には以下のOSSがあります。(詳細はここで見れます。)

containerdやruncも、、?と思ったのですが、
runcはOCIへ、containerdはCNCFへDocker社から寄贈されたようです。

https://www.creationline.com/tech-blog/16543
https://japan.zdnet.com/article/35066309/

また、Docker engineのソースがOSSとしてMobyプロジェクトのmobyとなっているようです。

https://dev.classmethod.jp/articles/docker-moved-github-repository/

AKB428さんの以下の図がとても分かりやすかったです。


https://zenn.dev/akb428/articles/49e51d4db36896 より参照

纏め

用語 概要
buildx BuildKitをDockerから利用するための拡張機能+α
build driver BuildKitバックエンドをどこでどのように動かすかを定めるもの
builder instance buildxが利用するdriverやその他の設定の集合体
BuildKit container buildを高機能にしてくれるツールキット。Mobyプロジェクトの中の1つ。
Moby Docker社が作ったOSSプロジェクト(群)。また、Docker engineのOSSとしての名前。

BuildKitの機能について

BuildKitの機能について記載していきます。

LLBとは

At the core of BuildKit is a Low-Level Build (LLB) definition format.
https://docs.docker.com/build/buildkit/

と記載されており、buildkitのコア部分はこのLLBのようです。

LLBとは何でしょうか。
buildkitのrepoにはこう記載されていました。

Exploring LLB
BuildKit builds are based on a binary intermediate format called LLB that is used for defining the dependency graph for processes running part of your build. tl;dr: LLB is to Dockerfile what LLVM IR is to C.
https://github.com/moby/buildkit#exploring-llb

依存関係グラフを定義するために使われる中間表現がLLBであり、DockerfileにおけるLLBはC言語におけるLLVM IRだと。

LLVMのようにfrontend, backendがあって
frontendが中間表現(LLB)を生成し、backendが最終成果物(image)を作成するという流れが想像できました。

Extendable frontend formats

Key Featuresの1つ Extendable frontend formatsを見ていきます。
と言っても、明確にこの機能がこのKey Featureだと記載されているわけではないので、なんとなくこれかなという感じです。

Frontends are components that run inside BuildKit and convert any build definition to LLB. There is a special frontend called gateway (gateway.v0) that allows using any image as a frontend.
https://github.com/moby/buildkit#exploring-dockerfiles

と記載されているとおり、任意のbuild定義をLLBに変換するコンポーネントがfrontendです。

現在サポートされているfrontendとしては以下があるようです。

  • Dockerfile
  • Mockerfile
  • Nix
  • Cargo Wahrf (Rust)
  • などなど。他にもたくさんありました。

現在は開発中なのでDockerfile frontend(dockerfile.v0)はBuildKit repoに入っていますが、将来的には外だしされる予定とのことです。

また、gateway.v0というfrontnendは特別なfrontendで、任意のcontainer imageをfrontendとして使うことができます。

Dockerfile frontendはこのgateway.v0を使うことで、Dockerfile形式以外の形式をbuildする仕組みがあるようです。

例えば以下です。

Mockerfile.yaml
# syntax=r2d4/mocker
apiVersion: v1alpha1
images:
- name: demo
  from: ubuntu:16.04
  package:
    repo:
    - deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8
    - deb [arch=amd64] https://download.docker.com/linux/ubuntu xenial edge
    gpg:
    - https://bazel.build/bazel-release.pub.gpg
    - https://download.docker.com/linux/ubuntu/gpg
    install:
    - ca-certificates
    - git
    - gcc
  external:
  - src: https://storage.googleapis.com/kubernetes-release/release/v1.10.0/bin/linux/amd64/kubectl
    dst: /usr/local/bin/kubectl

  - src: https://github.com/kubernetes-sigs/kustomize/releases/download/v1.0.8/kustomize_1.0.8_linux_amd64
    dst: /usr/local/bin/kustomize
    sha256: b5066f7250beb023a3eb7511c5699be4dbff57637ac4a78ce63bde6e66c26ac4

このファイルはMockerfileのリンク先に記載されていたMockerfileの例を一部短くするため & エラーが発生したのでその部分を除外したものです。

先頭に# syntax=r2d4/mockerと記載されています。

これはここに記述されているCustom Dockerfile syntaxで、
# syntax=[remote image reference]を指定することでBuildKit frontendとして利用する実装をcontainerで提供/利用することができます。

上記Mockerfileだとr2d4/mocker imageを使いMockerfileをLLBにbuildして最終的な成果物が作成されます。

実際に動かすと以下のようになります。

$ docker build -f Mockerfile.yaml .
[+] Building 39.8s (24/24) FINISHED                                                                                          docker:desktop-linux
 => [internal] load .dockerignore                                                                                                            0.0s
 => => transferring context: 2B                                                                                                              0.0s
 => [internal] load build definition from Mockerfile.yaml                                                                                    0.0s
 => => transferring dockerfile: 830B                                                                                                         0.0s
 => resolve image config for docker.io/r2d4/mocker:latest                                                                                    1.4s
 => CACHED docker-image://docker.io/r2d4/mocker@sha256:d34c92c892d73513e8c73beed920575df12819c66cb1df872e4aa65a20c25e9d                      0.0s
 => [internal] load Mockerfile from Mockerfile.yaml                                                                                          0.0s
 => => transferring dockerfile: 830B                                                                                                         0.0s
 => CACHED docker-image://docker.io/library/alpine:3.6                                                                                       1.1s
 => => resolve docker.io/library/alpine:3.6                                                                                                  1.1s
 => docker-image://docker.io/library/ubuntu:16.04                                                                                            0.8s
 => => resolve docker.io/library/ubuntu:16.04                                                                                                0.8s
 => CACHED /bin/sh -c apt-get update && apt-get install apt-transport-https -y                                                               0.0s
 => CACHED /bin/sh -c echo "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8" >> /etc/apt/sources.list                 0.0s
 => CACHED /bin/sh -c echo "deb [arch=amd64] https://download.docker.com/linux/ubuntu xenial edge" >> /etc/apt/sources.list                  0.0s
 => CACHED apk add --no-cache curl                                                                                                           0.0s
 => CACHED curl -Lo /key.gpg https://bazel.build/bazel-release.pub.gpg                                                                       0.0s
 => CACHED cp -a /src/key.gpg /dest/key.gpg                                                                                                  0.0s
 => CACHED /bin/sh -c apt-key add /key.gpg && rm /key.gpg                                                                                    0.0s
 => CACHED curl -Lo /key.gpg https://download.docker.com/linux/ubuntu/gpg                                                                    0.0s
 => CACHED cp -a /src/key.gpg /dest/key.gpg                                                                                                  0.0s
 => CACHED /bin/sh -c apt-key add /key.gpg && rm /key.gpg                                                                                    0.0s
 => CACHED /bin/sh -c curl -Lo /usr/local/bin/kubectl https://storage.googleapis.com/kubernetes-release/release/v1.10.0/bin/linux/amd64/kub  0.0s
 => /bin/sh -c apt-get update && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates git gcc                   35.9s
 => CACHED /bin/sh -c curl -Lo /usr/local/bin/kustomize https://github.com/kubernetes-sigs/kustomize/releases/download/v1.0.8/kustomize_1.0  0.0s
 => CACHED /bin/sh -c echo "b5066f7250beb023a3eb7511c5699be4dbff57637ac4a78ce63bde6e66c26ac4  /usr/local/bin/kustomize" | sha256sum -c -     0.0s
 => cp -a /src/usr/local/bin/kubectl /dest/usr/local/bin/kubectl                                                                             0.4s
 => cp -a /src/usr/local/bin/kustomize /dest/usr/local/bin/kustomize                                                                         0.2s
 => exporting to image                                                                                                                       0.4s
 => => exporting layers                                                                                                                      0.4s
 => => writing image sha256:8f36c49e32ff92522180b1907220b10d9abfda08b0ed27ecf11eb932e59c4219                                                 0.0s

何度かbuildした結果を取ったのでCACHEDになっていますが、# sytanxで指定したimageを取得して利用していますね。
Dockerfile fronendは# syntaxの宣言があると、gateway.v0としてBuildKitを呼び出すことでこのような動きができるのかと思われます。

https://github.com/moby/buildkit/blob/master/frontend/dockerfile/builder/build.go#L57-L59
DetectSyntax functionで、# syntax=が存在するかを判定して、ある場合はforwardGatewayを呼び出し。

forwardGatewaygateway.v0を設定している感じのようです。
https://github.com/moby/buildkit/blob/master/frontend/dockerfile/builder/build.go#L226-L230

このCustom Dockerfile syntaxを利用することで、

  • Dockerデーモンのupdate無しにbugfixや最新機能を受け取れる(最新のdocker frontend imageを利用すれば良い)
  • 全ユーザが同じbuild結果を保証できる(Dockerデーモンのバージョン差分による差が出ない)

というメリットがあります。

また、このMockerfileの例のように、様々なbuild定義をdocker(buildx)から変わらず利用することができるのと、
自身でBuildKit frontendを実装したimageを作成することもできます。

Build cache import/export

BuildKitは以下のcache exporterをサポートしています。

  • inline
    • 成果物のimageのconfigにcache metadataが付属される
  • registry
    • 成果物のimageとは別にcache用imageをrepositoryにpushする
  • local
    • localディレクトリにcache imageファイルを出力する
    • フォーマットはOCI Image Spec v1.0に準拠する
  • gha
    • GitHub Actions cacheに保存する
  • S3 (experimental)
    • S3にcache imageファイルを保存する
  • Azure Blob Storage (experimental)
    • Azure Blob Storageにcache imageファイルを保存する

上記exporterは--export-cacheオプションのtype=inline|registry|local|gha|s3|azblobで指定できます。
各typeごとに固有のオプションがあるものもあります。

共通して重要なオプションにmode=<min|max>があります。(inlineはmin modeだけサポート。)

  • min
    • 成果物イメージのlayerだけが対象
  • max
    • すべての中間ステップのlayerが対象

また、exportと対応して--import-cacheオプションもtypeを指定して利用します。

buildxからの利用

buildxからcacheを利用するには以下のように--cache-to--cache-fromオプションを指定します。

$ docker buildx build --push -t <registry>/<image> \
  --cache-to type=registry,ref=<registry>/<cache-image>[,parameters...] \
  --cache-from type=registry,ref=<registry>/<cache-image>[,parameters...] .

buildxの先にはBuildKitがいるのでオプション名以外は同じ構造ですね。

また、buildx(と恐らく直にBuildKitも)はMultiple cacheをサポートしているようです。

$ docker buildx build --push -t <registry>/<image> \
  --cache-to type=registry,ref=<registry>/<cache-image>:<branch> \
  --cache-from type=registry,ref=<registry>/<cache-image>:<branch> \
  --cache-from type=registry,ref=<registry>/<cache-image>:main .

上記例で書いているように、branchとmainを読み込んだり、BuildKitのProposalで書いてあるlatestとimage hash指定を読み込むことでcache hit率を高める狙いがあるようです。

このあたり色々と試してみようと思います。

multi-platform images

https://github.com/moby/buildkit/blob/master/docs/multi-platform.md

BuildKitはmulti-platformビルドをbuilt-inでサポートしています。

以下の例のように対象のplatformをカンマ区切りで並べて渡すことで、複数platformに向けてbuildしてくれます。

$ buildctl build \
  --frontend dockerfile.v0 \
  --opt platform=linux/amd64,linux/arm64 \
  --output type=image,name=docker.io/username/image,push=true \
  ...

ビルド対象のplatformがnativeにサポートされていない環境でビルドする場合には、QEMUが動き、そこでビルドされます。

このため、バイナリのコンパイルのようなCPU負荷の高いタスクには推奨されない、と書いてあります。

コンパイルステップにてnative performanceを得るにはpredefined platform ARGsを利用するか、xx projectを利用して最低限の変更でクロスコンパイルツールチェーンを追加すると良いようです。

ここを見ると良いと書いてあったので少し見ます。(xxの作者の記事のようですね。)

One way to avoid this overhead is to modify your Dockerfile so that the longest-running commands don’t run through an emulator. Instead, we can use a cross-compilation stage.
https://medium.com/@tonistiigi/faster-multi-platform-builds-dockerfile-cross-compilation-guide-part-1-ec087c719eaf

とあるようにうまくクロスコンパイルができる記述をすれば良いようですね。
その方法が以下の2つのようです。

  1. predefined platform ARGs
  2. xx

それぞれ具体的に見てみます。

Faster Multi-platform builds by predefined platform ARGs

DockerfileのFROM句には--platformを指定して、platformを指定できます。
これと以下の変数を組み合わせることで全環境で有効なクロスコンパイル定義が記述できます。

BUILDPLATFORM — matches the current machine. (e.g. linux/amd64)
BUILDOS — os component of BUILDPLATFORM, e.g. linux
BUILDARCH — e.g. amd64, arm64, riscv64
BUILDVARIANT — used to set ARM variant, e.g. v7
TARGETPLATFORM — The value set with --platform flag on build
TARGETOS - OS component from --platform, e.g. linux
TARGETARCH - Architecture from --platform, e.g. arm64
TARGETVARIANT

例えば以下です。

FROM --platform=$BUILDPLATFORM alpine AS build
# RUN <install build dependecies/compiler>
# COPY <source> .
ARG TARGETPLATFORM
RUN compile --target=$TARGETPLATFORM -o /out/mybinary

FROM alpine
# RUN <install runtime dependencies installed via emulation>
COPY --from=build /out/mybinary /bin

こう書くことでbuildステップではalpineイメージがbuild環境のarchitectureで動くことで高速にコンパイルを行うことができ、
最後の成果物のステップではbuildx build --platform で渡したtargetとなるarchitectureで作成できます。

また記事にはGoの依存関係の取得をより良くする方法も記載されていました。

Faster Multi-platform builds by xx

上記の例だと相当簡単に、かつ綺麗に高速化の対応ができましたが、Goなどの依存関係を考える対応をすると複雑になってきます。

そこで使えるのがこのxxです。
(という理解です。Faster Multi-platform builds: Dockerfile cross-compilation guide (Part 1)の次が読みたいです。)

xx--platformフラグで渡される値を理解し、クロスコンパイルをサポートしてくれるツールです。

xx

  • xx-info
  • xx-verify
  • xx-apl
  • xx-apt-get
  • xx-cc
  • xx-cargo
    などのコマンドを含んでおり、以下の様に利用します。
FROM --platform=$BUILDPLATFORM tonistiigi/xx AS xx

FROM --platform=$BUILDPLATFORM alpine
# copy xx scripts to your build stage
COPY --from=xx / /
# export TARGETPLATFORM (or other TARGET*)
ARG TARGETPLATFORM
# you can now call xx-* commands
RUN xx-info env

弊社ではRustを使っているので、xx-cargoを利用することで、クロスプラットフォームでの依存関係の解消などをxxが担ってくれて、すぐにbuildができるのだと思われます。
(試してみて追記できればです。)

READMEに載っているcacheなども考慮したbuild部分の記述例は以下です。

# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM rust:alpine
RUN apk add clang lld
# ...
RUN --mount=type=cache,target=/root/.cargo/git/db \
    --mount=type=cache,target=/root/.cargo/registry/cache \
    --mount=type=cache,target=/root/.cargo/registry/index \
    cargo fetch
ARG TARGETPLATFORM
RUN --mount=type=cache,target=/root/.cargo/git/db \
    --mount=type=cache,target=/root/.cargo/registry/cache \
    --mount=type=cache,target=/root/.cargo/registry/index \
    xx-cargo build --release --target-dir ./build && \
    xx-verify ./build/$(xx-cargo --print-target-triple)/release/hello_cargo

xx-verifyでターゲットプラットフォームのバイナリが問題なく出力されたかどうかを検証することができるようです。

終わりに

これまでは、書いたことの半分も理解できておらず雰囲気でdocker buildしていました。
あまり理解していなくてもBuildKitのメリットが受け取れていたのはbuildxのおかげだと感謝するとともに、使えていない便利な機能がたくさんあったので、うまく利用して良い開発時間を過ごしていきたいと思います。

また、理解が怪しいまま書いているところが多々ありますので、変なところを見つけた際にはご指摘いただければ幸いです。

今回書か(け)なかったこととしては、

  1. buildxのBakeについて
  2. BuildKitのGC、rootless機能、Otelサポート等

などがあります。私が分かっていないだけで、恐らくbuildx/BuildKitにはもっと様々な便利な機能があると思われます。

またどこかの時間で調べてブログに纏められたらと思っています。
最後まで見ていただいてありがとうございます。

参考

https://zenn.dev/akb428/articles/49e51d4db36896
https://zenn.dev/bells17/articles/docker-buildx#buildkit内部アーキテクチャ
https://zenn.dev/ttnt_1013/articles/f36e251a0cd24e
https://www.docker.com/ja-jp/blog/compiling-containers-dockerfiles-llvm-and-buildkit/
https://www.slideshare.net/KoheiTokunaga/buildkit-252619314
https://zenn.dev/sasakiki/articles/d235590c7af41a#docker-buildx

FRAIMテックブログ

Discussion