Virtualization.Frameworkを使ったDocker開発環境の構築 (Lima/virtiofs/Rosetta2)
\スニダンを開発しているSODA inc.の Advent Calendar 2023 18日目の記事です!!!/
概要
Limaを使って、macOS上にVirtualization.Frameworkを使用したDocker実行環境を構築する方法を紹介します。
Limaは、設定ファイを元にLinuxのVirtual Machine(VM)を自動で構築してくれる便利なツールです。様々な用途に応じたVMを作成するための設定ファイルのテンプレートが用意されており、これを利用すると簡単にVMを構築することができます。LimaにはDocker実行環境を構築するためのテンプレートが用意されていますが、今回はこれをそのまま使うのではなくカスタマイズし、Docker Desktopと同様の技術構成を目指します。
注意
- LimaのVirtualization.Frameworkサポートはexperimentalな機能なので変更が入る可能性があります[1]
- 今回利用するvirtiofsはinotifyをサポートしないため、inotifyの仕組みを基にしたホットリロードツールが動作しない可能性があります
システム要件
- CPU: Apple Silicon
- macOS: 13.0以上
- Lima: 0.14以上
アーキテクチャ
LimaでmacOSのVirtualization.Frameworkを利用してLinux VMを作成し、この上でDocker Engineを動かします。
Virtualization.Frameworkを利用することで、virtiofsを使ってホストとゲスト間でディレクトリを共有することができます。また、Rosetta 2を使ってIntel(x86_64)向けのバイナリを実行することもできます。
virtiofsを使う利点
virtiofsは仮想環境のユースケースに最適化したファイルシステムで、従来のネットワークファイルシステムのオーバーヘッドを回避できる利点があると公式サイトにあります。[2]
Virtiofs takes advantage of the virtual machine’s co-location with the hypervisor to avoid overheads associated with network file systems.
また、これはDocker Desktopの事例ですが、virtiofsを採用したことでDocker Desktopのパフォーマンスが大幅に向上したという報告があります。[3]
Big performance improvements
- A 90% improvement in the time taken to complete a 284MB MySQL import (3m 16s to 18s)
- An 87% improvement in the time taken to run ‘composer install’ in a large codebase (1m 27s to 11s)
- An 80% improvement in the time taken to boot a monolithic Typescript app (1m 30s to 18s)
事前準備
Limaのインストール
Linux VMを作成するために必要です。
$ brew install lima
Docker CLIのインストール
ホストからゲストのDocker Engineに繋ぐために必要です。
$ brew install docker
Rosetta 2のインストール
ゲスト側でx86_64のバイナリを実行するために必要です。
$ softwareupdate --install-rosetta --agree-to-license
Linux VMの作成
Limaでは、YAMLの設定ファイルを指定してVMを作成します。
limactl
はLimaのコマンドです。
$ limactl create VMの設定ファイル.yaml
現時点の最新(v0.19.0)のDocker用設定ファイルのテンプレートをみてみると、次のようになっています。 今回はこれをベースにしてカスタマイズをしていきます。
次の項目を設定ファイルに追加します。
vmType
はVMを実行する環境を指定するもので、vz
を指定するとVirtualization.Frameworkを使ってVMを作成します。省略した場合は、デフォルトのQEMUでVMが作成されます。
rosetta
を有効にすると、x86_64のバイナリをRosetta2で実行します。
networks
は vz
を使う場合は vzNAT
を指定する必要があります。[4]
mountType
は virtiofs
を指定しています。これでvirtiofsを使ってホストとゲスト間でファイルを共有することができます。
vmType: "vz"
rosetta:
enabled: true
binfmt: true
networks:
- vzNAT: true
mountType: "virtiofs"
項目を追加したバージョンの設定ファイルを公開していますので、これを利用してVMを作成することもできます。
limactl create
を実行するとプロンプトが表示されるので、Proceed with the current configuration
を選択してEnterを押すとVMの作成が始まります。
作成が正常に終わると、Run `limactl start docker-vz` to start the instance.
が表示されます。
$ limactl create docker-vz.yaml
? Creating an instance "docker-vz" [Use arrows to move, type to filter]
> Proceed with the current configuration
Open an editor to review or modify the current configuration
Choose another template (docker, podman, archlinux, fedora, ...)
Exit
Linux VMの起動
VMの起動は limactl start VMの名前
で行います。
VMの名前は、limactl create
時に指定した設定ファイルと同じになります。
今回は次のコマンドで起動します。
$ limactl start docker-vz
次のメッセージが表示されていれば起動が成功です。
To run `docker` on the host (assumes docker-cli is installed), run the following commands:
------
docker context create lima-docker-vz --docker "host=unix:///Your/home_directory/.lima/docker-vz/sock/docker.sock"
docker context use lima-docker-vz
docker run hello-world
------
念のためにLimaでVMのステータスを確認する場合は次のコマンドを実行します。 STATUS
が Running
になっていれば起動ができています。
$ limactl list
NAME STATUS SSH VMTYPE ARCH CPUS MEMORY DISK DIR
docker-vz Running 127.0.0.1:54758 vz aarch64 4 4GiB 100GiB ~/.lima/docker-vz
docker contextの設定
ホストからゲスト(VM)のDocker Engineに接続するための設定をします。
VMを起動するとホストの ${HOME}/.lima/docker/sock/docker.sock
にDockerのUnixドメインソケットが作成されます。これはゲストと共有されており、ゲスト上のDocker Engineのエンドポイントになっています。
ホストからこのソケットに繋ぐことで、ホストからゲストのDocker Engineに接続することができます。ホストとゲスト上のソケットファイルのパスは設定ファイル (docker-vz.yaml
) に記述されているので、分からなくなった場合はこれをみることで確認することができます。
docker context create
でエンドポイントを登録し、docker context use
でこれを使うように設定します。
/Your/home_director
の部分は適宜ご自身の環境のパスに書き換えてください。
$ docker context create lima-docker-vz --docker "host=unix:///Your/home_directory/.lima/docker-vz/sock/docker.sock"
$ docker context use lima-docker-vz
docker context ls
で現在選択中のエンドポイントを確認できます。*
が付いているものが現在選択中のものです。lima-docker-vz *
になっていれば問題ありません。
$ docker context ls
NAME DESCRIPTION DOCKER ENDPOINT ERROR
default Current DOCKER_HOST based configuration unix:///var/run/docker.sock
lima-docker-vz * unix:///Your/home_directory/.lima/docker-vz/sock/docker.sock
動作確認
いよいよDockerコンテナを実行して動作確認をします。
今回作成したDocker Engineを動かしているVMはARM向けのVMです。 したがって、ARM向けのDockerイメージに含まれるバイナリをそのまま実行することができます。
一方で、Intel(x86_64)向けのDockerイメージに含まれるバイナリも実行することができます。Intel向けのバイナリはRosetta 2を使って実行します。Rosetta 2はすでに有効になっているので特別な操作は必要ありません。
ARM向けのバイナリを実行を確認するには次のコマンドを実行します。
$ docker run --rm --platform linux/arm64 hello-world
Intel向けのバイナリを実行を確認するには次のコマンドを実行します。
$ docker run --rm --platform linux/amd64 hello-world
正常に動作できた場合は、それぞれ次のメッセージが表示されます。
Hello from Docker!
This message shows that your installation appears to be working correctly.
おわりに
Limaを使うことでmacOS上に簡単にDockerの開発環境を作成することができます。
今回は指定しませんでしたが、VMに割り当てるCPUの数やメモリのサイズをVM作成時に指定するとができます。また、その他の各種パラメータは、今回のように設定ファイルに記載する以外にも、limactl create
でVM作成時に --set
オプションを付けることでコマンドラインから指定することが可能です。実際の開発環境を構築するときには公式サイトを参考に適宜パラメータを指定してください。
検証環境
CPU
$ uname -m
arm64
OS
$ sw_vers
ProductName: macOS
ProductVersion: 13.6.2
BuildVersion: 22G320
Lima
$ limactl -v
limactl version 0.19.0
参考にしたドキュメント
株式会社SODAの開発組織がお届けするZenn Publicationです。 是非Entrance Bookもご覧ください! → recruit.soda-inc.jp/engineer
Discussion