docker buildx bakeで複数のイメージを並列でビルドする
概要
かつて、Dockerではイメージの並列ビルドを行うことはできませんでした。2017年に導入されたmulti-stage buildでは並列ビルドがサポートされましたが、あくまでも一つのイメージをビルドする過程でステージを並列実行するというものでした。
しかし、buildxの新機能であるbuildx bake
を使うと、一つのコマンドで複数のイメージを同時にビルドすることができます。例えば、以下のDockerfile
からmicroservice-a
とmicroservice-b
の2つのイメージを出力することができます。
# Microservice AとBをビルドするステージ
FROM rust as builder-stage
COPY ./src /services-src
WORKDIR /services-src
RUN cargo build --release --bins
# Microservice Aに必要なファイルだけを用意するステージ
FROM debian:bullseye-slim as microservice-a-stage
RUN apt-get update && \
apt-get install -y service-a-dependencies && \
rm -rf /var/lib/apt/lists/*
COPY /services-src/target/release/service-a /service-a
ENTRYPOINT ["/service-a"]
# Microservice Bに必要なファイルだけを用意するステージ
FROM debian:bullseye-slim as microservice-b-stage
RUN apt-get update && \
apt-get install -y service-b-dependencies && \
rm -rf /var/lib/apt/lists/*
COPY /services-src/target/release/service-b /service-b
ENTRYPOINT ["/service-b"]
この記事では上記のDockerfile
を例にとり、buildx bake
コマンドを使って複数のイメージを並列でビルドする方法を紹介します。
ビルド定義ファイル
buildx bake
を使うには、まずビルド定義ファイルを用意する必要があります。冒頭で示したDockerfile
をビルドするには、以下のようにdocker-bake.hcl
を書きます。
target "microservice-a" {
dockerfile = "Dockerfile" # Dockerfileのファイル名(デフォルト値なので省略可能)
target = "microservice-a-stage" # ステージ名(紛らわしいが、2行上のtargetとは無関係)
tags = ["ciffelia/microservice-a"] # イメージにつけるタグ(複数可)
}
target "microservice-b" {
dockerfile = "Dockerfile"
target = "microservice-b-stage"
tags = ["ciffelia/microservice-b"]
}
ビルド定義ファイルでは複数のtargetを定義できます。targetの中では、docker build
を実行するときと同じように、イメージをビルドするオプションを指定します。
従来は、1回のdocker build
で1つのイメージを作成していました。buildx bake
では、1つのtargetで1つのイメージを作成します。
なお、定義ファイルの記法は以下の3つの中から選ぶことができます。
- Docker Compose (
docker-compose.yml
のbuild
セクションに書く) - HCL (HashiCorp configuration language)
- JSON
個人的にはdocker-compose.yml
の肥大化を避けたいので、ビルド定義はHCLかJSONに書くのが良いのではないかと思います。JSONを手で書くのは大変なので、この記事ではHCLを採用しています。
buildx bake
コマンド
buildx bake
は、予め用意しておいたビルド定義ファイルに基づいてビルドを実行するコマンドです。以下のコマンドで、先程示したdocker-bake.hcl
のmicroservice-a
microservice-b
targetを実行できます。
docker buildx bake --file docker-bake.hcl microservice-a microservice-b
このコマンド1つで、ciffelia/microservice-a
とciffelia/microservice-b
の2つのイメージが作成されます。また、3つのステージは並列で実行されます。
便利な機能
ここからは、buildx bake
を使う上で便利な機能をいくつか紹介します。
Target options
target の中で指定できるオプションは、args
, cache-from
, cache-to
, context
, dockerfile
, inherits
, labels
, no-cache
, output
, platform
, pull
, secrets
, ssh
, tags
, target
です。使い方は基本的にdocker buildx build
と同じです。
target "example" {
dockerfile = "docker/Dockerfile.webapp"
tags = ["ciffelia/webapp"]
cache-from = ["type=registry,ref=ciffelia/webapp"] # 事前にレジストリからキャッシュをpullする
push = true # ビルド完了後、レジストリにpushする
}
Groups
複数のtargetをまとめることができます。
group "default" {
targets = ["microservice-a", "microservice-b"]
}
target "microservice-a" {
target = "microservice-a-stage"
tags = ["ciffelia/microservice-a"]
}
target "microservice-b" {
target = "microservice-b-stage"
tags = ["ciffelia/microservice-b"]
}
上記のようにdocker-bake.hcl
を書いて、以下のコマンドを実行すれば、microservice-a
とmicroservice-b
の2つのtargetが実行されます。
docker buildx bake --file docker-bake.hcl default
なお、実行したいtargetやgroupの名前がdefault
の場合は省略することができます。
# 同じ結果が得られる
docker buildx bake --file docker-bake.hcl
継承
inherits
を使うと、既存のtargetをもとに新しいtargetを作成することができます。
target "microservice-a" {
target = "microservice-a-stage"
tags = ["ciffelia/microservice-a"]
}
target "microservice-a-multiarch" {
inherits = ["microservice-a"]
platforms = ["linux/amd64", "linux/arm64/v8", "linux/arm/v7"]
}
複数の Dockerfile
1つのdocker-bake.hcl
で複数のDockerfile
を使うことができます。当然、並列でビルドされます。
target "frontend" {
dockerfile = "docker/Dockerfile.frontend"
tags = ["ciffelia/my-frontend"]
}
target "backend" {
dockerfile = "docker/Dockerfile.backend"
tags = ["ciffelia/my-backend"]
}
GitHub Action
buildx bake
を実行するGitHub Actionが、Docker公式からリリースされています。
Discussion