AWS firecracker を試そうとしたらいろいろハマった話

#FUJITSU Advent Calendar 初日
##担当にもかかわらず、大遅刻です。ごめんなさい

GitHub Actionsが12月までには来るだろうと甘く見て、なんの準備もしなかったらこんなことになってしましました（反省）

## AWS FireCracker（OSS）を手元のマシンで触って起動させてみた

ということで、今日は、みなさん大好きAWSの新プロダクト、[firecracker](https://github.com/firecracker-microvm/firecracker)を触ってみました。

すでに、クラスメソッドさんがすでに触られた[記事](https://dev.classmethod.jp/cloud/aws/reinvent2018-try-firecracker/)がありましたが、なんであんなに簡単に動くの・・・・というくらいハマったので、そのあたりを今回の記事にします。

先のお断りですが、この記事だけでは起動の確認までで、実際にアプリを載せて動かすところまでできていません。時間を見て触っていけたらと思います。


## 環境
firecrackerは、Linuxカーネル4.14以上とKVMが必要と書かれています。
今回は、手持ちのFedora29 workstationで試しました。
このFedora 29 workstationは、MacMini Server(2011)にインストールされています。
ビルドに必要なルーツは、都度エラー解決でここでは触れませんが、`dnf groupinstall "Development Tools"`と、DockerとKVM関係を入れておけばほぼ解決するかと思います。


## 手順
GitHub上の[手順](https://github.com/firecracker-microvm/firecracker/blob/master/docs/getting-started.md
)を元にすすめます。
今回は、ソースからビルドします。

```
git clone https://github.com/firecracker-microvm/firecracker
cd firecracker
tools/devtool build --release
```

から、手順（getting-started)を上からやっていけばいです。

### 注意その１

・firecrackerと、イメージファイルは同じディレクトリに置くべし

手順にかかれていない注意として、curlコマンドを叩くカレントディレクトリに、イメージファイル２個（hello-vmlinux.binとhello-rootfs.ext4）が必要です。
絶対パスで記載しても、動かないという仕様です。
また、このカレントで、firecrackerを起動しないとcurlのレスポンスでイメージが見つからないとなります。

たとえば、デフォルトでビルド`./tool/debtool build`すると、firecrackerのバイナリは、以下に落ちます

```
firecracker/build/debug
```

そのため、手順の通り起動するには、バイナリのあるフォルダまで移動しないといけません

```
cd firecracker/build/debug
./firecracker --api-sock /tmp/firecracker.sock
```

この状態で、イメージファイルが存在するディレクトリでコマンドを叩くと

```
[tnaoto@macmini download]$ pwd
/home/tnaoto/download
[tnaoto@macmini download]$ ls
hello-rootfs.ext4  hello-vmlinux.bin
[tnaoto@macmini download]$ 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": "./hello-vmlinux.bin",
>         "boot_args": "console=ttyS0 reboot=k panic=1 pci=off"
>     }'
HTTP/1.1 400 Bad Request
Content-Type: application/json
Transfer-Encoding: chunked
Date: Sun, 02 Dec 2018 14:57:57 GMT

{
  "fault_message": "The kernel file cannot be opened due to invalid kernel path or invalid permissions."
}
```
となって、理由がわかりません

先に起動しているプロセス側にもログは出ません。


## 注意その２

・パッチを当てないとログを出さずに死ぬ

```
[tnaoto@macmini download]$ ./firecracker --api-sock /tmp/firecracker.sock
2018-12-03T00:00:51.910396674 [:ERROR:vmm/src/lib.rs:1160] Failed to log metrics while stopping: Logger was not initialized.
```

ゲストを起動しようとしたところ（start the guest machine）で、詳細なログなしで落ちます。

このため、このパッチを当てます

https://github.com/firecracker-microvm/firecracker/issues/685#issuecomment-443476791

パッチを当てたものは[こちら](https://github.com/tnaoto/firecracker/commit/f122a98711878bc582e5b2ff8a4fabda2b55ccce)

すると、こんな感じで起動します

```
[tnaoto@macmini download]$ ./firecracker --api-sock /tmp/firecracker.sock
[    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
[    0.000000] tsc: Unable to calibrate against PIT
[    0.000000] tsc: No reference (HPET/PMTIMER) available
[    0.000000] e820: last_pfn = 0x8000 max_arch_pfn = 0x400000000
[    0.000000] MTRR: Disabled
[    0.000000] x86/PAT: MTRRs disabled, skipping PAT initialization too.
[    0.000000] CPU MTRRs all blank - virtualized system.
[    0.000000] x86/PAT: Configuration [0-7]: WB  WT  UC- UC  WB  WT  UC- UC
[    0.000000] found SMP MP-table at [mem 0x0009fc00-0x0009fc0f] mapped at [ffffffffff200c00]
[    0.000000] Scanning 1 areas for low memory corruption
[    0.000000] No NUMA configuration found
[    0.000000] Faking a node at [mem 0x0000000000000000-0x0000000007ffffff]
[    0.000000] NODE_DATA(0) allocated [mem 0x07fde000-0x07ffffff]
[    0.000000] kvm-clock: Using msrs 4b564d01 and 4b564d00
[    0.000000] kvm-clock: cpu 0, msr 0:7fdc001, primary cpu clock
[    0.000000] kvm-clock: using sched offset of 26851893899 cycles
[    0.000000] clocksource: kvm-clock: mask: 0xffffffffffffffff max_cycles: 0x1cd42e4dffb, max_idle_ns: 881590591483 ns
[    0.000000] Zone ranges:
[    0.000000]   DMA      [mem 0x0000000000001000-0x0000000000ffffff]
[    0.000000]   DMA32    [mem 0x0000000001000000-0x0000000007ffffff]
[    0.000000]   Normal   empty
[    0.000000] Movable zone start for each node
[    0.000000] Early memory node ranges
[    0.000000]   node   0: [mem 0x0000000000001000-0x000000000009efff]
[    0.000000]   node   0: [mem 0x0000000000100000-0x0000000007ffffff]
[    0.000000] Initmem setup node 0 [mem 0x0000000000001000-0x0000000007ffffff]
[    0.000000] Intel MultiProcessor Specification v1.4
[    0.000000] MPTABLE: OEM ID: FC
[    0.000000] MPTABLE: Product ID: 000000000000
[    0.000000] MPTABLE: APIC at: 0xFEE00000
[    0.000000] Processor #0 (Bootup-CPU)
[    0.000000] IOAPIC[0]: apic_id 2, version 17, address 0xfec00000, GSI 0-23
[    0.000000] Processors: 1
[    0.000000] smpboot: Allowing 1 CPUs, 0 hotplug CPUs
[    0.000000] PM: Registered nosave memory: [mem 0x00000000-0x00000fff]
[    0.000000] PM: Registered nosave memory: [mem 0x0009f000-0x000fffff]
[    0.000000] e820: [mem 0x08000000-0xffffffff] available for PCI devices
[    0.000000] Booting paravirtualized kernel on KVM
[    0.000000] clocksource: refined-jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645519600211568 ns
[    0.000000] random: get_random_bytes called from start_kernel+0x94/0x486 with crng_init=0
[    0.000000] setup_percpu: NR_CPUS:128 nr_cpumask_bits:128 nr_cpu_ids:1 nr_node_ids:1
[    0.000000] percpu: Embedded 41 pages/cpu @ffff880007c00000 s128728 r8192 d31016 u2097152
[    0.000000] KVM setup async PF for cpu 0
[    0.000000] kvm-stealtime: cpu 0, msr 7c15040
[    0.000000] PV qspinlock hash table entries: 256 (order: 0, 4096 bytes)
[    0.000000] Built 1 zonelists, mobility grouping on.  Total pages: 32137
[    0.000000] Policy zone: DMA32
[    0.000000] Kernel command line: console=ttyS0 reboot=k panic=1 pci=off  root=/dev/vda virtio_mmio.device=4K@0xd0000000:5
[    0.000000] PID hash table entries: 512 (order: 0, 4096 bytes)
[    0.000000] Memory: 111064K/130680K available (8204K kernel code, 622K rwdata, 1464K rodata, 1268K init, 2820K bss, 19616K reserved, 0K cma-reserved)
[    0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
[    0.000000] Kernel/User page tables isolation: enabled
[    0.004000] Hierarchical RCU implementation.
[    0.004000] 	RCU restricting CPUs from NR_CPUS=128 to nr_cpu_ids=1.
[    0.004000] RCU: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=1
[    0.004000] NR_IRQS: 4352, nr_irqs: 48, preallocated irqs: 16
[    0.004000] Console: colour dummy device 80x25
[    0.004000] console [ttyS0] enabled
[    0.004000] tsc: Detected 1995.467 MHz processor
[    0.004000] Calibrating delay loop (skipped) preset value.. 3990.93 BogoMIPS (lpj=7981868)
[    0.004000] pid_max: default: 32768 minimum: 301
[    0.004000] Security Framework initialized
[    0.004020] SELinux:  Initializing.
[    0.004867] Dentry cache hash table entries: 16384 (order: 5, 131072 bytes)
[    0.006258] Inode-cache hash table entries: 8192 (order: 4, 65536 bytes)
[    0.007537] Mount-cache hash table entries: 512 (order: 0, 4096 bytes)
[    0.008014] Mountpoint-cache hash table entries: 512 (order: 0, 4096 bytes)
[    0.009799] Last level iTLB entries: 4KB 512, 2MB 8, 4MB 8
[    0.010827] Last level dTLB entries: 4KB 512, 2MB 32, 4MB 32, 1GB 0
[    0.012006] Spectre V2 : Mitigation: Full generic retpoline
[    0.013052] Spectre V2 : Spectre v2 mitigation: Enabling Indirect Branch Prediction Barrier
[    0.014614] Spectre V2 : Enabling Restricted Speculation for firmware calls
[    0.016004] Speculative Store Bypass: Mitigation: Speculative Store Bypass disabled via prctl and seccomp
[    0.033889] Freeing SMP alternatives memory: 28K
[    0.036299] smpboot: Max logical packages: 1
[    0.037487] x2apic enabled
[    0.038405] Switched APIC routing to physical x2apic.
[    0.040998] ..TIMER: vector=0x30 apic1=0 pin1=0 apic2=-1 pin2=-1
[    0.042192] smpboot: CPU0: Intel(R) Xeon(R) Processor (family: 0x6, model: 0x2a, stepping: 0x7)
[    0.043946] Performance Events: unsupported p6 CPU model 42 no PMU driver, software events only.
[    0.044000] Hierarchical SRCU implementation.
[    0.044440] smp: Bringing up secondary CPUs ...
[    0.045311] smp: Brought up 1 node, 1 CPU
[    0.046072] smpboot: Total of 1 processors activated (3990.93 BogoMIPS)
[    0.047736] devtmpfs: initialized
[    0.048071] x86/mm: Memory block size: 128MB
[    0.049092] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns
[    0.050929] futex hash table entries: 256 (order: 2, 16384 bytes)
[    0.052314] NET: Registered protocol family 16
[    0.053354] cpuidle: using governor ladder
[    0.054139] cpuidle: using governor menu
[    0.060248] HugeTLB registered 2.00 MiB page size, pre-allocated 0 pages
[    0.061795] dmi: Firmware registration failed.
[    0.062773] NetLabel: Initializing
[    0.063421] NetLabel:  domain hash size = 128
[    0.064015] NetLabel:  protocols = UNLABELED CIPSOv4 CALIPSO
[    0.065120] NetLabel:  unlabeled traffic allowed by default
[    0.066527] clocksource: Switched to clocksource kvm-clock
[    0.067594] VFS: Disk quotas dquot_6.6.0
[    0.067594] VFS: Dquot-cache hash table entries: 512 (order 0, 4096 bytes)
[    0.070781] NET: Registered protocol family 2
[    0.071784] TCP established hash table entries: 1024 (order: 1, 8192 bytes)
[    0.073135] TCP bind hash table entries: 1024 (order: 2, 16384 bytes)
[    0.074362] TCP: Hash tables configured (established 1024 bind 1024)
[    0.075592] UDP hash table entries: 256 (order: 1, 8192 bytes)
[    0.076728] UDP-Lite hash table entries: 256 (order: 1, 8192 bytes)
[    0.077945] NET: Registered protocol family 1
[    0.079594] virtio-mmio: Registering device virtio-mmio.0 at 0xd0000000-0xd0000fff, IRQ 5.
[    0.081200] platform rtc_cmos: registered platform RTC device (no PNP device found)
[    0.082860] Scanning for low memory corruption every 60 seconds
[    0.084314] audit: initializing netlink subsys (disabled)
[    0.085677] Initialise system trusted keyrings
[    0.086521] Key type blacklist registered
[    0.087326] audit: type=2000 audit(1543763068.395:1): state=initialized audit_enabled=0 res=1
[    0.089020] workingset: timestamp_bits=36 max_order=15 bucket_order=0
[    0.091822] squashfs: version 4.0 (2009/01/31) Phillip Lougher
[    0.096553] Key type asymmetric registered
[    0.097354] Asymmetric key parser 'x509' registered
[    0.098321] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 254)
[    0.099794] io scheduler noop registered (default)
[    0.100793] io scheduler cfq registered
[    0.101762] virtio-mmio virtio-mmio.0: Failed to enable 64-bit or 32-bit DMA.  Trying to continue, but this might not work.
[    0.104098] Serial: 8250/16550 driver, 1 ports, IRQ sharing disabled
[    0.128038] serial8250: ttyS0 at I/O 0x3f8 (irq = 4, base_baud = 115200) is a U6_16550A
[    0.131548] loop: module loaded
[    0.133058] tun: Universal TUN/TAP device driver, 1.6
[    0.134090] hidraw: raw HID events driver (C) Jiri Kosina
[    0.135184] nf_conntrack version 0.5.0 (1024 buckets, 4096 max)
[    0.136467] ip_tables: (C) 2000-2006 Netfilter Core Team
[    0.137535] Initializing XFRM netlink socket
[    0.138456] NET: Registered protocol family 10
[    0.139932] Segment Routing with IPv6
[    0.140694] NET: Registered protocol family 17
[    0.141555] Bridge firewalling registered
[    0.142377] sched_clock: Marking stable (140649458, 0)->(245981005, -105331547)
[    0.143968] registered taskstats version 1
[    0.144768] Loading compiled-in X.509 certificates
[    0.146789] Loaded X.509 cert 'Build time autogenerated kernel key: 3472798b31ba23b86c1c5c7236c9c91723ae5ee9'
[    0.148698] zswap: default zpool zbud not available
[    0.149620] zswap: pool creation failed
[    0.150518] Key type encrypted registered
[    0.160671] EXT4-fs (vda): recovery complete
[    0.161721] EXT4-fs (vda): mounted filesystem with ordered data mode. Opts: (null)
[    0.163159] VFS: Mounted root (ext4 filesystem) on device 254:0.
[    0.165617] devtmpfs: mounted
[    0.167105] Freeing unused kernel memory: 1268K
[    0.176244] Write protecting the kernel read-only data: 12288k
[    0.179194] Freeing unused kernel memory: 2016K
[    0.182499] Freeing unused kernel memory: 584K
2018-12-03T00:04:28.589449367 [:WARN:vmm/src/lib.rs:906] Guest-boot-time = 346826 us 346 ms, 334391 CPU us 334 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)

 * Mounting /proc ...
 [ ok ]
 * Mounting /run ...
 * /run/openrc: creating directory
 * /run/lock: creating directory
 * /run/lock: correcting owner
 * Caching service dependencies ...
Service `hwdrivers' needs non existent service `dev'
 [ ok ]
Starting boot runlevel
 * Remounting devtmpfs on /dev ...
 [ ok ]
 * Mounting /dev/mqueue ...
 [ ok ]
 * Mounting /dev/pts ...
 [ ok ]
 * Mounting /dev/shm ...
 [ ok ]
 * Setting hostname ...
 [ ok ]
 * Checking local filesystems  ...
 [ ok ][    0.398169] random: fast init done

 * Remounting filesystems ...
 [ ok ]
 * Mounting local filesystems ...
 [ ok ]
 * Loading modules ...
modprobe: can't change directory to '/lib/modules': No such file or directory
modprobe: can't change directory to '/lib/modules': No such file or directory
 [ ok ]
 * Mounting misc binary format filesystem ...
 [ ok ]
 * Mounting /sys ...
 [ ok ]
 * Mounting security filesystem ...
 [ ok ]
 * Mounting debug filesystem ...
 [ ok ]
 * Mounting SELinux filesystem ...
 [ ok ]
 * Mounting persistent storage (pstore) filesystem ...
 [ ok ]
Starting default runlevel
[    1.088252] clocksource: tsc: mask: 0xffffffffffffffff max_cycles: 0x3986e85801c, max_idle_ns: 881590625023 ns

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

localhost login:
```

たしかに一瞬で起動するので、これは良いかもしれません

起動したVMには、root/rootで入れます

```
localhost:~# cat /proc/cpuinfo
processor	: 0
vendor_id	: GenuineIntel
cpu family	: 6
model		: 42
model name	: Intel(R) Xeon(R) Processor
stepping	: 7
microcode	: 0x1
cpu MHz		: 1995.467
cache size	: 6144 KB
physical id	: 0
siblings	: 1
core id		: 0
cpu cores	: 1
apicid		: 0
initial apicid	: 0
fpu		: yes
fpu_exception	: yes
cpuid level	: 13
wp		: yes
flags		: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss syscall nx rdtscp lm constant_tsc rep_good nopl nonstop_tsc cpuid pni pclmulqdq vmx ssse3 cx16 pcid sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer aes xsave avx hypervisor lahf_lm cpuid_fault pti ssbd ibrs ibpb tpr_shadow vnmi flexpriority ept vpid tsc_adjust xsaveopt arat umip arch_capabilities
bugs		: cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass
bogomips	: 3990.93
clflush size	: 64
cache_alignment	: 64
address sizes	: 36 bits physical, 48 bits virtual
power management:
```

VMを１００個とかつくりたければ、firecrackerのインスタンスを１００個起動して、それぞれにファイルを与えて起動すれば良いですが、現在のこの状態だとネットワークデバイスがアタッチされていないため、VMが外界を通信することができず、面白みはありません。

このあたりは、引き続き時間のあるときに調査していきたいと思います。

### 注意その３

・シャットダウンが下手

shutdownコマンドはありません。
なので、halt コマンドなのですが、OSは終わってもFireCrackerが終わりません。
Ctrl-Cでもだめです。プロセスを探してkillする必要があります

また、応急として、rebootコマンドを打つと綺麗に死ぬ謎仕様です
PRでは、Graceful shutdown on rebootとか書かれているんですが、なんだそれ　です

https://github.com/firecracker-microvm/firecracker/pull/503/commits/bafb0e6ebf938322f88a0b2a492f2c0dc3541c54

なので、１００個VM作るとか遊ぶと、殺すのに一苦労します


##終わりに

まだ新しいプロダクトであるため、OSSに名を残すチャンスです。
Issueでもドキュメントでもとりあえずなにかあったら書いてみるのがいいでしょう

言語がRustなので馴染みがないかもしれませんが、C/C++ができる方は読もうと思えば読めるのではないでしょうか（私は少しは読めても書ける気がしないですが・・・）