🐳

コンテナのマルチプラットフォームビルドをリモートビルダーで構成する

2024/01/21に公開

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