ラズパイ4にFirecrackerの環境を構築してMicroVMを動かそう!!

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

Firecrackerのロードマップとして掲げられているARMサポートですが、現在Preview段階まで開発が進んでいます。また、1ヶ月前にリリースされたFirecracker v0.20.0でGICv2のサポートが追加されたことで、ラズパイ4上でFirecrackerを試すことが可能になりました。このブログではラズパイ4上でFirecrackerのMicroVMを起動させるまでの手順をご紹介します。

環境

今回利用した環境です

  • Raspberry Pi 4 Model B
  • Ubuntu Server 19.10.1
  • カーネル 5.3.0-1015-raspi2
  • Firecracker v0.20.0

やってみる

ここからは実際に環境構築~MicroVM起動までの手順をご紹介します。

OSのインストール

ラズパイのOSといえばRaspbian...なのですが、Raspbianは32ビットOSです。Firecrackerを動かすにはKVMが有効化されたカーネル4.14以後の64ビットOSが必要になります。UbuntuのWikiでラズパイ向けにUbuntu Serverのイメージが公開されているので、以下のリンクからUbuntu Server19.10.1のイメージを取得してインストールしましょう。

ubuntu-19.10.1-preinstalled-server-arm64+raspi3.img.xz

Firecrackerのバイナリ取得

OSがインストールできたらFirecrackerのGetting Startedの内容に沿って環境を構築していきます。まずarm64向けのバイナリを取得してパスの通っている適当なディレクトリに突っ込みます。

$ latest=$(basename $(curl -fsSLI -o /dev/null -w  %{url_effective}  https://github.com/firecracker-microvm/firecracker/releases/latest))
$ curl -LOJ https://github.com/firecracker-microvm/firecracker/releases/download/${latest}/firecracker-${latest}-$(uname -m)
$ mv firecracker-${latest}-$(uname -m) firecracker
$ sudo chmod +x firecracker
$ suod mv firecracker /usr/local/bin

KVMのパーミッション設定

Firecrackerを実行するには/dev/kvmに対するパーミッションが必要になります。setfaclコマンドでパーミッションを設定しましょう。インストールしたUbuntu Serverのイメージにはsetfaclコマンドがインストールされていないので、事前にインストールします。

$ sudo apt install acl

拡張ACLを設定します。

$ sudo setfacl -m u:${USER}:rw /dev/kvm

前提条件のチェック

ここまでできたら一旦以下のスクリプトを実行して前提条件のチェックを行います。

err="";
[ "$(uname) $(uname -m)" = "Linux x86_64" ]  \
  || [ "$(uname) $(uname -m)" = "Linux aarch64" ] \
  || err="ERROR: your system is not Linux x86_64 or Linux aarch64."; \
[ -r /dev/kvm ] && [ -w /dev/kvm ] \
  || err="$err\nERROR: /dev/kvm is innaccessible."; \
(( $(uname -r | cut -d. -f1)*1000 + $(uname -r | cut -d. -f2) >= 4014 )) \
  || err="$err\nERROR: your kernel version ($(uname -r)) is too old."; \
dmesg | grep -i "hypervisor detected" \
  && echo "WARNING: you are running in a virtual machine." \
  && echo "Firecracker is not well tested under nested virtualization."; \
[ -z "$err" ] && echo "Your system looks ready for Firecracker!" || echo -e "$err"

Your system looks ready for Firecracker!と表示されればチェックOKです

MicroVM用のカーネル&ルートファイルシステムの準備

MicroVMを起動するために必要なカーネル&ルートファイルシステムのイメージがS3で公開されているので、以下のスクリプトを実行してDLします。

arch=`uname -m`
dest_kernel="hello-vmlinux.bin"
dest_rootfs="hello-rootfs.ext4"
image_bucket_url="https://s3.amazonaws.com/spec.ccfc.min/img"

if [ ${arch} = "x86_64" ]; then
        kernel="${image_bucket_url}/hello/kernel/hello-vmlinux.bin"
        rootfs="${image_bucket_url}/hello/fsfiles/hello-rootfs.ext4"
elif [ ${arch} = "aarch64" ]; then
        kernel="${image_bucket_url}/aarch64/ubuntu_with_ssh/kernel/vmlinux.bin"
        rootfs="${image_bucket_url}/aarch64/ubuntu_with_ssh/fsfiles/xenial.rootfs.ext4"
else
        echo "Cannot run firecracker on $arch architecture!"
        exit 1
fi

echo "Downloading $kernel..."
curl -fsSL -o $dest_kernel $kernel

echo "Downloading $rootfs..."
curl -fsSL -o $dest_rootfs $rootfs

echo "Saved kernel file to $dest_kernel and root block device to $dest_rootfs."

Firecrackerの起動

カーネル&ルートファイルシステムの準備ができたらFirecrackerのプロセスを起動し、管理用のAPIを受け付ける準備をします。

firecracker --api-sock /tmp/firecracker.socket

MicroVMの設定と起動

Firecrackerのプロセスが起動できたら別のシェルからFirecrackerのAPIサーバーに対してリクエストを実行し、MicroVMの設定を行います。

まずカーネルの設定です

arch=`uname -m`
kernel_path=$(pwd)"/hello-vmlinux.bin"

if [ ${arch} = "x86_64" ]; then
  curl --unix-socket /tmp/firecracker.socket -i \
      -X PUT 'http://localhost/boot-source'   \
      -H 'Accept: application/json'           \
      -H 'Content-Type: application/json'     \
      -d "{
            \"kernel_image_path\": \"${kernel_path}\",
            \"boot_args\": \"console=ttyS0 reboot=k panic=1 pci=off\"
       }"
elif [ ${arch} = "aarch64" ]; then
    curl --unix-socket /tmp/firecracker.socket -i \
      -X PUT 'http://localhost/boot-source'   \
      -H 'Accept: application/json'           \
      -H 'Content-Type: application/json'     \
      -d "{
            \"kernel_image_path\": \"${kernel_path}\",
            \"boot_args\": \"keep_bootcon console=ttyS0 reboot=k panic=1 pci=off\"
       }"
else
    echo "Cannot run firecracker on $arch architecture!"
    exit 1
fi

続いてルートファイルシステムです

rootfs_path=$(pwd)"/hello-rootfs.ext4"
curl --unix-socket /tmp/firecracker.socket -i \
  -X PUT 'http://localhost/drives/rootfs' \
  -H 'Accept: application/json'           \
  -H 'Content-Type: application/json'     \
  -d "{
        \"drive_id\": \"rootfs\",
        \"path_on_host\": \"${rootfs_path}\",
        \"is_root_device\": true,
        \"is_read_only\": false
   }"

準備ができたのでいよいよMicroVMの起動です!!

curl --unix-socket /tmp/firecracker.socket -i \
    -X PUT 'http://localhost/actions'       \
    -H  'Accept: application/json'          \
    -H  'Content-Type: application/json'    \
    -d '{
        "action_type": "InstanceStart"
     }'

成功するとFirecrackerのプロセスを起動した1つ目のシェルにMicroVMのブートメッセージが流れた後、ログインプロンプトが表示されます。

[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Linux version 4.14.138 (sandreim@firecracker-arm-ci) (gcc version 7.4.0 (Ubuntu/Linaro 7.4.0-1ubuntu1~18.04.1)) #1 SMP Tue Sep 10 12:26:05 UTC 2019
[    0.000000] Boot CPU: AArch64 Processor [410fd083]
[    0.000000] Machine model: linux,dummy-virt

...略
[  OK  ] Started Serial Getty on ttyS0.
[  OK  ] Reached target Login Prompts.
[  OK  ] Reached target Multi-User System.
[  OK  ] Reached target Graphical Interface.
         Starting Update UTMP about System Runlevel Changes...
[  OK  ] Started Update UTMP about System Runlevel Changes.

Ubuntu 18.04.2 LTS fadfdd4af58a ttyS0

fadfdd4af58a login:

ID・パスワードともに root でMicroVMにログインできるので、MicroVMをいじくり回してやりましょう。

ハマったポイント

最終的にはGetting Startedの手順そのままで非常にお手軽にMicroVMを起動することに成功しました。が、ここに至るまで色々と苦労したので、ハマりポイントを共有しておきます。

RaspbianだとFirecrackerが動作しない

前述の通りFirecrackerは64ビットOSが必要になります。自前でOSイメージを用意するのは面倒なので公開されているUbuntu Serverのイメージを使いましょう。

Ubuntu公式で提供されている18.04 LTSのイメージはKVMが無効

最初LTSだからという理由で19.10.1のイメージではなく18.04 LTSのイメージを利用していたのですが、KVMが無効化されており、Firecrackerが起動できませんでした。KVMを有効化してカーネルを再ビルドしたのですが、再起動後にSSHで接続できなくなり、適当なディスプレイ&HDMIケーブルを持っていなかったので原因の切り分けもできずに諦めました。

ラズパイ3BだとFirecrackerが動作しない?

元々ラズパイ4を持っていなかったのでラズパイ3で挑戦したのですが、GICではなく独自の割込みコントローラを利用しているそうで、Firecrackerの仮想デバイス初期化が異常終了してしまいました。

参考: Raspberry Pi 3の割込みについてまとめる

後からブートオプションでenable_gicに1を指定すればGIC-400を利用するという記述も見つけたのですが、enable_gicはデフォルトで1になるそうなので、何が原因だったのかはよく分かっていません。

Boot options in config.txt

もしかすると頑張ればラズパイ3上でもFirecrackerを動作させることは可能なのかもしれません。

最新版のFirecrackerのソースからビルドするとMicroVMの起動に失敗する

最初は現時点の最新版リリースv0.20.0にGICv2サポートが追加されていることに気づいておらず、Firecrackerを自前でビルドしていました。が、どうにもMicroVMの起動に失敗してうまくいきませんでした。v0.20.0にGICv2サポートが追加されている(というかGetting Startedがいつの間にかARM対応していた)ことに気付いたので自前ビルドをやめてGetting Startedの手順通り進めることでうまくいくようになりました。結局自前ビルドしたFirecrackerがMicroVMの起動に失敗する理由はよく分からずでした。

まとめ

Firecrackerというと試すのには敷居が高い印象がありましたが、ラズパイ4を使うことでお手軽に試すことが可能になりました。みなさんも是非一度お試し下さい。