この記事は、3-shake Advent Calendar 2023 2日目のエントリ記事です。
2023年10月に Docker Desktop for Apple silicon での Rosetta for Linux が GA となり、Apple Silicon の Mac 上で x86_64 バイナリ実行のパフォーマンスや安定性が向上したとありました。
Docker Desktop は2021年の有償化以降、Lima が代替ソフトウェアのプラットフォームとして広く使われています。Amazon の Finch や Rancher Desktop の内部でも使われています。
私も Apple silicon の MacBook Air で Lima を docker の実行環境として利用していました。Lima はデフォルトでは qemu で VM の仮想化を行なっていますが、vmType
に vz
を指定することで Apple の Virtualization Framework を使うようになっており、さらに rosetta を有効にすることで Docker Desktop のように ARM の VM 上で docker daemon を実行しつつ、x86_64 のコンテナを実行することができます。
docker daemon 用 VM の定義の作成
vz
で rosetta を有効にした aarch64 の VM を定義します。
limactl create --name=default \
--cpus=2 --memory=2 \
--vm-type=vz --mount-type=virtiofs --rosetta \
template://docker
~/.lima/default
配下に必要なファイルが作成されます
$ limactl ls
NAME STATUS SSH VMTYPE ARCH CPUS MEMORY DISK DIR
default Stopped 127.0.0.1:0 vz aarch64 2 2GiB 100GiB ~/.lima/default
template の一覧は limactl create --list-templates
で確認できます。Homebrew でインストールしている場合は ls $(brew --prefix)/opt/lima/share/lima/templates
でファイルも確認できます。
docker daemon 用 VM の起動
次に limactl start NAME
(NAME が default の場合は省略可能) を実行することで VM が起動されます。
docker テンプレートを使った場合、次のような出力がされるはずです、create
は初回のみ実行すればよく、context use
も ~/.docker/config.json
に書き込まれるので切り替えが不要であれば1度実行しておけば良いです。(docker context)
docker context create lima-default --docker "host=unix:///Users/teraoka/.lima/default/sock/docker.sock"
docker context use lima-default
これで docker コマンドはこの VM 上の docker daemon と通信することになります。
lima
コマンドの引数が VM 内で実行されます。uname -m
で architecture を確認すると aarch64
で ARM であることが確認できます。
$ lima uname -m
aarch64
docker コンテナの実行
先ほどの結果からデフォルトでは arm64 のコンテナイメージをダウンロードして実行しようとします。
$ docker run --rm debian uname -m
Unable to find image 'debian:latest' locally
latest: Pulling from library/debian
df2021ddb7d6: Pull complete
Digest: sha256:133a1f2aa9e55d1c93d0ae1aaa7b94fb141265d0ee3ea677175cdb96f5f990e5
Status: Downloaded newer image for debian:latest
aarch64
今度は --platform=linux/amd64
を指定して実行してみます。
$ docker run --rm --platform=linux/amd64 debian uname -m
Unable to find image 'debian:latest' locally
latest: Pulling from library/debian
90e5e7d8b87a: Pull complete
Digest: sha256:133a1f2aa9e55d1c93d0ae1aaa7b94fb141265d0ee3ea677175cdb96f5f990e5
Status: Downloaded newer image for debian:latest
x86_64
指定した image 名は同じですが、platform が異なるため新たにダウンロードされました。uname -m
コマンドのの出力も x86_64
となっています。
ダウンロードされている image を確認してみます。
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
debian <none> a588e7890234 9 days ago 139MB
debian latest 0ce03c8a15ec 9 days ago 117MB
ls
では architecture が確認できないので inspect
で確認してみます。
$ docker image inspect $(docker image ls --format '{{.ID}}') | jq '.[] | {id:.Id[7:19],arch:.Architecture,tag:.RepoTags[0]}' -c
{"id":"a588e7890234","arch":"arm64","tag":null}
{"id":"0ce03c8a15ec","arch":"amd64","tag":"debian:latest"}
パフォーマンス比較
私は今のところ手元の docker 環境でたいした処理を行わないので誰かやってみてください。
次のようにして複数の VM を作成し、切り替えて試すことができます。
aarch64 (rosetta 無し)
limactl create --name=arm64 \
--arch=aarch64 \
--cpus=2 --memory=2 \
--vm-type=vz --mount-type=virtiofs \
template://docker
この環境で --platform=linux/amd64
を指定してコンテナを実行すると次のようなエラーで実行できないはずです。
exec /usr/bin/uname: exec format error
x86_64 (qemu)
limactl create --name=amd64 \
--arch=x86_64 \
--cpus=2 --memory=2 \
--vm-type=qemu --mount-type=9p \
template://docker
qemu の場合、mountType
に virtiofs
を指定することができません。(9p と virtiofs は以前簡単に比較してみました。)
$ limactl ls
NAME STATUS SSH VMTYPE ARCH CPUS MEMORY DISK DIR
amd64 Stopped 127.0.0.1:0 qemu x86_64 2 2GiB 100GiB ~/.lima/amd64
arm64 Stopped 127.0.0.1:0 vz aarch64 2 2GiB 100GiB ~/.lima/arm64
default Stopped 127.0.0.1:0 vz aarch64 2 2GiB 100GiB ~/.lima/default