毎日、[AWS Lambda は数兆回の関数呼び出しを実行し、AWS Fargate は数百万のコンテナをスケジュールしています。その一つひとつが完全な仮想マシンであり、独自のカーネルを持ち、1秒未満で起動します。
どうやって? 約5万行の Rust で書かれた Firecracker がその答えです。Firecracker は、業界がついに「リソースを制御する Linux コンテナは、セキュリティ境界として設計されたものではない」と認めたから生まれました。
分離の問題
あなたのラップトップ上のすべての Docker コンテナは、3 つの Linux カーネル機能を組み合わせたものです:
- 名前空間 は目隠しです。内部のプロセスは、システムのプライベートなビュー(独自の PID リスト、ネットワークスタック、マウントテーブル、ホスト名、ユーザー ID)を持ちます。コンテナ内の PID 1 は、ホスト上のランダムな PID であり、コンテコンテナは他のプロセスを見ることさえできません。
- cgroups は予算です。制御グループは、カーネルのアカウンティングとレート制限の層です。プロセスツリーが消費できる CPU、メモリ、ディスク IO、ネットワーク帯域幅を制限します。
- seccomp + ケーパビリティ は許可リストです。ケーパビリティは root の権限を約 40 の個別の特権(低いポートのバインド、カーネルモジュールのロード、ファイルシステムのマウントなど)に分割するため、必要なものだけを付与できます。seccomp は、プロセスが実行を許可されるシステムコール(ユーザースペースからカーネルへの唯一の API)を決定するプロセスごとにフィルタリングします。
Docker がインストールされていなくても、自分で確認できます:
1unshare --mount --pid --net --fork /bin/bash
Docker が行うその他のこと(イメージレイヤー、レジストリ、DNS)は、その上でのオーケストレーションです。
これらすべての保護は、約3000万行のコードからなる単一の Linux カーネルを通過し、400 以上のシステムコールを公開しています。ホスト上のすべてのコンテナは、その同じカーネルを呼び出します。これらのシステムコールのいずれかに 1 つバグがあると、そのマシン上のすべてのテナントにとってゲームオーバーです。
完全な仮想マシンは、強引な方法で分離を解決します:各 VM は独自のカーネルを持ちます。
最新の CPU には「ゲストモード」があり、実際のシリコン上でゲスト命令を実行します。ゲストが特権的な操作(実際のハードウェアに触れる、フォルトが発生する、割り込みを受ける)を行った場合のみ、ホストが介入します。ハイパーバイザーは、その瞬間を調停する薄い層です。
Linux は、/dev/kvm で公開される KVM というカーネルモジュールとしてハイパーバイザーを提供します。これはハードウェア仮想化拡張機能(Intel の vmx、AMD の svm)を利用します:
1ls -l /dev/kvm
完全な VM の問題は、遅くて大きいことです。従来の QEMU VM は、架空の PC(BIOS、PCI バス、IDE コントローラ、VGA カード、PS/2 キーボード)全体をエミュレートします。これは、1998 年の OS が起動することを前提としていたからです。イメージは数百メガバイトで、起動に数秒かかります。ワークロードが始まる前から、メモリフットプリントは数百 MiB です。40ms しか生きない Web リクエストの場合、マシンの起動にその 40 倍の時間がかかることになります。
つまり、あなたは次のジレンマに直面しています:
- コンテナ:50ms 起動、5 MiB オーバーヘッド、共有カーネルによる攻撃面。
- VM:5 秒以上の起動、300+ MiB オーバーヘッド、ハードウェアによる分離。
信頼できないマルチテナントコードを実行するすべての人(AWS や、既存のほぼすべての AI サンドボックスベンダー)は、このトレードオフの両方を同時に必要としています。
マイクロ VM の登場
VMM(仮想マシンモニター)は、ハイパーバイザーを駆動するユーザースペースプロセスです。ゲストメモリを設定し、仮想デバイスをプラグインし、KVM にゲストコードの実行を指示します。
マイクロ VM は、1998 年の PC を削除した VMM です:BIOS なし、PCI バスなし、VGA なし、USB なし、ACPI なし、ACPI なし(実際のデスクトップが起動時に通過するレガシーハードウェアはなく、40ms の関数呼び出しには無関係です)。残るのは:KVM、シリアルコンソール、そしていくつかの virtio デバイス(ネット、ブロック、vsock)です。
virtio は、「自分が VM 内で実行されていることを認識している」ための標準的なデバイスインターフェースです。ゲストは、実際の Intel e1000 カードや IDE コントローラを駆動かしているふりをする代わりに、軽量な仮想 NIC とディスク(virtio-net、virtio-block)を介してハイパーバイザーと協調します。この協調と、上記の欠落したレガシーハードウェアのすべてが、マイクロ VM が高速に起動する最大の理由です。
結果は次の通りです:
- VMM 起動からゲストユーザースペースで init が実行されるまで約 125ms。
- VM あたり 5 MiB 未満の VMM メモリオーバーヘッド(ゲストワークロードが自身のために何も確保する前に、ホストが VM ごとに支払うブックキーピングメモリ)。
- 単一ホストで毎秒 150 VM/秒の作成レート。
- ベアメタルと比較して約 2~8% のランタイムパフォーマンス低下。
完全な VM と同じハードウェアレベルの分離を、コンテナと同程度の密度で実現します。

Firecracker は VMM であり、実際に /dev/kvm と通信してマイクロ VM を起動するプロセスです。この投稿の残りの部分では、そのスタックをエンドツーエンドで説明します。
Firecracker
2018 年 11 月、AWS は re:Invent で Firecracker をオープンソース化しました。それはすでに Lambda を本番環境で動かしており、あなたの import pandas のコールドスタートをミリ秒単位で課金できるほど高速に十分な速さにしているものです。2020 年、チームは NSDI '20 でアーキテクチャを発表しました。
アーキテクチャ
Google の crosvm からフォークされ、Rust で書き直され、コードの半分以上が削除されました。各 Firecracker プロセスは 1 つのマイクロ VM であり、正確に 3 つのスレッドタイプがあります:
- API スレッド は注文受付窓口です。Unix ソケットにバインドされた REST サーバー。起動前の設定と、起動後の限られたアクションを受け付けます。
- VMM スレッド はハードウェアの工場フロアです。ゲストが見ることのできるすべてのデバイスのふりをします。ゲストが NIC レジスタだと思って何かを書き込むと、CPU はゲストを一時停止し、VMM がその書き込みを処理し、再開します。メカニズム:ゲストがマジックアドレスを読み書きし、CPU がそれらをホストにトラップします。
- vCPU スレッド はランナーです。ゲスト CPU あたり 1 つで、それぞれがタイトなループ内にあります:何か面白いこと(デバイスへの書き込み、割り込み、停止)が起こるまで KVM にゲストを実行させ、それを処理し、ループします。
これらは Rust チャネル(プロセス内のロックフリーなメッセージキュー)を介して通信します。ゲストは正確に 4 つのデバイスを見ます。

4 つのデバイス
- virtio-net は VM の NIC であり、1998 年のエミュレーションはありません。ゲストはパケットを virtqueue(共有メモリ内のリングバッファッファ)に書き込み、VMM は io_uring または epoll によって駆動されるホスト側の TAP デバイス(カーネルがファイルとして公開する仮想イーサネットインターフェース)を介してそれらを排出するため、VMM スレッドはブロックしません。
- virtio-block は VM のディスクであり、ホスト上の単なるファイル IO です。ゲストはセクタ要求を virtqueue に入れ、VMM はホストファイルに対してプレーンな pread/pwrite を発行します。IDE も AHCI も SCSI もありません。
- virtio-vsock は VM からホストへのインターホンです。IP/ポートペアの代わりに(コンテキスト ID、ポート)タプルでアドレス指定されるため、ゲストエージェントはゲスト IP なしで、またネットワーク上にスプーフィング可能なものなしで、ホーム(ログ、ヘルスピング、スナップショットメタデータ)に電話できます。
- 8250 シリアル UART はブートコンソールです。固定アドレスでエミュレートされた小さなレガシーシリアルチップ。virtio が起動する前の初期ブート前のログとクラッシュダンプに使用されます。安価で普遍的で、決してなくなりません。
マイクロ VM の起動、エンドツーエンド
API は制御プレーン全体です:設定チャネルであり、データプレーン(実際にゲストコードを実行する vCPU スレッド)から)意図的に分離されています。Unix ソケットを指すバイナリを起動します:
1firecracker --api-sock /tmp/firecracker.sock
次に、設定を PUT します:
1curl --unix-socket /tmp/firecracker.sock -i \2 -X PUT 'http://localhost/boot-source \3 -H "Content-Type: application/json" \4 -d '{5 "kernel_image_path": "./vmlinux.bin",6 "boot_args": "console=ttyS0 reboot=k panic=1 pci=off"7 }'
4 回の HTTP 呼び出しです。それが制御プレーン全体です。

セキュリティオニオン
単一の KVM 境界だけでも強力です。Firecracker はその周りにさらに 2 つの層を巻き付けます。
jailer はサンドボックスビルダーです。その唯一の仕事は、VMM が実行される前にそれを箱詰めすることだけです。chroot(プロセスを単一のディレクトリサブツリーにロックし、あたかディレクトリがファイルシステムのルートであるかのように見せる Linux 機能)を作成し、新しい PID 名前空間にドロップしてホストの他のプロセスを見えなくし、特権のない uid/gid に切り替え、cgroup の CPU/メモリ制限を適用し、その後初めてその刑務所内で Firecracker バイナリを実行します:
1firecracker-jailer --id 42 --chroot-base-dir \2 --uid 1000 --gid 1000 \3 --exec ./firecracker -- --api-sock /tmp/firecracker.sock
これで VMM プロセス自体は、専用の chroot 以外のファイルシステムを持たず、ホスト上の他のプロセスを見ることができず、root ケーパビリティも持ちません。もしゲストからホストへの脱出が virtio または KVM を介して成功したとしても、攻撃者は cgroup 制限のあるその chroot 内に閉じ込められます。
Seccomp はスレッドごとのシステムコール許可リストです。リストにないものは、カーネルのシステムコールハンドラに到達する前に強制終了されるか、EPERM を返します。Firecracker は 3 つのレベルを提供します:
- レベル 0: オフ。本番では使用しないでください。
- レベル 1: システムコール番号による許可リスト。
- レベル 2: 引数値も制約します(例:ioctl は許可するが、コマンドが KVM_RUN の場合のみ)。デフォルトかつ推奨。
各スレッドは可能な限り最小の表面積を取得します:API スレッドは ioctl(KVM_RUN) を必要とせず、vCPU スレッドは socket() を必要としません。1 1 つのルールがどのように見えるかを簡略化したものです:
1SeccompRule::new(vec![2 Allow(syscall!(write)),3 Allow(syscall!(read)),4 Allow(syscall!(ioctl)).and(ArgCond(1, Eq(0, KVM_RUN)),5])
攻撃者がホストに到達するためには、各層が独立して失敗する必要があります。
スナップショット:Lambda SnapStart の裏技
実行中のマイクロ VM のスナップショットを取ります。ミリ秒単位で、別のホスト上に、真新しい VMM プロセスとして復元します。カーネルブートをスキップし、init をスキップし、JIT ウォームアップをスキップします。
実行中の VM をフリーズし、メモリとデバイス状態をディスクにダンプします:
1curl --unix-socket /tmp/firecracker.sock -i \2 -X PATCH http://localhost/vm \3 -H "Content-Type: application/json" \4 -d '{5 "state": "Paused"6 }'
スナップショットはウォームアップ後の状態をキャプチャするため、復元された VM は最初ではなく、人生の途中で目覚めます。
これはまさに AWS Lambda SnapStart が行っていることです:Java Lambda を一度初期化し、マイクロ VM をスナップショットし、その後のすべてのコールドスタートでそのスナップショットを復元します。JVM のコールドスタートが突然 8 秒以上から 1 秒未満になります。

それらがどのように組み合わさるか
gVisor は異なる設計です:Go で書かれたユーザースペースカーネルであり、通常のプロセスとして実行される Linux システムコールインターフェースの再実装です。ゲストのシステムコールはホストカーネルの代わりに代わり gVisor にヒットし、gVisor が何をダウンストリームに転送するかを決定します。マイクロ VM よりも起動が速く、ホットパスで 10~30% のシステムコールオーバーヘッドがあり、異なる信頼境界を持ちます。
Firecracker は「独自のカーネルを持つが、PCI BIOS はない」という箱に位置します:ハードウェア分離、小さなデバイスモデル、ミリ秒単位の起動。
ツールを選んでください:
特性 | コンテナ | マイクロ VM | gVisor |
|---|---|---|---|
分離境界 | 共有カーネル | ハードウェア | ユーザースペースカーネル |
起動時間 | 50ms | 125ms | 100ms |
メモリオーバーヘッド | 5 MiB | 5 MiB + ゲストカーネル | 10-15 MiB |
互換性 | 完全な Linux | 完全な Linux | ほとんどの Linux |
密度 | 高い | 高い | 高い |
誰がこれを使っているか
マイクロ VM の上に構築されていないサーバーレスプラットフォームをリストアップする方がほぼ早いでしょう。
本番環境の Firecracker:
- AWS Lambda と AWS Fargate:元のユースケース。すべての Lambda の呼び出しは Firecracker マイクロ VM に着地し、Fargate タスクは内部に薄いコンテナランタイムを持つ Firecracker VM です。
- Fly.io Machines:すべての fly machine の実行は Firecracker マイクロ VM であり、グローバルに分散され、サブ秒のコールドスタートと永続ディスクを備えています。
- 過去 18 ヶ月間にあなたが使ったほとんどすべての AI エージェントコード実行サンドボックス は、Firecracker マイクロ VM 内に存在します。
この時点で、サンドボックス API の形状はベンダー間でほぼ同じです:
1sandbox = Sandbox()2sandbox.exec("pip install requests")3result = sandbox.exec("python my_script.py")
約 4 行のコードで:Firecracker マイクロ VM が起動し、カーネルが初期化し、ゲスト内のエージェントプロセスが vsock を介してあなたのコマンドを受け取り、実行し、結果をストリーミングで返し、VM は終了します。
エージェント時代:なぜこれが今重要なのか
1 年前、「AI サンドボックスとは何か?」はニッチな質問でした。もし LLM がコードを生成した場合、それはおそらくどんなマシンでも ンでも %安全ではない可能性が高く、そのため一時的なサンドボックスで実行することになります。
今日、すべての本格的な AI 製品はエージェントを出荷しています。サンドボックスも改善されましたが、エージェントの形状は変わり、古いランタイムの答えは新しい形状に適合しません。
プロセス内エージェント vs ホストレベルエージェント
ラウンド 1 の AI エージェントは、あなたのアプリケーション内部に存在しました。ライブラリをインポートし、ループを配線し、既存のバックエンドで実行しました:
1from agents import Agent, run_agent23result = run_agent(4 model="gpt-4",5 tools=[search, calculator],6 prompt="What's 2+2?"7)
すべての呼び出しはモデルへの HTTP ラウンドトリップでした。すべてのツール呼び出しはあなた自身のプロセス内の関数でした。「サンドボックス」はあなた自身のサーバーでした。これが Vercel AI SDK、LangChain、OpenAI Agents SDK の世界です。これはうまく機能し、今日でも本番エージェントの大部分を出荷しています。
ラウンド 2 は異なります。Claude Code、Codex、OpenCode はホストレベルエージェントです:あなたの内部に存在するのではなく、マシンを乗っ取るバイナリです。これらは本物のシェル、パッケージマネージャ、書き込み可能なディスクを期待します。Claude Code にタスクを与えると、次のようなものを実行します:
1# Claude Code が生成した内部コマンド2find . -type: f -name "*.py" | xargs grep "TODO"3sed -i 's/old_api/new_api/g' src/**/*.py4npm test
それはシェル/bash です。本物のファイルシステム、本物の fork/exec、パッケージマネージャ、書き込み可能なディスク、到達可能なネットワークが必要です。それらのどれもチャット補完ツールスキーマとして表現できず、またそれらのどれも他のテナントと共有カーネカーネルコンテナ内で実行しても安全ではありません。
ラボは、これらのハーネル自体の周りの足場であるこれらのハーネス(シェル、ファイルエディタ、テストランナー、エージェントループ自体)で直接モデルをポストトレーニングしています。つまり、「モデル + それがトレーニングされたハーネス」と「モデル + 自作の足場」のギャップは四半期ごとに拡大しています。
エージェントあたり 1 台の完全な Linux マシンで、エージェントが発明したばかりの信頼コードを実行することは、まさに Firecracker が構築されたワークロードです。上記の収束は偶然ではありません。
エージェントを取り巻くコンピュートとハーネスの分離に関する実験が増え始めています。Anthropic の Managed Agents はその一例であり、エージェントハーネスがサンドボックスの隣で、内部ではなく実行されています。
一部の企業は、エージェントにより良い検索とストレージを提供するために、完全なホスト型ファイルシステム(Archil や Mesa など)を構築しています。
エージェントが向上し、時間とともに変化するにつれて、Firecracker 上に構築された、さらに多くの興味深いインフラ提供が行われるでしょう。
あなたが実際にエージェントインフラプラットフォームに支払っているもの
汎用的な「任意のコードを実行する」サンドボックスは、今やコモディティです。インフラは完全にオープンソースです。マイクロ VM 層は Firecracker または Cloud Hypervisor であり、Apache 2.0 で利用可能です。コンテナから rootfs への変換は 200 行の Go スクリプトです。有能なエンジニアは週末で動作するサンドボックスプラットフォームを立ち上げることができます。
あなたが支払うのは、VM に接続されているものです。ベアなマイクロ VM は参加条件にすぎません。
興味深いプロダクトサーフェス:
- 可観測性 は製品であり、デバッグ補助ではありません。エージェントが行うすべてのこと(stdout、システムコール、ファイル書き込み、ネットワークリクエスト)は、単一のソケットを通じてホスト側のコレクターに流れます。エージェントビルダーは、完全なセッションリプレイと、最良の製品を作成するためのアクションごとのアーティファクトを必要とします。
- シークレット はワイヤーレベルで仲介され、ゲストには決して渡されません。ゲストはプレースホルダー環境変数の環境変数のみを見ます;サンドボックス内で echo $SECRET を実行すると、プレースホルダーが返されます。ホスト側のエグレスプロキシ(すべての送信パケットが通過する必要があります)は、明示的な許可リストとセッションごとの監査証跡に基づいて、ホスト側の TAP(ゲストが見ることもアドレス指定することもできない、VM の仮想 NIC のカーネル所有の端)で実際の認証情報を置き換えます。エージェントは 5 秒前に生成した任意のコードを実行していても、決して持っていなかった認証情報を外部に持ち出すことはできません。
- アイデンティティ はエージェント内部ではなく、ホストで署名されます。送信リクエストは、パケットがブリッジを離れる前にホストによって作成された、暗号化されたセッションごとのアイデンティティ(HTTP メッセージ署名 + Ed25519 に基づく Web Bot Auth 署名を含む)を運ぶことができます。署名鍵はマイクロ VM に入ることはありません。
- その他のコンピュート はランタイムと同じマイクロ VM にバンドルされています。Browserbase は各エージェントランタイムを、同じホスト上、多くの場合同じマイクロ VM 内のブラウザと 1:1 でペアリングします。エージェージェントプロセスと Chromium 間の物理的な距離は実質的にゼロです:CDP コマンドは、サービスのネットワークを越えるのではなく、Unix ソケットを介して送信されるため、アクションのレイテンシは一桁のミリ秒です。スクリーンキャストフレームは、セッションリプレイに着地するために公開インターネットを越える必要はありません。
そして、これらすべてを Docker の上にきれいに縫い合わせることはできません。継ぎ目がありません。私たちの賭けは、エージェントランタイム市場は、生のコンピュートではなく、最高の可観測性、シークレット、アイデンティティ、パートナーシップ、そしてコロケーションされたコンピュートを1 つの製品サーフェスに凝縮したものによって勝ち取られるというものです。

注目すべきランタイムの代替案
- Bubblewrap:特権限のないユーザー名前空間サンドボックス化。非 root ユーザーは sudo なしでサンドボックスを起動でき、Flatpak がデスクトップアプリを制限するために使用するのと同じカーネルプリミティブを使用します。VM より軽量ですが、ホストカーネルを共有するため、真に信頼できないコードに対するマイクロ VM の代わりにはなりません。しかし、マイクロ VM 内で実行する優れたネストされた分離層、または自分のホスト上で信頼できるコードには適した選択肢です。
- V8 アイソレート:Cloudflare Workers のモデル。各アイソレートは独自のヒープを持つ個別の JS 実行コンテキストであり、すべてが単一の V8 プロセスを数千の他のテナントと共有します。起動は約 5ms で、マイクロ VM よりも 2 桁高速です。信頼境界は V8 自身のサンドボックスです;歴史的にうまく機能してきましたが、ハイパーバイザーよりもはるかに薄い線です。もう 1 つの問題:Node 風のセマンティクスのみを取得します。fork も exec もネイティブモジュールもなく、ファイルシステムはシミュレートされます。純粋な JS エージェントコードには壊滅的ですが、pip install numpy が必要な場合には役に立ちません。
- gVisor:Google の Go によるユーザースペースカーネル。ネストされた仮想化された仮想化(ほとんどのクラウドプロバイダーがデフォルトで無効にする、別の VM 内で実行されるゲスト VM)なしで強力な分離を実現します;gVisor はそれを必要としないため、GKE でそのまま動作します。システムコールが多いワークロードで約 10~30% のオーバーヘッドが発生します。ハードウェア仮想化が利用できない場合の堅実な中間点です。
- WASM サンドボックス(wasmtime、wasmer):決定論的で、小さく、高速ですが、エコシステムは浅いです。WASI(WASM の標準システムコール API)は成熟しつつあります。まだ「この任意の Python/Node バイナリを実行する」ためのドロップインターゲットではありません。

信頼できない汎用コードのために構築する場合:Firecracker(または Cloud Hypervisor、同様の VMM/virtio 設計)。既知られている JS ワークロードのために構築する場合:V8 アイソレート。その他はすべて、特殊な質問に対する特殊な答えです。
より大きな全体像
Firecracker は、コンピューティングにおける最も古いアイデアの 1 つである仮想マシンを採用し、それを安価にするために十分に削除しました。ハードウェアによる分離は、十分に高速にできるなら価値があるという賭けです。
その賭けは、サーバーレスにとって常に報われるものでした。変わったのは、「信頼できないマルチテナントコード」ワークロードが「サンドボックス化したくない Web 関数」から「本番環境に触れる可能性のある任意のコマンドを生成するエージェント」に成長したことです。境界は移動し、共有カーネルからの脱出に対する許容度は「許容可能なリスク」から「出荷不可能」に変わりました。
そして、それは実現しました。それは /dev/kvm と通信する、5 万行の Rust バイナリです。
コンテナはソフトウェアをパッケージ化します。マイクロ VM はそれを分離します。次の 10 年の興味深いエンジニアリングは、ボックスの周りにラップするすべてのものです。
→ Kyle
このブログ投稿にはインタラクティブなコンポーネントとアニメーションが含まれています(X の記事には表示されません。そのバージョンをご覧になりたい場合は、こちら:https://www.browserbase.com/blog/what-is-firecracker。





