おさらいで以下のネットワーク構成をマイクロVMと実マシンで実現している。

これをVM側で認識するためにTAPをネットワークとして認識させ、カーネルパラメータにIPアドレスを渡してあげる必要がある。
そのスクリプトを以下に記載します。
#!/bin/bash
SOCK=/run/firecracker.socket
KERNEL="${PWD}/hello-vmlinux.bin"
ROOTFS="${PWD}/rootfs.ext4"
sudo curl --unix-socket "$SOCK" -i \
-X PUT http://localhost/machine-config \
-H "Content-Type: application/json" \
-d '{
"vcpu_count": 1,
"mem_size_mib": 512,
"smt": false
}'
sudo curl --unix-socket "$SOCK" -i \
-X PUT http://localhost/network-interfaces/eth0 \
-H "Content-Type: application/json" \
-d "{
\"iface_id\": \"eth0\",
\"guest_mac\": \"AA:FC:00:00:00:01\",
\"host_dev_name\": \"tap0\"
}"
sudo curl --unix-socket "$SOCK" -i \
-X PUT http://localhost/boot-source \
-H "Content-Type: application/json" \
-d "{
\"kernel_image_path\": \"${KERNEL}\",
\"boot_args\": \"console=ttyS0 quiet reboot=k panic=1 pci=off root=/dev/vda rw init=/bin/busybox setsid -c /bin/sh ip=172.16.0.2::172.16.0.1:255.255.255.0::eth0:off\"
}"
sudo curl --unix-socket "$SOCK" -i \
-X PUT http://localhost/drives/rootfs \
-H "Content-Type: application/json" \
-d "{
\"drive_id\": \"rootfs\",
\"path_on_host\": \"${ROOTFS}\",
\"is_root_device\": true,
\"is_read_only\": false
}"
sudo curl --unix-socket "$SOCK" -i \
-X PUT http://localhost/actions \
-H "Content-Type: application/json" \
-d '{ "action_type": "InstanceStart" }'
今回使用しているrootfs.ext4はPingなどのネットワーク系のコマンドが入っているrootfsを使用している。
というわけで、外部にPingを通すことが出来た。
hal@hal-VirtualBox:~$ sudo firecracker.sh
[sudo] hal のパスワード:
2026-03-21T14:46:33.406631614 [anonymous-instance:main] Running Firecracker v1.14.3
2026-03-21T14:46:33.407293540 [anonymous-instance:main] Listening on API socket ("/run/firecracker.socket").
2026-03-21T14:46:33.408952104 [anonymous-instance:fc_api] API server started.
2026-03-21T14:46:47.129826622 [anonymous-instance:fc_api] The API server received a Put request on "/machine-config" with body "{\n \"vcpu_count\": 1,\n \"mem_size_mib\": 512,\n \"smt\": false\n }".
2026-03-21T14:46:47.129947108 [anonymous-instance:fc_api] The request was executed successfully. Status code: 204 No Content.
2026-03-21T14:46:47.156219128 [anonymous-instance:fc_api] The API server received a Put request on "/network-interfaces/eth0" with body "{\n \"iface_id\": \"eth0\",\n \"guest_mac\": \"AA:FC:00:00:00:01\",\n \"host_dev_name\": \"tap0\"\n }".
2026-03-21T14:46:47.156907083 [anonymous-instance:fc_api] The request was executed successfully. Status code: 204 No Content.
2026-03-21T14:46:47.182578852 [anonymous-instance:fc_api] The API server received a Put request on "/boot-source" with body "{\n \"kernel_image_path\": \"/home/hal/code/fc/blog/hello-vmlinux.bin\",\n \"boot_args\": \"console=ttyS0 quiet reboot=k panic=1 pci=off root=/dev/vda rw init=/bin/busybox setsid -c /bin/sh ip=172.16.0.2::172.16.0.1:255.255.255.0::eth0:off\"\n }".
2026-03-21T14:46:47.182795946 [anonymous-instance:fc_api] The request was executed successfully. Status code: 204 No Content.
2026-03-21T14:46:47.209168581 [anonymous-instance:fc_api] The API server received a Put request on "/drives/rootfs" with body "{\n \"drive_id\": \"rootfs\",\n \"path_on_host\": \"/home/hal/code/fc/blog/rootfs.ext4\",\n \"is_root_device\": true,\n \"is_read_only\": false\n }".
2026-03-21T14:46:47.209418262 [anonymous-instance:fc_api] The request was executed successfully. Status code: 204 No Content.
2026-03-21T14:46:47.234915393 [anonymous-instance:fc_api] The API server received a Put request on "/actions" with body "{ \"action_type\": \"InstanceStart\" }".
2026-03-21T14:46:47.251109804 [anonymous-instance:main] Artificially kick devices
2026-03-21T14:46:47.251292080 [anonymous-instance:fc_vcpu 0] Received a VcpuEvent::Resume message with immediate_exit enabled. immediate_exit was disabled before proceeding
2026-03-21T14:46:47.251401936 [anonymous-instance:fc_api] The request was executed successfully. Status code: 204 No Content.
[ 0.604045] dmi: Firmware registration failed.
2026-03-21T14:46:50.508177094 [anonymous-instance:fc_vcpu 0] Failed to trigger i8042 kbd interrupt (disabled by guest OS)
2026-03-21T14:46:50.533449547 [anonymous-instance:fc_vcpu 0] Failed to trigger i8042 kbd interrupt (disabled by guest OS)
~ # ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=114 time=32.365 ms
64 bytes from 8.8.8.8: seq=1 ttl=114 time=30.102 msVMへのPingも通すことが出来た。
(base) ~ $ ping 192.168.10.251
PING 192.168.10.251 (192.168.10.251): 56 data bytes
64 bytes from 192.168.10.251: icmp_seq=0 ttl=63 time=109.274 ms
64 bytes from 192.168.10.251: icmp_seq=1 ttl=63 time=10.225 ms
64 bytes from 192.168.10.251: icmp_seq=2 ttl=63 time=9.911 ms
64 bytes from 192.168.10.251: icmp_seq=3 ttl=63 time=11.581 msホストの物理NICに付与したパブリックIPを、1:1 NATでマイクロVMのプライベートIPへマッピングしました。これにより、ローカル環境でありながら、AWSのElastic IP(EIP)を介してEC2にアクセスするのと同等の『仮想パブリックIP環境』を再現しています。
1. 呪文の解読:boot_args の ip パラメータ
Firecrackerを起動する際、カーネルに渡す引数(boot_args)に以下のような記述があります。
ip=172.16.0.2::172.16.0.1:255.255.255.0::eth0:off
一見すると複雑ですが、実は以下のルールで構成されています。
| 項目 | 値 | 意味 |
| client-ip | 172.16.0.2 | マイクロVM(ゲスト)自身のIPアドレス |
| server-ip | (空) | 通常は空でOK(NFS起動時などに使用) |
| gateway-ip | 172.16.0.1 | ホスト側のTAPデバイスのIP(出口) |
| netmask | 255.255.255.0 | サブネットマスク |
| hostname | (空) | ゲストのホスト名 |
| device | eth0 | ゲストOS内でのネットワークインターフェース名 |
| autoconf | off | DHCPなどを使わず、静的に設定することを指定 |
これを理解していれば、複数のVMを立ち上げる際に「次は 172.16.0.3 にしよう」と迷わず変更できますね。
2. なぜMACアドレスを「固定」するのか
スクリプト内で AA:FC:00:00:00:01 というMACアドレスを明示的に指定しています。
JSON
"guest_mac": "AA:FC:00:00:00:01"
「適当な値でいいのでは?」と思うかもしれませんが、VMを量産するならここが生命線です。
もしMACアドレスを重複させたまま複数のVMを同じネットワーク(ブリッジなど)に繋ぐと、ホスト側のARPテーブルが「このMACアドレス、さっき別のポートにいたぞ?」と混乱し、通信がブツブツ切れる「ネットワークのカオス」が発生します。
実務でスケールさせるなら、VMのIDに合わせて末尾を書き換える(例:VM1なら 01、VM2なら 02)といった自動化が必須になります。
3. rootfs選びの重要性:なぜ「Busybox」なのか
Firecrackerを最小構成で動かす際、rootfs.ext4 の中身は何でも良いわけではありません。
今回の検証でBusyboxベースのrootfsを採用したのにはPingを使うためという理由があります。
自作のミニマルなrootfsだと、いざ起動しても「pingコマンドが見つかりません」という悲しい結末になりがちです。「ネットワークが繋がらない」のか「コマンドがないだけ」なのかを切り分ける手間を省くためにも、まずは実績のあるBusyboxから入るのが鉄則です。
まとめ
Firecrackerのネットワークは、一見すると「おまじない」が多いですが、一つひとつのパラメータには明確な意図があります。
- IP設定で出口を教え、
- MACアドレスで個性を出し、
- 適切なrootfsで道具を揃える。
この3つが揃って初めて、クラウドの裏側で動いているような「爆速でセキュアなマイクロサービス基盤」への道が開けます。