今発売されているMacはすべてARMアーキテクチャを採用したCPUを使用しており,以前のIntelチップやWindowsの多くの機種とアーキテクチャが異なる.
M1 MacではRosettaなどのアーキテクチャ変換技術を用いることでAMDアーキテクチャのイメージを使うことができるが,とても実行に時間がかかる.(逆に,ARMのイメージしかない場合,AMDの環境では実行できるのだろうか?)

そのため,dockerのイメージをDockerfileからビルドして,AMDとARMの複数用意したくなった.

このときのやり方をメモする.


環境

前提

PCの環境

Docker hubに登録しており,ターミナル上でdocker loginを実行し,ログインされた状態.

人間

Dockerfileから自分でイメージをなんとかbuildできるくらいの知識はある.

Mac

M1のMacbook Pro (Monterey)

% sw_vers
ProductName:	macOS
ProductVersion:	12.1
BuildVersion:	21C52

Docker

% docker version
Client:
 Cloud integration: v1.0.22
 Version:           20.10.11
 API version:       1.41
 Go version:        go1.16.10
 Git commit:        dea9396
 Built:             Thu Nov 18 00:36:09 2021
 OS/Arch:           darwin/arm64
 Context:           default
 Experimental:      true

Server: Docker Engine - Community
 Engine:
  Version:          20.10.11
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.16.9
  Git commit:       847da18
  Built:            Thu Nov 18 00:34:44 2021
  OS/Arch:          linux/arm64
  Experimental:     false
 containerd:
  Version:          1.4.12
  GitCommit:        7b11cfaabd73bb80907dd23182b9347b4245eb5d
 runc:
  Version:          1.0.2
  GitCommit:        v1.0.2-0-g52b36a2
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

ちなみに公式的に必要なのは

Docker メニューから About Docker Desktop をクリックし、インストールした Docker Desktop のバージョンが 2.0.4.0 (33772) 以上かどうかを確認します。
マルチ CPU アーキテクチャのサポートを活用 - Docker

らしい.

buildx

自分でインストールした記憶がないが,既に入っていた.いつからかのバージョンから標準搭載になったのかも.

% docker buildx version
github.com/docker/buildx v0.7.1 05846896d149da05f3d6fd1e7770da187b52a247

やり方

ビルダーを作成

以下のコマンドで新たなビルダーを作成.

docker buildx create --name armamd

--nameの後に書いたのがこのビルダーの名前.場合によって変える.以降,armamdとして進める.

作成できたかは,以下のコマンドでビルダーの一覧を取得することで確認できる.

docker buildx ls

作った名前のものがあればOK.

ビルダーを切り替え

以下のコマンドを実行して,先ほど作成したビルダーに切り替える.

docker buildx use armamd

そして,

docker buildx ls

を実行するとビルダー名の横に*がつく.

以下のコマンドで一応切り替えられたかちゃんと作成できたかとか,色々チェックできる.

docker buildx inspect --bootstrap

自分の場合,結果は以下.

[+] Building 13.8s (1/1) FINISHED
 => [internal] booting buildkit                                                                                                                                  13.7s
 => => pulling image moby/buildkit:buildx-stable-1                                                                                                               13.1s
 => => creating container buildx_buildkit_armamd0                                                                                                                 0.6s
Name:   armamd
Driver: docker-container

Nodes:
Name:      armamd0
Endpoint:  unix:///var/run/docker.sock
Status:    running
Platforms: linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6

ビルドする

今回は,とりあえずMac全体をターゲットとするイメージを作成したいので,linux/arm64, linux/amd64を対象にする.

公式の例を使うとこんな感じ.

docker buildx build --platform linux/amd64,linux/arm64 -t username/demo:latest --push .

ビルドコマンドを実行すると,当たり前だがビルドが始まるので時間がかかるので注意.

もちろん,usernameやリポジトリ名(今回だとdemo),タグ(今回だとlatest)の部分などは個別の環境で変更する必要がある.

buildコマンドの文法

ビルドコマンドを個別に覚えなきゃいけないのか?と怖かったが,そんなこともなさそうだと思った.
個人的には,普通のビルドのコマンドに対して,以下の変換を行えば良いものだとイメージしている.

  • docker image builddocker buildx build
  • buildの直後に--platform linux/amd64,linux/arm64を追加(直後じゃなくてもいいかもしれないが…)
  • タグ(先ほどの例だと-t username/demo:latest)とDockerfileのパス(先ほどの例だと.)の間に--pushを追加(これもここじゃなくてもいいかもしれないが…)
    • --pushは生成したイメージとアーキテクチャの対応を踏まえた上で全てのイメージをDocker Hubに送信することを意味する.

たとえば,普通のイメージのビルドを以下のコマンドで行なっているとする.

docker image build \
    --build-arg dir_name=$DIR_NAME \
    --build-arg user_name=$USER_NAME \
    -t username/$DIR_NAME:$IMAGE_VERSION $SCRIPT_DIR/docker

このとき,armとamd用のイメージをビルドして,docker hubにアップロードしたい場合は以下のコマンドを実行すれば良い.

docker buildx build \
    --platform linux/amd64,linux/arm64 \
    --build-arg dir_name=$DIR_NAME \
    --build-arg user_name=$USER_NAME \
    -t username/$DIR_NAME:$IMAGE_VERSION \
    --push $SCRIPT_DIR/docker

なお,$XXXは事前にシェルスクリプト内で代入した変数であり,\はシェルスクリプト内の改行するときのマークである.

実行が終了したあと,Docker hubでちゃんと指定したアーキテクチャのイメージがアップロードされていればOK!

結論

buildxを使えば簡単にできる.

コメント

結構簡単で,覚えることもそんなになくできたので感動している.

docker buildx lsをやった時点でdefaultのビルダーが存在したのでもしかしたら新しい環境を作成しなくてもうまくいったのかもしれないが未検証.

参考

関連

https://note.yu9824.com/howto/2021/09/04/docker-conda-activate/