Firecracker で任意のコマンドを実行できる API を実装してみた

Firecracker は AWS Lambda や AWS Fargate でも使われている OSS の仮想化技術です。

先日 Twitter にこの Firecracker を使って、AI エージェントの動作基盤を開発しているスライドが流れてきました。

これを見て大学生の頃に任意コマンドを実行できる Slack Bot を作って、大学のサークルの Slack に放流していたことを思い出しました。

speakerdeck.com

きっと同じものをまた作れるのでは?と思い、実装してみました。

github.com

PoC というか hobby use 用のコードです。

動作

例えば以下のような Python コードを用意して

print("Hello World! from Python")


def fib(n):
    if n < 2:
        return n
    return fib(n - 1) + fib(n - 2)


print(fib(10))

curlAPI を叩くと実行結果が返ってきます。

$ curl -X POST http://localhost:3000/run -H 'Content-Type: multipart/form-data' -F file=@./examples/example.py -F 'payload={"environmentName": "python"};type=application/json'
{"stdout":"Hello World! from Python\n55\n","stderr":""}

仕組み

KVM + Firecracker で立てた microVM の中で任意のコマンドを実行してその結果を返しています。

  1. API サーバ: ユーザーのコードを受け付ける
  2. API サーバ: python -c 形式のコマンドに変換
  3. API サーバ: Firecracker の管理を行うプロセスに microVM の起動を依頼
  4. Firecracker Manager: microVM を起動して、VM 内と通信ができる UNIX ドメインソケットを返す
  5. API サーバ: VM 内のプロセスに対してコマンドを送信
  6. VM 内のプロセス: コマンドを実行して結果を返す

という流れになっています。

今回はただ動くものを実装するのが目的だったので、全部を Node.js で実装してます。多分ちゃんと運用するなら VM 内のプロセスは、シングルバイナリにできる Go とかで書いたほうがいい気がします。

Tips

実装する中で気づいた知見について紹介します。

.ext4 ファイルは Docker イメージから生成できる

microVM のディスクファイルとして、.ext4 ファイルを用意する必要があります。

docker export を使うとコンテナのファイルシステムを書き出すことができるので、これを使うのが楽でした。各言語のセットアップなどは有名な Docker イメージを利用できるのが便利です。

github.com

ゲストのプロセスとの通信は vsock 経由で行う

vsock は VM とホストマシンが通信するためのアドレスファミリーです。Firecracker 独自の仕組みではなくて、VM 全般で利用される仕組みのようです。

ただ自分はこのことを知らなかったので、以下のドキュメントで初めて知りました。

github.com

ホスト側はソケットが生えるだけなので、便利な仕組みだなと思いました。

microVM 内でループバックアドレスを up する必要がある

Node.js は vsock をネイティブにサポートしていません。

なので今回は socat を使って、vsock を TCP に proxy することにしました。

具体的には microVM の起動時に以下のコマンドも実行しています。

$ socat VSOCK-LISTEN:8000,fork TCP:127.0.0.1:8080

こうすれば 8080 ポートで HTTP サーバを立てるだけで済むので実装の難易度が下がります。

ただ初期状態の microVM ではループバックアドレスが down していたので、以下のエラーが発生しました。

# 2025/11/25 15:34:53 socat[248] W connect(5, AF=2 127.0.0.1:8080, 16): Network is unreachable
2025/11/25 15:34:53 socat[248] E TCP:127.0.0.1:8080: Network is unreachable

これを解決するために、起動時に ip link set lo up も実行してます。

余談

実装にあたって仮想化や Linux 周りの知識が不足していたのを ChatGPT にかなり助けてもらいました。昔だったらもっと時間がかかっていた気がします。

これを本番環境で稼働させるための調査や追加の実装はさらに時間が必要になると考えてます。

さっと動くものは簡単に作れるけど、ちゃんと動くものまでの距離は依然遠いままだな〜と感じました。