Firecrackerつかいたい

本記事はwhywaita Advent Calendar 2019 16日目の記事です。

初めまして、uronです。 ちなみにwhywaita界隈ではかなり新入りです。ご容赦ください。

ちなみに概要にwaitawhyのすべらない話と書いてありますが、whywaitとは少ししか被らない事もご容赦ください。

#0

自分は今年の4月からwhy君と仲良くさせて貰ってるんですが、彼のインフラチックなところがかなり好きですし尊敬してます。 なので、自分も見習わなきゃと自分なりに調べている所存であります。そんな事もありながら最近では彼の敵とも言える aws の海外カンファレンスに行って帰ってきてからの話。

f:id:kurouw:20191216040236j:plain

このように治安の悪い話をしながらしたい事を語り合ってます。(雑談なんでご容赦を)

と言う事でFargate作ります!!!!!(作れません)

どうやらFargateはFirecrackerと言われる仮想化技術を使っているそうです。しかも最近ではfirecracker-containerdと呼ばれるコンテナランタイムを使っているらしいです。

仮想化とかコンテナとかはまあ詳しくはないんですが、触ってみたいなと言う事でwhy君のアドベントカレンダーを使わせていただきます。

Firecracker is 何

awsによって開発された、仮想化技術で、使用しないデバイスやゲスト向けの機能を排除して、起動や実行に必要なメモリー量と攻撃されそうな領域を減らす。それによってFirecrackerで作られたvmはセキュリティーが向上し起動時間も早くなり、ハードウェアの使用率が向上するらしいです。

起動が早くてセキュリティも考慮された小さいvmを立ち上げるものだと解釈してます。 起動・停止が早い分Fargateやlambdaのようにすぐスケールアウトしてすぐスケールインして欲しい用件があるサービスの基板にはいいんだろうなと思います。

firecracker-containerd is 何

continerdのコンテナランタイムとしてFirecracker microVMを管理できるようにするソフトウェアらしいです。

どう言う事かと言うと、

例えばkubernetesで podを作る時を考えると

  1. podとかを作る要求を僕らがする
  2. 高レベルランタイムに要求がくる
  3. 高レベルランタイムから低レベルランタイムに要求がくる
  4. 低レベルランタイムがコンテナを作る

のように動いているっぽいです。

webで例えるなら フロント(kubelet)があって、webサーバー(高レベルランタイム)に要求が行って、webサーバーから、データベース(低レベルランタイム)にクエリが投げられて、データベースが処理をしてデータを永続化する。自分はこのようになんとなく理解しています。

上記の話の高レベルランタイムに当たるのがcontainerdでFirecracker microVMは低レベルランタイムに当たるのかなと思います。

間違っていたら教えて!why君!

実際にコンテナ作ってみる

前提条件

  • Linux (4.14+), an Intel x86_64 processor and KVM enabled. 対応のマシン
  • git
  • ルートファイルシステム
  • Docker CE
  • Go 1.11以降

マシンの用意

Linux (4.14+), an Intel x86_64 processor and KVM enabled. 対応のマシンを用意していきます。

優しいことにドキュメントには候補が書いてありました。

  An i3.metal running Amazon Linux 2 is a good candidate.

EC2の普通のインスタンスはすでに仮想化されていてNested VMは許可されてないようなのでやはりベアメタルのインスタンスになるってことなんでしょうね。値段は高いですが少しの勉強の間ならまあ大丈夫です。

f:id:kurouw:20191216041101p:plain

f:id:kurouw:20191216041119j:plain

用意しました。ここからが勝負!

firecrackerが使えるか確認しましょう。

#!/bin/bash
err=""; \
[ "$(uname) $(uname -m)" = "Linux x86_64" ] \
  || err="ERROR: your system is not Linux x86_64."; \
[ -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. Firecracker is not well tested under nested virtualization."; \
[ -z "$err" ] && echo "Your system looks ready for Firecracker!" || echo -e "$err"
$ 上記のスクリプト.sh
ERROR: /dev/kvm is innaccessible.
  • kvmの有効化
$ sudo setfacl -m u:${USER}:rw /dev/kvm
$ 上記のスクリプト.sh
Your system looks ready for Firecracker!

いけてそうですね。

Dockerとgoのインストールは省略します。

firecracker-containerdのセットアップ

カーネルのダウンロード

$ curl -fsSL -o hello-vmlinux.bin https://s3.amazonaws.com/spec.ccfc.min/img/hello/kernel/hello-vmlinux.bin

$ ls
hello-vmlinux.bin

firecrackerのセットアップ

  • firecracker-containerdをクローンしてくるこの時Goのプロジェクトに準拠した場所に配置する
  • セットアップ
$ git clone --recurse-submodules https://github.com/firecracker-microvm/firecracker-containerd

$ GO111MODULE=on make all
  • 以下の3つにPATHを通すかPATHの通ってるところに配置する
    • runtime/containerd-shim-aws-firecracker
    • firecracker-control/cmd/containerd/firecracker-containerd
    • firecracker-control/cmd/containerd/firecracker-ctr
$ sudo make install

上記のコマンドでも可

firecrackerのビルド

$ make firecracker
  • 以下の2つにPATHを通すかPATHの通ってるところに配置する
    • _submodules/firecracker/target/x86_64-unknown-linux-musl/release/firecracker
    • _submodules/firecracker/target/x86_64-unknown-linux-musl/release/jailer
$ sudo make install-firecracker

上記のコマンドでも可

ルートファイルシステムのビルド

このリポジトリにはDebianベースのvm用のルートファイルシステムを構築するためのイメージビルダーコンポーネントが含まれてました。

$ make image
$ sudo mkdir -p /var/lib/firecracker-containerd/runtime
$ sudo cp tools/image-builder/rootfs.img /var/lib/firecracker-containerd/runtime/default-rootfs.img

firecracker-containerdバイナリの設定

disabled_plugins = ["cri"]
root = "/var/lib/firecracker-containerd/containerd"
state = "/run/firecracker-containerd"
[grpc]
  address = "/run/firecracker-containerd/containerd.sock"
[plugins]
  [plugins.devmapper]
    pool_name = "fc-dev-thinpool"
    base_image_size = "10GB"
    root_path = "/var/lib/firecracker-containerd/snapshotter/devmapper"

[debug]
  level = "debug"
$ sudo mkdir -p /etc/firecracker-containerd
$ sudo vim /etc/firecracker-containerd/config.toml
上記の設定を書く

snapshotterの準備と設定

#!/bin/bash

# Sets up a devicemapper thin pool with loop devices in
# /var/lib/firecracker-containerd/snapshotter/devmapper

set -ex

DIR=/var/lib/firecracker-containerd/snapshotter/devmapper
POOL=fc-dev-thinpool

mkdir ${DIR}

if [[ ! -f "${DIR}/data" ]]; then
touch "${DIR}/data"
truncate -s 100G "${DIR}/data"
fi

if [[ ! -f "${DIR}/metadata" ]]; then
touch "${DIR}/metadata"
truncate -s 2G "${DIR}/metadata"
fi

DATADEV="$(losetup --output NAME --noheadings --associated ${DIR}/data)"
if [[ -z "${DATADEV}" ]]; then
DATADEV="$(losetup --find --show ${DIR}/data)"
fi

METADEV="$(losetup --output NAME --noheadings --associated ${DIR}/metadata)"
if [[ -z "${METADEV}" ]]; then
METADEV="$(losetup --find --show ${DIR}/metadata)"
fi

SECTORSIZE=512
DATASIZE="$(blockdev --getsize64 -q ${DATADEV})"
LENGTH_SECTORS=$(bc <<< "${DATASIZE}/${SECTORSIZE}")
DATA_BLOCK_SIZE=128 # see https://www.kernel.org/doc/Documentation/device-mapper/thin-provisioning.txt
LOW_WATER_MARK=32768 # picked arbitrarily
THINP_TABLE="0 ${LENGTH_SECTORS} thin-pool ${METADEV} ${DATADEV} ${DATA_BLOCK_SIZE} ${LOW_WATER_MARK} 1 skip_block_zeroing"
echo "${THINP_TABLE}"

if ! $(dmsetup reload "${POOL}" --table "${THINP_TABLE}"); then
dmsetup create "${POOL}" --table "${THINP_TABLE}"
fi

containerd runtime pluginの設定

# /etc/containerd/firecracker-containerd.json
# サンプル設定
{
  "firecracker_binary_path": "/usr/local/bin/firecracker",
  "kernel_image_path": "/var/lib/firecracker-containerd/runtime/hello-vmlinux.bin",
  "kernel_args": "console=ttyS0 noapic reboot=k panic=1 pci=off nomodules ro systemd.journald.forward_to_console systemd.unit=firecracker.target init=/sbin/overlay-init",
  "root_drive": "/var/lib/firecracker-containerd/runtime/default-rootfs.img",
  "cpu_template": "T2",
  "log_fifo": "fc-logs.fifo",
  "log_level": "Debug",
  "metrics_fifo": "fc-metrics.fifo"
}
  • kernel_image_pathで設定してあるのはダウンロードしてきたカーネルなので該当の場所に配置する

コンテナを立ち上げていく

default shim 用のディレクトリを作成

$ mkdir -p /var/lib/firecracker-containerd

containerdを起動

$ sudo PATH=$PATH /usr/local/bin/firecracker-containerd \
  --config /etc/firecracker-containerd/config.toml

コンソールを一つ占有します

f:id:kurouw:20191216040608p:plain

imageをpullしてきます

$ sudo firecracker-ctr --address /run/firecracker-containerd/containerd.sock images \
  pull --snapshotter devmapper \
  docker.io/library/busybox:latest

f:id:kurouw:20191216040711p:plain

Dockerより可愛いですね。

実際にコンテナを起動

$ sudo firecracker-ctr --address /run/firecracker-containerd/containerd.sock \
  run \
  --snapshotter devmapper \
  --runtime aws.firecracker \
  --rm --tty --net-host \
  docker.io/library/busybox:latest busybox-test

f:id:kurouw:20191216040819p:plain

/ # cat /proc/cpuinfo
processor   : 0
vendor_id   : GenuineIntel
cpu family  : 6
model       : 63
model name  : Intel(R) Xeon(R) Processor @ 2.30GHz
stepping    : 2
microcode   : 0x1
cpu MHz     : 2300.006
cache size  : 46080 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 syscall nx rdtscp lm constant_tsc rep_good nopl nonstop_tsc cpuid pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm cpuid_fault invpcid_single pti ssbd ibrs ibpb stibp fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid smap xsaveopt arat arch_capabilities
bugs        : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass
bogomips    : 4600.01
clflush size    : 64
cache_alignment : 64
address sizes   : 46 bits physical, 48 bits virtual
power management:

性能は上記の通り

コンテナ一覧

$ firecracker-ctr --address /run/firecracker-containerd/containerd.sock containers list

CONTAINER       IMAGE                               RUNTIME
busybox-test    docker.io/library/busybox:latest    aws.firecracker

コンテナ削除

$ firecracker-ctr --address /run/firecracker-containerd/containerd.sock containers delete busybox-test

一通りの操作はできました。

ここまでかかった時間は1時間30分でした。課金もランチ1回分で抑えられて良かったです。それぐらいGetting Startはわかりやすかったです。

終わりに

触りはなんとなくわかってよかったです。Fargateに一歩近くこともできたかもしれません(?) 次はスケールアウト・イン機構をFirecrackerで作ってみたいです。

ここ最近で仮想化とかに興味が湧いてきたのでそのためにももっと基礎知識みたいなのは欲しいなと思いました。

why君に弟子入りでもしてみようかな。。。

明日はjoniy_joniyさんの尿酸値と痛風、私とwhywaita氏です。