コンテナのマルチプラットフォームビルドをリモートビルダーで構成する
Docker buildxを使用したマルチプラットフォームコンテナのビルドを、リモートビルダーを使用して行う方法です。
この記事ではローカルのビルド環境はMac mini(M2 Pro), リモートのビルド環境はAMD64(AMD Ryzen 5 4500)のUbuntuで行っています。
マルチプラットフォームコンテナとは
1つのコンテナイメージでamd64とarmなど、複数のプラットフォームで動かせるコンテナのことです。複数のプラットフォーム用のコンテナが1つのイメージの中にまとまっています。
ビルドの際にはdocker-buildxを使用するのが一般的です。
使い方
WindowsおよびmacOSの場合にはDocker Desktopをインストールすることでbuildxも使えるようになります。Linuxの場合には別途インストールが必要です。
ここではmacOSにDocker Desktopが入っている場合の例を説明します。まず、以下でbuildxを有効化します。
docker buildx create --use
そして以下のコマンドでビルドを行います。
$ docker buildx build -t myimage:latest . \
--platform linux/amd64,linux/arm64/v8 \
--output=type=image,push=true
これでamd64とarm64のマルチプラットフォームコンテナができます。
仕組み
マルチプラットフォームビルドでは、実行ホストと違うプラットフォーム用コンテナのビルドにはQEMUを使用したエミュレート環境でビルドが実行されます。Apple SilliconのMac上ではamd64のイメージビルドがQEMU上で実行されることになります。
問題点
QEMU上でのビルには以下の問題点があります。
遅い
エミュレータを使用してる以上仕方がない部分もありますが、ネイティブ環境と比べるとビルドにかなり時間が掛かります。
完全互換ではない
Railsを含むコンテナのbuildでエラーが発生しました。どうやら完全な互換性はなく、エラーが発生することもある模様です。
リモートビルダー
エミュレータを使う代わりにリモートの本物のマシンを使ってビルドするのがリモートビルダーです。本物なので実行も早いし何より互換性は全く問題ありません。
ビルダー作成
まずローカルのビルドマシンからリモートのビルドマシンにsshで認証鍵を使用して(パスワードなしで)ログインできるようにしておきます。以下のコマンドでリモートのDocker情報が取れればよいです。
docker -H ssh://USER@REMOTE_HOST info
(#USER@REMOTE_HOSTの部分は自分の環境に合わせて書き換える)
以後ローカルマシンで実行します。
新たにlocal_remote_builder
という名前のビルダーを作成します。ARM系プラットフォームのビルド方法を定義します。
$ docker buildx create \
--name local_remote_builder \
--node local_remote_builder \
--platform linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/mips64le,linux/mips64,linux/arm/v8,linux/arm/v7,linux/arm/v6 \
--driver-opt env.BUILDKIT_STEP_LOG_MAX_SIZE=10000000 \
--driver-opt env.BUILDKIT_STEP_LOG_MAX_SPEED=10000000
docker buildx ls
で確認すると以下のようになります。
NAME/NODE DRIVER/ENDPOINT STATUS PLATFORMS
local_remote_builder * docker-container
local_remote_builder unix:///var/run/docker.sock running linux/arm64*, linux/riscv64*, linux/ppc64le*, linux/s390x*, linux/mips64le*, linux/mips64*, linux/arm/v7*, linux/arm/v6*, linux/amd64, linux/amd64/v2, linux/386
ビルダーにリモートビルドの定義を追加
次に、作成したlocal_remote_builderにリモートのビルド定義を--appendで
追加します。
$ docker buildx create \
--name local_remote_builder \
--append \
--node intelarch \
--platform linux/amd64,linux/386 \
ssh://USER@REMOTE_HOST \
--driver-opt env.BUILDKIT_STEP_LOG_MAX_SIZE=10000000 \
--driver-opt env.BUILDKIT_STEP_LOG_MAX_SPEED=10000000
(#USER@REMOTE_HOSTの部分は自分の環境に合わせて書き換える)
docker buildx ls
で確認すると以下のようになります。
NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
local_remote_builder * docker-container
local_remote_builder desktop-linux running v0.12.4 linux/arm64*, linux/riscv64*, linux/ppc64le*, linux/s390x*, linux/mips64le*, linux/mips64*, linux/arm/v8*, linux/arm/v7*, linux/arm/v6*, linux/amd64, linux/amd64/v2, linux/386
intelarch ssh://xxxx@xxxx.xxx stopped linux/amd64*, linux/386*
これでamd64の時はssh経由でリモートマシンを使う定義になりました。
作成したビルダーを使うように設定
最後に作成したlocal_remote_builder
を使うように設定します。
docker buildx use local_remote_builder
docker buildx inspect --bootstrap
設定は以上です。これでマルチプラットフォームのコンテナビルドがかなり早くなりました。
Discussion