最近のDocker Build仕様

BuildKitなどの最新のDocker Buildの仕様がよくわかっていないので、公式ドキュメントを見ながら確認する。

Dockerビルドのアーキテクチャ
UIを提供するのがBuildxで、バックエンドで実際にビルドするのがBuildKit。公式のアーキテクチャ図がわかりやすい。
Builder(BuildKit)はBuildxと同一環境で動作させることもリモート環境で動作させることもできる。
詳しくはBuildersの章で。このあたりリモートでビルドさせてビルドの改善ができないかは気になる。

Dockerfileによるソフトウェアのパッケージング
Dockerfileの詳細な仕様はDockerfile referenceで。
複数のDockerfileを利用するときは <something>.Dockerfile
とするのが公式推奨の命名規則。
結局 -f で指定するのでこの命名規則を統一するメリットがあるのかは不明。
Dockerfileの先頭コメントにはParser directiveを指定できる。
詳細はParser directiveの通り。
parser directiveにはBuildKitの挙動をカスタマイズするsyntax directiveと、Dockerfileのエスケープ文字(デフォルト \
)をカスタマイズするescape directiveがある。
特にバックスラッシュがディレクトリパスのセパレータであるWindows環境ではescape directiveが有益。

ビルドコンテキスト
ビルドコンテキストにはリモートgitリポジトリも指定できて、この場合はリポジトリとすべてのサブモジュールがコンテキストに含まれる。
ビルドコンテキストにローカルファイルシステムを利用するとき、.dockerignoreで除外設定できる。
このとき、Dockerfile別に.dockerignoreを作成することもできる。利用するDockerfile名をprefixに持つdockerignoreが反映される。例えば build.Dockerfile
に対しては build.Dockerfile.dockerignore
が専用のdockerignoreファイルになる。
ビルドコンテキストのルート.dockerignoreファイルが共存する場合は、Dockerfile別dockerignoreが優先される(ルート .dockerignoreは無視されるということ?)
ビルドコンテキストにgitリポジトリを指定する場合、タグやブランチ、コンテキストに利用するサブディレクトリなども指定できる。
デフォルトでは .gitディレクトリはビルドコンテキストに含まれないが、 BUILDKIT_CONTEXT_KEEP_GIT_DIR
をbuild argumentに指定することで含めることができる。
これはビルド中にgit履歴を利用するとき(git rev-parseなどを利用するとき)に有益。
プライベートリポジトリをコンテキストに指定するときは、SSHクレデンシャルやSSH_AUTH_SOCK、GIT_AUTH_TOKEN(PATなど)を指定する。

マルチステージビルド
--target
オプションを指定することで特定のステージのみビルドすることもできる。
これはデバッグのため、またはテストのため特定のステージまでビルドしたらビルド処理を止めたいときに有益。
BuildKitはステージの依存関係を確認して依存しないステージのビルドはスキップしてくれる。BuildKit以前のビルドでは依存関係は考慮せず、Dockerfileの先頭から指定のステージまですべてビルドする。
マルチステージビルドでファイルをコピーするときは、 --from=nginx:latest
のように指定することで別ステージからだけでなく別イメージからファイルをコピーすることもできる。

マルチプラットフォームイメージ
ビルド時に--platform
を指定することで特定プラットフォーム向けのビルドを実行できる。
マルチプラットフォーム向けのビルドを実行する方法としては、QEMUを利用する、multiple native nodeを利用する、プログラミング言語のクロスコンパイル機能を活用する、の3通りがある。
このあたりは実際に動作確認しながら検証した方がよさそう。
Docker Desktopではマルチアーキテクチャのサポートがあるので特別な設定は不要。

Docker Build用の環境変数
BuildKit built-in build argsと合わせて確認しておくとよさそう。
BUILDKIT_HOST
、BUILDKIT_EXPERIMENTAL_SOURCE_POLICY
、BUILDX_CONFIG
、BUILDX_GIT_LABELS
などが気になる。

OpenTelemetryサポート
buildxおよびbuildkitのトレース情報をJaegerなどで可視化することができる。

独自のベースイメージを作成する。
DebianのDebootstrapなどを利用して1からイメージを構築する方法もある。

その他のイメージビルドに関する情報はDockerfile reference や Dockerfileベストプラクティスを参照。

Builders
docker buildが実行されるBuildKitデーモンがbuilder。
デフォルトではdefault builderが生成されてそこでビルドが実行される。
default builderはbuild driverとして docker
が選択されており、docker daemonでビルドされる。
その他のdriverとして、別のコンテナ上でビルドを実行するdocker-container
、kubernetesクラスタ上でpodとして動作するkubernetes
、独自に管理しているBuildKit daemonを利用するremote
が選択できる。
builder一覧を表示する方法としてdocker buildx ls
コマンドがある。ここで管理されているbuilderを --builder
フラグやBUILDX_BUILDR
環境変数で指定して利用できる。

buildersの管理
デフォルトでは docker
ドライバを利用する。docker
ドライバのbuilderは手動で作成できない。
独自のbuilderを作成するときはdocker buildx create
コマンドを実行する。デフォルトではdocker-container
ドライバで作成されるが、--driver
フラグを指定することで別のドライバで作成することもできる。
Docker Desktopでbuilderを管理する方法は現在ベータ版の扱い。

Buildx ドライバ概要
docker
ドライバはシンプルで簡単に利用できるが、拡張機能をサポートしていないしカスタマイズできない。

Docker driver
カスタマイズ項目が無く、利用するBuildKitバージョンの指定もできない(docker engineに依存)。

docker container driver
docker buildkit createコマンドで新しいbuilderを作成できる。
docker-containerをbuilderとして指定してdocker buildするとき、moby/buildkitのコンテナ上でビルドを実行する。
docker-containerでは明示的に--loadオプションを指定しないとビルドしたイメージは読み込まれない。
docker buildx rmでbuilderを削除するときに --keep-stateオプションを指定することでキャッシュがvolumeとして保持される。
docker-containerでは--platformオプションを指定することで異なる環境をQEMU上で実行することができる。
ビルド時に専用のネットワークを分離したい場合は事前に作成して利用できる。
buildkitのバージョンをカスタマイズするメリットの整理が必要。どのような場合に異なるバージョンのbuildkitを利用したいユースケースがあるか。
キャッシュまわりやQEMU利用はパフォーマンス影響を確認したい。