AWS Firecrackerを触ってみる

## Firecrackerとは
AWS re:invent 2018で発表された新サービス？というかOSSです。

[Firecrackerの紹介](https://aws.amazon.com/jp/blogs/news/firecracker-lightweight-virtualization-for-serverless-computing/)

概要を見たときは前にまとめたKata Conteinersに似ていると思いましたがFirecrackerはVMMみたいなので完全に別物ですね。

そういう認識があるのかGithub上にもKataContainersとの違いが書いてあったりします。

[Firecracker Github](https://firecracker-microvm.github.io/)
`What is the difference between Firecracker and Kata Containers and QEMU?`

* FirecrackerはVMM
* KVMベースでQEMUの代わりに動作するプロセス
* LambdaやFargate用基盤で使われているらしい

![image.png](https://qiita-image-store.s3.amazonaws.com/0/146026/23dd6152-5abd-472d-93ac-22396564dc40.png)


[Firecracker のデザインについて調べてみた](https://dev.classmethod.jp/cloud/aws/reinvent2018-study-firecracker/)

* Firecracker はユーザー空間で動作する
* Linuxカーネルベースの仮想マシン（KVM）を使用して microVM を作成する
* Firecracker は QEMU に代わる幅広い機能を備えた VMM（仮想マシンモニター）
* 様々なゲストOS をホストする
* Firecracker プロセスはvCPUの数の設定やマシンの起動などの一般的な操作を RESTful API 経由で制御できる
* Firecracker プロセスは同じマシン上の何千ものマイクロVMによって使用されるネットワークとストレージのリソースを細かく制御できるように、レートリミッタを内蔵している
* Firecracker はホストとゲストOS 間で構成情報を安全に共有するメタデータサービスも提供する
* Firecracker API を使用してメタデータサービス構成および設定ができる

RESTful APIで制御可能な、最適化されたVMMであるというところが魅力ですね。

## 触ってみる

まあ、Githubのインストールページを参考にしているだけですが。

FirecrackerはAWSだとベアメタルインスタンス(i3.metal)で実行する必要がありそうです。

今回はGCEのネストインスタンスを使ってみます。

ネストインスタンスとは入れ子の意味でVM内で更にVMを動かす時の仕組みです。
[Google Compute Engine、仮想マシンの入れ子（Nested Virtualization）を可能に。KVM対応](https://www.publickey1.jp/blog/17/google_compute_enginenested_virtualizationkvm.html)

## 事前準備

### OS

 * Linux 4.14+
  * Firecracker currently supports physical Linux x86_64 hosts, with kernel version 4.14 or later.

* KVM
 * you have KVM enabled in your Linux kernel
 * you have read/write access to /dev/kvm

### Docker Install
```
$ sudo apt-get update
$ sudo apt-get install docker.io

$ sudo yum install docker
$ sudo systemctl start docker
$ sudo usermod -aG docker $USER
```

## ダウンロード
モジュールをダウンロードすればそのまま使えます。
ソースコードを自分でビルドもできます。

```
$ curl -fsSL -o firecracker  https://github.com/firecracker-microvm/firecracker/releases/download/v0.11.0/firecracker-v0.11.0

$ chmod +x firecracker
$ ls -l
total 6008
-rwxr-xr-x 1 root root 6151112 Nov 29 13:40 firecracker

$ ./firecracker -V
firecracker 0.11.0
```

## プロセス実行
```
$ rm -f /tmp/firecracker.sock
$ firecracker --api-sock /tmp/firecracker.sock
```
これを実行するとフォアグラウンドでターミナルを占有してしまうので別ターミナルでアクセスします。

ここで作ったunix domain socketに対してRESTful APIでアクセスできます。
/をGETすると応答があります。

```
$ sudo curl --unix-socket /tmp/firecracker.sock -i http://localhost/


HTTP/1.1 200 OK
Content-Type: application/json
Transfer-Encoding: chunked
Date: Thu, 29 Nov 2018 09:53:21 GMT

{"id":"anonymous-instance","state":"Uninitialized"}
```

## テストVM実行

AWS公式のS3上にテストイメージがあるのでダウンロードします。

```
$ curl -fsSL -o hello-vmlinux.bin https://s3.amazonaws.com/spec.ccfc.min/img/hello/kernel/hello-vmlinux.bin
$ curl -fsSL -o hello-rootfs.ext4 https://s3.amazonaws.com/spec.ccfc.min/img/hello/fsfiles/hello-rootfs.ext4
$ ls -l
total 57496
-rwxr-xr-x 1 root root  6151112 Nov 29 13:40 firecracker
-rw-r--r-- 1 root root 31457280 Nov 29 13:56 hello-rootfs.ext4
-rw-r--r-- 1 root root 21266136 Nov 29 13:54 hello-vmlinux.bin
```

### バイナリアップロード

```
$ curl --unix-socket /tmp/firecracker.sock -i \
     -X PUT 'http://localhost/boot-source'   \
     -H 'Accept: application/json'           \
     -H 'Content-Type: application/json'     \
     -d '{
        "kernel_image_path": "/usr/firecracker/hello-vmlinux.bin",
        "boot_args": "console=ttyS0 reboot=k panic=1 pci=off"
     }'


HTTP/1.1 204 No Content
Date: Thu, 29 Nov 2018 13:58:52 GMT
```

### rootファイルシステムアップロード

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


HTTP/1.1 204 No Content
Date: Thu, 29 Nov 2018 14:00:13 GMT
```

なんとなーくlsofで見てみると/dev/kvmやら関連ファイルが開かれています。

```
$ lsof /tmp/firecracker.sock
COMMAND     PID USER   FD   TYPE             DEVICE SIZE/OFF  NODE NAME
firecrack 21848 root    8u  unix 0xffffa0553bca6000      0t0 84467 /tmp/firecracker.sock type=STREAM

```

```
$ lsof -p 21848
COMMAND     PID USER   FD      TYPE             DEVICE SIZE/OFF   NODE NAME
firecrack 21848 root  cwd       DIR                8,1     4096      2 /
firecrack 21848 root  rtd       DIR                8,1     4096      2 /
firecrack 21848 root  txt       REG                8,1  6151112 519615 /usr/firecracker/firecracker
firecrack 21848 root    0u      CHR              136,0      0t0      3 /dev/pts/0
firecrack 21848 root    1u      CHR              136,0      0t0      3 /dev/pts/0
firecrack 21848 root    2u      CHR              136,0      0t0      3 /dev/pts/0
firecrack 21848 root    3u  a_inode               0,13        0  10602 [eventfd]
firecrack 21848 root    4u  a_inode               0,13        0  10602 [eventfd]
firecrack 21848 root    5u  a_inode               0,13        0  10602 [eventpoll]
firecrack 21848 root    6r     FIFO               0,12      0t0  84466 pipe
firecrack 21848 root    7w     FIFO               0,12      0t0  84466 pipe
firecrack 21848 root    8u     unix 0xffffa0553bca6000      0t0  84467 /tmp/firecracker.sock type=STREAM
firecrack 21848 root    9u  a_inode               0,13        0  10602 [eventpoll]
firecrack 21848 root   10u  a_inode               0,13        0  10602 [timerfd]
firecrack 21848 root   11u      CHR             10,232      0t0    384 /dev/kvm
firecrack 21848 root   12u  a_inode               0,13        0  10602 kvm-vm
firecrack 21848 root   13u  a_inode               0,13        0  10602 [eventfd]
firecrack 21848 root   14u  a_inode               0,13        0  10602 [eventfd]
firecrack 21848 root   15u  a_inode               0,13        0  10602 [eventfd]
firecrack 21848 root   16u  a_inode               0,13        0  10602 [eventfd]
firecrack 21848 root   18r      REG                8,1 21266136 519617 /usr/firecracker/hello-vmlinux.bin
```

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


HTTP/1.1 204 No Content
Date: Thu, 29 Nov 2018 14:09:20 GMT
```

VMを起動させるとfirecrackerプロセスを実行したターミナル側にバーッと起動メッセージが出力され、その後にカーネルが起動してきます。

```
[    0.000000] Linux version 4.14.55-84.37.amzn2.x86_64 (mockbuild@ip-10-0-1-79) (gcc version 7.3.1 20180303 (Red Hat 7.3.1-5) (GCC)) #1 SMP Wed Jul 25 18:47:15 UTC 2018
[    0.000000] Command line: console=ttyS0 reboot=k panic=1 pci=off  root=/dev/vda virtio_mmio.device=4K@0xd0000000:5
[    0.000000] x86/fpu: Supporting XSAVE feature 0x001: 'x87 floating point registers'
[    0.000000] x86/fpu: Supporting XSAVE feature 0x002: 'SSE registers'
[    0.000000] x86/fpu: Supporting XSAVE feature 0x004: 'AVX registers'
[    0.000000] x86/fpu: xstate_offset[2]:  576, xstate_sizes[2]:  256
[    0.000000] x86/fpu: Enabled xstate features 0x7, context size is 832 bytes, using 'standard' format.
[    0.000000] e820: BIOS-provided physical RAM map:
[    0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
[    0.000000] BIOS-e820: [mem 0x0000000000100000-0x0000000007ffffff] usable
[    0.000000] NX (Execute Disable) protection: active
[    0.000000] DMI not present or invalid.
[    0.000000] Hypervisor detected: KVM

・
・
<中略>
・
・

2018-11-29T14:09:22.416078504 [:WARN:vmm/src/lib.rs:903] Guest-boot-time = 1490307 us 1490 ms, 1485027 CPU us 1485 CPU ms
OpenRC init version 0.35.5.87b1ff59c1 starting
Starting sysinit runlevel

   OpenRC 0.35.5.87b1ff59c1 is starting up Linux 4.14.55-84.37.amzn2.x86_64 (x86_64)

・
・
<中略>
・
・

Welcome to Alpine Linux 3.8
Kernel 4.14.55-84.37.amzn2.x86_64 on an x86_64 (ttyS0)

localhost 
```

最後にログインプロンプトが表示されます。
VM起動しました。

ここでステータスを見てみるとstateがRunningになっています。

```
$ curl --unix-socket /tmp/firecracker.sock -i http://localhost/

HTTP/1.1 200 OK
Content-Type: application/json
Transfer-Encoding: chunked
Date: Thu, 29 Nov 2018 14:17:03 GMT

{"id":"anonymous-instance","state":"Running"}
```

他にも[firecrackerのAPI](https://github.com/firecracker-microvm/firecracker/blob/master/api_server/swagger/firecracker.yaml)があるんでGET系のものを実行してみます。

```
$ curl --unix-socket /tmp/firecracker.sock http://localhost/machine-config

{ "vcpu_count": 1, "mem_size_mib": 128,  "ht_enabled": false,  "cpu_template": "Uninitialized" }
```

## VMにログイン
このVMイメージの場合はrootアカウントにrootパスワードでログインできます。

```
localhost login: root
Password:
Welcome to Alpine!

The Alpine Wiki contains a large amount of how-to guides and general
information about administrating Alpine systems.
See <http://wiki.alpinelinux.org>.

You can setup the system with the command: setup-alpine

You may change this message by editing /etc/motd.

login[984]: root login on 'ttyS0'
localhost:~#
```

とりあえずVMMとしてVM起動まで～
まあ、これだけだとQEMUとの違いとかがわからないっすね