Compute EngineのNested Virtualizationを使ってFirecrackerの開発環境を構築してみた

スナップショットを知りたければFirecrackerを学ぶべし!
2022.11.29

CX事業部@大阪の岩田です。

少し前に社内でこんなつぶやきをしていました。

re:invent初日の今日、本当に来ましたね。

Lambdaの基盤で利用されているVMMのFirecrackerは以前からスナップショット機能の開発が進んでいて、re:Invent 2019の時点で既にMicroVMを5ミリ秒で起動することに成功していました。Firecrackerの開発動向から考えるとある程度予想できた流れだったと言えるでしょう。

この発表をきっかけにFirecrackerのスナップショット機能を触ってみたい!という人が増えるかもしれないので、このブログではFirecrackerの開発環境構築手順についてご紹介します。

Firecrackerをどこで動かすか?

Firecrackerをなるべく手頃に試せる場所を探すでも紹介されているように、Firecrackerを動かす環境はいくつか候補が考えられます。この中でもお手頃に試せそうなのが、Nested Virtualizationを利用するという選択肢です。自前でハードを用意する必要がありませんし、ベアメタルインスタンスを利用するのに比べてお手軽な料金でFirecrackerを試すことができます。今回はnested virtualizationが利用可能なGoogle CloudのCompute Engine上にFirecrackerの開発環境を構築してみます。

Compute EngineでNested Virtualizationを有効化したインスタンスを起動する

まずはCompute Engineのマネジメントコンソールから「インスタンスを作成」をクリックし、諸々必要事項を入力していきましょう。今回は以下の設定で作成していきます。

  • マシンタイプ: n2-standard-2
  • CPUプラットフォーム: x86/64
  • OS: Ubuntu 18.04 LTS
  • ブートディスク: 40G

一通り入力できたら「作成」ではなく「同等のコマンドライン」をクリックします。

すると以下のようなコマンドがコピーできます。

gcloud compute instances create firecracker-dev-x86-64 --project=<プロジェクト名> --zone=asia-northeast2-a --machine-type=n2-standard-2 --network-interface=network-tier=PREMIUM,subnet=default --maintenance-policy=MIGRATE --provisioning-model=STANDARD --service-account=<プロジェクトNO>-compute@developer.gserviceaccount.com --scopes=https://www.googleapis.com/auth/devstorage.read_only,https://www.googleapis.com/auth/logging.write,https://www.googleapis.com/auth/monitoring.write,https://www.googleapis.com/auth/servicecontrol,https://www.googleapis.com/auth/service.management.readonly,https://www.googleapis.com/auth/trace.append --create-disk=auto-delete=yes,boot=yes,device-name=firecracker-dev-x86-64,image=projects/ubuntu-os-cloud/global/images/ubuntu-1804-bionic-v20221125,mode=rw,size=40,type=projects/<プロジェクト名>/zones/asia-northeast2-a/diskTypes/pd-balanced --no-shielded-secure-boot --shielded-vtpm --shielded-integrity-monitoring --reservation-affinity=any

このコマンドの末尾にNested Virtualizationを有効化するためのオプション--enable-nested-virtualizationを付与して実行しましょう。最終的なコマンドは

gcloud compute instances create firecracker-dev-x86-64 --project=<プロジェクト名> --zone=asia-northeast2-a --machine-type=n2-standard-2 --network-interface=network-tier=PREMIUM,subnet=default --maintenance-policy=MIGRATE --provisioning-model=STANDARD --service-account=<プロジェクトNO>-compute@developer.gserviceaccount.com --scopes=https://www.googleapis.com/auth/devstorage.read_only,https://www.googleapis.com/auth/logging.write,https://www.googleapis.com/auth/monitoring.write,https://www.googleapis.com/auth/servicecontrol,https://www.googleapis.com/auth/service.management.readonly,https://www.googleapis.com/auth/trace.append --create-disk=auto-delete=yes,boot=yes,device-name=firecracker-dev-x86-64,image=projects/ubuntu-os-cloud/global/images/ubuntu-1804-bionic-v20221125,mode=rw,size=40,type=projects/<プロジェクト名>/zones/asia-northeast2-a/diskTypes/pd-balanced --no-shielded-secure-boot --shielded-vtpm --shielded-integrity-monitoring --reservation-affinity=any --enable-nested-virtualization

のようになります。

コマンドが実行できたらしばらく待ってからSSH接続します。

gcloud compute ssh firecracker-dev-x86-64

以下のコマンドを実行し、0以外の値が出力されればNested Virtualizationが有効化されています。

grep -cw vmx /proc/cpuinfo
2

Firecrackerの開発環境を整える

インスタンスが起動したので、ここからはFirecrackerの開発に必要な環境を整えていきます。Firecrackerの開発に便利なDockerイメージ&Dockerfileが公開されるので、基本的にこのDockerイメージを利用していきます。

Dockerのインストール

まずはDockerのインストール

sudo apt-get update
sudo apt-get install \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  
sudo apt-get update

sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin

ログインユーザーをdockerグループに追加してdockerコマンドを実行できるようにします。

sudo usermod -a -G docker $USER

一旦ログアウトしてから再度SSH 接続

exit
Connection to xxx.xxx.xxx.xxx closed.

gcloud compute ssh firecracker-dev-x86-64

sudo無しでdockerコマンドが叩けることを確認しておきます。

docker run hello-world

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
2db29710123e: Pull complete
Digest: sha256:faa03e786c97f07ef34423fccceeec2398ec8a5759259f94d99078f264e9d7af
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

ソースコードのClone

続いてFirecrackerのソースコードをCloneします

git clone https://github.com/firecracker-microvm/firecracker.git

Cloning into 'firecracker'...
remote: Enumerating objects: 38971, done.
remote: Counting objects: 100% (327/327), done.
remote: Compressing objects: 100% (234/234), done.
remote: Total 38971 (delta 133), reused 235 (delta 91), pack-reused 38644
Receiving objects: 100% (38971/38971), 23.54 MiB | 24.35 MiB/s, done.
Resolving deltas: 100% (24624/24624), done.

取得できたらディレクトリ内に移動しておきましょう

cd firecracker

開発用コンテナイメージのPULL

cloneしたリポジトリ内に含まれるDockerfileから開発用のコンテナイメージをビルドしても良いんですが、それなりに時間がかかるのでECR Publicで公開されているビルド済みイメージをPULLします。現時点ではv44のタグが最新なので、v44のタグを指定してPULLします。

docker pull public.ecr.aws/firecracker/fcuvm:v44

v44: Pulling from firecracker/fcuvm
726b8a513d66: Pull complete
c902087c353a: Pull complete
bd49ff15459a: Pull complete
a19aa9ec83e7: Pull complete
4ca7e6d4b702: Pull complete
2116b4920242: Pull complete
4e88412695d9: Pull complete
bc5294c03c96: Pull complete
f88c91f9b95e: Pull complete
aa0be5182a1d: Pull complete
a9a3533f84b3: Pull complete
8317680728d5: Pull complete
ad17528d5766: Pull complete
a7d5eb0fa1b2: Pull complete
5a06dea846a3: Pull complete
Digest: sha256:f92ff74d3de6b174dbec1cb53e71fe578ca881819f5ab244f046e7d6ba32d8c7
Status: Downloaded newer image for public.ecr.aws/firecracker/fcuvm:v44
public.ecr.aws/firecracker/fcuvm:v44

Firecrackerのビルド

これで必要な準備が整ったので、Firecrackerをビルドしてみましょう。以下のコマンドを実行すると、開発用のコンテナが起動しFirecrackerのバイナリのビルドがスタートします。

./tools/devtool build
warning: patch for `kvm-bindings` uses the features mechanism. default-features and features will not take effect because the patch dependency does not support this mechanism
    Updating git repository `https://github.com/firecracker-microvm/kvm-bindings`
    Updating git submodule `https://github.com/rust-vmm/rust-vmm-ci.git`
    Updating git repository `https://github.com/firecracker-microvm/micro-http`
    Updating git submodule `https://github.com/rust-vmm/rust-vmm-ci.git`
    Updating crates.io index
  Downloaded ryu v1.0.9
  Downloaded proc-macro2 v1.0.36
  Downloaded serde_derive v1.0.136
  Downloaded syn v1.0.86
  Downloaded unicode-xid v0.2.2
  Downloaded itoa v1.0.1
  Downloaded vmm-sys-util v0.11.0
  Downloaded derive_more v0.99.17
  Downloaded bincode v1.3.3
  Downloaded serde v1.0.136
  Downloaded quote v1.0.15
  Downloaded libc v0.2.117
...略
   Compiling libc v0.2.117
   Compiling serde v1.0.136
   Compiling regex-syntax v0.6.25
   Compiling jailer v1.1.0 (/firecracker/src/jailer)
   Compiling regex v1.5.5
   Compiling vmm-sys-util v0.11.0
   Compiling serde_derive v1.0.136
   Compiling derive_more v0.99.17
   Compiling utils v0.1.0 (/firecracker/src/utils)
WARN rustc_codegen_ssa::back::link Linker does not support -static-pie command line option. Retrying with -static instead.
    Finished dev [unoptimized + debuginfo] target(s) in 20.80s

最終的にBuild successful.と表示されればビルド完了です。

[Firecracker devtool] Build successful.
[Firecracker devtool] Firecracker and Jailer binaries placed under /home/<ユーザー名>/firecracker/build/cargo_target/x86_64-unknown-linux-musl/debug
[Firecracker devtool] Seccompiler-bin binary placed under /home/<ユーザー名>/firecracker/build/seccompiler/x86_64-unknown-linux-musl/debug
[Firecracker devtool] Rebase_snap binary placed under /home/<ユーザー名>/firecracker/build/rebase-snap/x86_64-unknown-linux-musl/debug

スナップショットを作ってみる

これで一応Firecrackerの開発環境は構築できたんですが、せっかくなのでスナップショットを作ってみます。とりあえあずスナップショット作成を試すだけであれば、開発用のシェルスクリプトであるdevtoolのサブコマンドを実行するだけで簡単に試せるので、以下のコマンドで試してみましょう。

./tools/devtool create_snapshot_artifacts

[Firecracker devtool] Creating snapshot artifacts ...
Creating snapshot of microVM with kernel vmlinux-4.14.bin and disk ubuntu-18.04.ext4.
Copied snapshot memory file, vmstate file, disk and ssh key to: snapshot_artifacts/4.14_None_guest_snapshot.
Creating snapshot of microVM with kernel vmlinux-5.10.bin and disk ubuntu-18.04.ext4.
Copied snapshot memory file, vmstate file, disk and ssh key to: snapshot_artifacts/5.10_None_guest_snapshot.
Creating snapshot of microVM with kernel vmlinux-4.14.bin and disk ubuntu-18.04.ext4.
Copied snapshot memory file, vmstate file, disk and ssh key to: snapshot_artifacts/4.14_C3_guest_snapshot.
Creating snapshot of microVM with kernel vmlinux-5.10.bin and disk ubuntu-18.04.ext4.

snapshot_artifactsディレクトリ配下にMicroVMのスナップショットが作成されているので、このディレクトリを確認してみましょう。

ls -l snapshot_artifacts/4.14_C3_guest_snapshot/
total 1441832
-rw-r--r-- 1 root root  402653184 Nov 29 12:12 ubuntu-18.04.ext4
-rw-r--r-- 1 root root       1679 Nov 29 12:11 ubuntu-18.04.id_rsa
-rw-r--r-- 1 root root 1073741824 Nov 29 12:11 vm.mem
-rw-r--r-- 1 root root      28130 Nov 29 12:11 vm.vmstate

ファイル名から察するにubuntu-18.04.ext4がディスクのイメージでubuntu-18.04.id_rsaが秘密鍵、vm.memがMicroVMのメモリ、vm.vmstateがMicroVMのステートを保持していると考えて良さそうです。

この辺りの詳細に興味があればFirecrackerのスナップショットに関するドキュメントを確認してみて下さい。試しにvm.vmstateファイルを少し覗いてみましょう。

strings snapshot_artifacts/4.14_C3_guest_snapshot/vm.vmstate

vmlinux.bin
console=ttyS0 reboot=k panic=1 pci=off
GenuntelineI
Intel(R) Xeon(R)
 Processor @ 2.8
0GHz
@KVMKVMKVM
::::::::::::::::
ZZZZZZZZZZZZZZZZ
GenuntelineI
Intel(R) Xeon(R)
 Processor @ 2.8
0GHz
@KVMKVMKVM
rootfs
rootfs
ubuntu-18.04.ext4
tap0
tap3
tap1
tap2
vsock
/v.sock
balloon

なにやら仮想ハードウェアの情報らしきものが垣間見えました。

まとめ

Firecrackerの開発環境構築手順をご紹介しました。思ったよりも簡単ですね。

スナップショット機能を試すだけならNested Virtualizationが有効なインスタンス上にFirecrackerのバイナリをDLするだけで試せるんですが、せっかくなんで開発環境を構築して色々と触ってみるのが楽しいと思います。目指せFirecrackerコントリビューター!!

参考