<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>虚拟化 - DJJ</title><link>https://blog.pdjjq.org/tags/%E8%99%9A%E6%8B%9F%E5%8C%96/</link><description>反抗吧，朋友！</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Fri, 03 Apr 2026 00:17:48 +0800</lastBuildDate><atom:link href="https://blog.pdjjq.org/tags/%E8%99%9A%E6%8B%9F%E5%8C%96/index.xml" rel="self" type="application/rss+xml"/><item><title>E2B &amp; FireCracker by GPT5.4</title><link>https://blog.pdjjq.org/post/e2b-z1sb21m.html</link><pubDate>Fri, 03 Apr 2026 00:17:48 +0800</pubDate><guid>https://blog.pdjjq.org/post/e2b-z1sb21m.html</guid><description>&lt;p>如果你第一次接触 Firecracker，很容易陷入一种混乱：&lt;/p>
&lt;ul>
&lt;li>KVM 是不是虚拟机？&lt;/li>
&lt;li>QEMU 和 KVM 到底是什么关系？&lt;/li>
&lt;li>Firecracker 是不是“替代了” QEMU？&lt;/li>
&lt;li>如果我要自己做一个 mini Firecracker，最小需要做什么？&lt;/li>
&lt;/ul>
&lt;p>我最近就是沿着这个问题一路往下挖，最后发现：&lt;br>
&lt;strong>这几个东西其实不是同一层的概念。&lt;/strong>&lt;/p>
&lt;p>它们的关系，如果一句话概括，就是：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>KVM&lt;/strong>：内核里的硬件虚拟化执行后端&lt;/li>
&lt;li>&lt;strong>QEMU&lt;/strong>：用户态的通用 VMM / 设备模拟器&lt;/li>
&lt;li>&lt;strong>Firecracker&lt;/strong>：用户态的极简 VMM，建立在 KVM 之上&lt;/li>
&lt;/ul>
&lt;p>也就是说：&lt;/p>
&lt;p>&lt;strong>QEMU 和 Firecracker 都可以用 KVM。&lt;/strong>&lt;br>
它们真正的区别，不在“有没有 KVM”，而在于：&lt;strong>谁来做 VMM，以及这个 VMM 做得多大、多复杂。&lt;/strong>&lt;/p>
&lt;p>这篇文章我想把这件事彻底讲清楚。&lt;/p>
&lt;hr>
&lt;h1 id="一问题的起点为什么-firecracker-会存在">一、问题的起点：为什么 Firecracker 会存在？&lt;a class="heading-anchor" href="#%e4%b8%80%e9%97%ae%e9%a2%98%e7%9a%84%e8%b5%b7%e7%82%b9%e4%b8%ba%e4%bb%80%e4%b9%88-firecracker-%e4%bc%9a%e5%ad%98%e5%9c%a8" aria-label="本节链接">#&lt;/a>
&lt;/h1>&lt;p>Firecracker 不是凭空出现的，它解决的是一个非常现实的问题：&lt;/p>
&lt;p>在云计算场景里，比如 AWS Lambda、Fargate、Serverless 平台，一台物理机上往往要同时运行大量来自不同用户的代码。&lt;/p>
&lt;p>这里有一个经典矛盾：&lt;/p>
&lt;h2 id="容器很轻但隔离不够强">容器很轻，但隔离不够强&lt;a class="heading-anchor" href="#%e5%ae%b9%e5%99%a8%e5%be%88%e8%bd%bb%e4%bd%86%e9%9a%94%e7%a6%bb%e4%b8%8d%e5%a4%9f%e5%bc%ba" aria-label="本节链接">#&lt;/a>
&lt;/h2>&lt;p>Docker、containerd 这条路线有明显优势：&lt;/p>
&lt;ul>
&lt;li>启动快&lt;/li>
&lt;li>资源开销小&lt;/li>
&lt;li>编排成熟&lt;/li>
&lt;/ul>
&lt;p>但容器共享宿主内核。&lt;br>
这意味着：&lt;/p>
&lt;p>&lt;strong>容器的隔离边界，本质上不是硬件级别的。&lt;/strong>&lt;/p>
&lt;p>只要内核、namespace、cgroup、runtime 某一层出了问题，就可能导致跨容器突破。&lt;/p>
&lt;hr>
&lt;h2 id="传统虚拟机隔离强但太重">传统虚拟机隔离强，但太重&lt;a class="heading-anchor" href="#%e4%bc%a0%e7%bb%9f%e8%99%9a%e6%8b%9f%e6%9c%ba%e9%9a%94%e7%a6%bb%e5%bc%ba%e4%bd%86%e5%a4%aa%e9%87%8d" aria-label="本节链接">#&lt;/a>
&lt;/h2>&lt;p>另一边是传统 VM：&lt;/p>
&lt;ul>
&lt;li>有自己的内核&lt;/li>
&lt;li>隔离边界更强&lt;/li>
&lt;li>更接近“真正的一台独立机器”&lt;/li>
&lt;/ul>
&lt;p>但问题也很明显：&lt;/p>
&lt;ul>
&lt;li>启动慢&lt;/li>
&lt;li>内存开销大&lt;/li>
&lt;li>设备模型复杂&lt;/li>
&lt;li>历史兼容包袱重&lt;/li>
&lt;/ul>
&lt;p>如果你只是想跑一个很小的函数，或者一个短生命周期任务，传统 VM 往往过重。&lt;/p>
&lt;hr>
&lt;h2 id="firecracker-的目标">Firecracker 的目标&lt;a class="heading-anchor" href="#firecracker-%e7%9a%84%e7%9b%ae%e6%a0%87" aria-label="本节链接">#&lt;/a>
&lt;/h2>&lt;p>Firecracker 的目标可以理解为：&lt;/p>
&lt;p>&lt;strong>用尽量小的开销，换取 VM 级别的隔离。&lt;/strong>&lt;/p>
&lt;p>不是追求“模拟一台完整 PC”，而是追求：&lt;/p>
&lt;ul>
&lt;li>少设备&lt;/li>
&lt;li>少功能&lt;/li>
&lt;li>少攻击面&lt;/li>
&lt;li>快启动&lt;/li>
&lt;li>小内存占用&lt;/li>
&lt;/ul>
&lt;p>所以它本质上是一个：&lt;/p>
&lt;p>&lt;strong>建立在 KVM 之上的极简 microVM VMM。&lt;/strong>&lt;/p>
&lt;hr>
&lt;h1 id="二先把关系讲清楚kvmqemufirecracker-各自是什么">二、先把关系讲清楚：KVM、QEMU、Firecracker 各自是什么？&lt;a class="heading-anchor" href="#%e4%ba%8c%e5%85%88%e6%8a%8a%e5%85%b3%e7%b3%bb%e8%ae%b2%e6%b8%85%e6%a5%9akvmqemufirecracker-%e5%90%84%e8%87%aa%e6%98%af%e4%bb%80%e4%b9%88" aria-label="本节链接">#&lt;/a>
&lt;/h1>&lt;p>这是最容易混的地方。&lt;/p>
&lt;hr>
&lt;h2 id="1-kvm-是什么">1. KVM 是什么？&lt;a class="heading-anchor" href="#1-kvm-%e6%98%af%e4%bb%80%e4%b9%88" aria-label="本节链接">#&lt;/a>
&lt;/h2>&lt;p>KVM，&lt;code>Kernel-based Virtual Machine&lt;/code>，是 Linux 内核里的一套虚拟化能力。&lt;/p>
&lt;p>它不是完整虚拟机，也不是设备模拟器。&lt;br>
它的核心职责很简单：&lt;/p>
&lt;ul>
&lt;li>创建 VM&lt;/li>
&lt;li>创建 vCPU&lt;/li>
&lt;li>让 guest 指令直接在物理 CPU 上运行&lt;/li>
&lt;li>当 guest 发生 VM Exit 时，把控制权还给用户态 VMM&lt;/li>
&lt;/ul>
&lt;p>所以可以把 KVM 理解成：&lt;/p>
&lt;p>&lt;strong>内核提供的“虚拟 CPU 执行引擎”。&lt;/strong>&lt;/p>
&lt;p>它解决的是：&lt;/p>
&lt;p>&lt;strong>“guest 代码怎么高效运行在硬件上？”&lt;/strong>&lt;/p>
&lt;hr>
&lt;h2 id="2-qemu-是什么">2. QEMU 是什么？&lt;a class="heading-anchor" href="#2-qemu-%e6%98%af%e4%bb%80%e4%b9%88" aria-label="本节链接">#&lt;/a>
&lt;/h2>&lt;p>QEMU 是用户态的 VMM / 模拟器。&lt;/p>
&lt;p>它做的事情是：&lt;/p>
&lt;ul>
&lt;li>加载 kernel / initrd / BIOS&lt;/li>
&lt;li>布置 guest memory&lt;/li>
&lt;li>模拟磁盘、网卡、串口、时钟等设备&lt;/li>
&lt;li>处理 guest 的 I/O 行为&lt;/li>
&lt;li>提供完整的启动流程&lt;/li>
&lt;/ul>
&lt;p>如果&lt;strong>不配 KVM&lt;/strong>，QEMU 也能跑，但那是纯软件模拟，会很慢。&lt;br>
如果&lt;strong>配 KVM&lt;/strong>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">qemu-system-x86_64 -accel kvm ...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>那么就是：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>QEMU 管机器&lt;/strong>&lt;/li>
&lt;li>&lt;strong>KVM 管 CPU 执行&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>所以：&lt;/p>
&lt;p>&lt;strong>QEMU 不是 KVM 的替代品，而是 KVM 上层最常见的 VMM。&lt;/strong>&lt;/p>
&lt;hr>
&lt;h2 id="3-firecracker-是什么">3. Firecracker 是什么？&lt;a class="heading-anchor" href="#3-firecracker-%e6%98%af%e4%bb%80%e4%b9%88" aria-label="本节链接">#&lt;/a>
&lt;/h2>&lt;p>Firecracker 也是用户态 VMM，但和 QEMU 的理念完全不同。&lt;/p>
&lt;p>QEMU 的目标是：&lt;/p>
&lt;ul>
&lt;li>通用&lt;/li>
&lt;li>兼容很多硬件&lt;/li>
&lt;li>能模拟一大堆设备&lt;/li>
&lt;li>覆盖各种历史负担&lt;/li>
&lt;/ul>
&lt;p>Firecracker 的目标是：&lt;/p>
&lt;ul>
&lt;li>只做 microVM 需要的最小集合&lt;/li>
&lt;li>设备尽量少&lt;/li>
&lt;li>启动路径尽量短&lt;/li>
&lt;li>安全面尽量小&lt;/li>
&lt;/ul>
&lt;p>所以 Firecracker 不是“没有 KVM 的另一个东西”，而是：&lt;/p>
&lt;p>&lt;strong>Firecracker = 更小的 VMM + KVM&lt;/strong>&lt;/p>
&lt;hr>
&lt;h1 id="三最关键的一句话它们的边界在哪里">三、最关键的一句话：它们的边界在哪里？&lt;a class="heading-anchor" href="#%e4%b8%89%e6%9c%80%e5%85%b3%e9%94%ae%e7%9a%84%e4%b8%80%e5%8f%a5%e8%af%9d%e5%ae%83%e4%bb%ac%e7%9a%84%e8%be%b9%e7%95%8c%e5%9c%a8%e5%93%aa%e9%87%8c" aria-label="本节链接">#&lt;/a>
&lt;/h1>&lt;p>如果把一台虚拟机拆开看，可以粗暴分成两层：&lt;/p>
&lt;h2 id="下层让-guest-cpu-跑起来">下层：让 guest CPU 跑起来&lt;a class="heading-anchor" href="#%e4%b8%8b%e5%b1%82%e8%ae%a9-guest-cpu-%e8%b7%91%e8%b5%b7%e6%9d%a5" aria-label="本节链接">#&lt;/a>
&lt;/h2>&lt;p>这是 &lt;strong>KVM&lt;/strong> 解决的。&lt;/p>
&lt;h2 id="上层让它看起来像一台机器">上层：让它看起来像一台机器&lt;a class="heading-anchor" href="#%e4%b8%8a%e5%b1%82%e8%ae%a9%e5%ae%83%e7%9c%8b%e8%b5%b7%e6%9d%a5%e5%83%8f%e4%b8%80%e5%8f%b0%e6%9c%ba%e5%99%a8" aria-label="本节链接">#&lt;/a>
&lt;/h2>&lt;p>这是 &lt;strong>QEMU / Firecracker&lt;/strong> 解决的。&lt;/p>
&lt;p>也就是说：&lt;/p>
&lt;ul>
&lt;li>KVM 管“执行”&lt;/li>
&lt;li>VMM 管“机器行为”&lt;/li>
&lt;/ul>
&lt;p>所以你可以记一句很有用的话：&lt;/p>
&lt;p>&lt;strong>KVM 管 CPU，VMM 管设备和启动流程。&lt;/strong>&lt;/p>
&lt;hr>
&lt;h1 id="四firecracker-每一层到底在解决什么问题">四、Firecracker 每一层到底在解决什么问题？&lt;a class="heading-anchor" href="#%e5%9b%9bfirecracker-%e6%af%8f%e4%b8%80%e5%b1%82%e5%88%b0%e5%ba%95%e5%9c%a8%e8%a7%a3%e5%86%b3%e4%bb%80%e4%b9%88%e9%97%ae%e9%a2%98" aria-label="本节链接">#&lt;/a>
&lt;/h1>&lt;p>如果从工程视角看，Firecracker 不是“一个大黑盒”，而是一层一层在解决问题。&lt;/p>
&lt;hr>
&lt;h2 id="1-jailer先把-vmm-自己关进笼子">1. Jailer：先把 VMM 自己关进笼子&lt;a class="heading-anchor" href="#1-jailer%e5%85%88%e6%8a%8a-vmm-%e8%87%aa%e5%b7%b1%e5%85%b3%e8%bf%9b%e7%ac%bc%e5%ad%90" aria-label="本节链接">#&lt;/a>
&lt;/h2>&lt;p>问题是：&lt;/p>
&lt;p>即使 guest 被 KVM 隔离了，&lt;strong>Firecracker 进程自己仍然运行在 host 上&lt;/strong>。&lt;/p>
&lt;p>如果 VMM 本身有 bug，被打穿，它依旧可能伤害宿主机。&lt;/p>
&lt;p>所以 Firecracker 在启动前先用 Jailer 做一层外部隔离：&lt;/p>
&lt;ul>
&lt;li>namespace&lt;/li>
&lt;li>cgroup&lt;/li>
&lt;li>chroot&lt;/li>
&lt;li>降权&lt;/li>
&lt;li>最小文件可见性&lt;/li>
&lt;/ul>
&lt;p>它解决的是：&lt;/p>
&lt;p>&lt;strong>“谁来限制 VMM 自己？”&lt;/strong>&lt;/p>
&lt;hr>
&lt;h2 id="2-kvm-初始化让-guest-能真正跑起来">2. KVM 初始化：让 guest 能真正跑起来&lt;a class="heading-anchor" href="#2-kvm-%e5%88%9d%e5%a7%8b%e5%8c%96%e8%ae%a9-guest-%e8%83%bd%e7%9c%9f%e6%ad%a3%e8%b7%91%e8%b5%b7%e6%9d%a5" aria-label="本节链接">#&lt;/a>
&lt;/h2>&lt;p>问题是：&lt;/p>
&lt;p>你需要一种方式，让 guest 不靠软件模拟，而是尽量直接使用硬件。&lt;/p>
&lt;p>KVM 提供的核心对象一般是三个 fd：&lt;/p>
&lt;ul>
&lt;li>KVM fd&lt;/li>
&lt;li>VM fd&lt;/li>
&lt;li>vCPU fd&lt;/li>
&lt;/ul>
&lt;p>然后用户态 VMM 负责：&lt;/p>
&lt;ul>
&lt;li>配 guest 内存&lt;/li>
&lt;li>创建 vCPU&lt;/li>
&lt;li>设寄存器&lt;/li>
&lt;li>调 &lt;code>KVM_RUN&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>它解决的是：&lt;/p>
&lt;p>&lt;strong>“guest 指令到底怎么执行？”&lt;/strong>&lt;/p>
&lt;hr>
&lt;h2 id="3-内存映射guest-看到的物理内存从哪来">3. 内存映射：guest 看到的物理内存从哪来？&lt;a class="heading-anchor" href="#3-%e5%86%85%e5%ad%98%e6%98%a0%e5%b0%84guest-%e7%9c%8b%e5%88%b0%e7%9a%84%e7%89%a9%e7%90%86%e5%86%85%e5%ad%98%e4%bb%8e%e5%93%aa%e6%9d%a5" aria-label="本节链接">#&lt;/a>
&lt;/h2>&lt;p>Guest 以为自己有一块连续物理内存。&lt;br>
实际上，这通常只是 host 上的一段 &lt;code>mmap&lt;/code> 区域。&lt;/p>
&lt;p>KVM 帮你把：&lt;/p>
&lt;ul>
&lt;li>guest physical address&lt;/li>
&lt;li>映射到 host 内存&lt;/li>
&lt;/ul>
&lt;p>它解决的是：&lt;/p>
&lt;p>&lt;strong>“guest 看到的 RAM 是怎么伪造出来的？”&lt;/strong>&lt;/p>
&lt;hr>
&lt;h2 id="4-vcpu-线程guest-cpu-怎么持续运行">4. vCPU 线程：guest CPU 怎么持续运行？&lt;a class="heading-anchor" href="#4-vcpu-%e7%ba%bf%e7%a8%8bguest-cpu-%e6%80%8e%e4%b9%88%e6%8c%81%e7%bb%ad%e8%bf%90%e8%a1%8c" aria-label="本节链接">#&lt;/a>
&lt;/h2>&lt;p>每个 vCPU 一般对应一个 host 线程。&lt;br>
VMM 的典型主循环是：&lt;/p>
&lt;ol>
&lt;li>调 &lt;code>KVM_RUN&lt;/code>&lt;/li>
&lt;li>guest 执行&lt;/li>
&lt;li>遇到 VM Exit&lt;/li>
&lt;li>VMM 处理退出原因&lt;/li>
&lt;li>再次进入 guest&lt;/li>
&lt;/ol>
&lt;p>它解决的是：&lt;/p>
&lt;p>&lt;strong>“guest 怎么在 host 上持续执行，同时还能被暂停、恢复和管理？”&lt;/strong>&lt;/p>
&lt;hr>
&lt;h2 id="5-设备模拟guest-怎么做-io">5. 设备模拟：guest 怎么做 I/O？&lt;a class="heading-anchor" href="#5-%e8%ae%be%e5%a4%87%e6%a8%a1%e6%8b%9fguest-%e6%80%8e%e4%b9%88%e5%81%9a-io" aria-label="本节链接">#&lt;/a>
&lt;/h2>&lt;p>Guest 不可能直接摸宿主机硬件。&lt;br>
所以 VMM 需要提供设备。&lt;/p>
&lt;p>Firecracker 采取的是最小设备集：&lt;/p>
&lt;ul>
&lt;li>​&lt;code>virtio-net&lt;/code>&lt;/li>
&lt;li>​&lt;code>virtio-blk&lt;/code>&lt;/li>
&lt;li>​&lt;code>serial&lt;/code>&lt;/li>
&lt;li>​&lt;code>rng&lt;/code>&lt;/li>
&lt;li>​&lt;code>vsock&lt;/code>&lt;/li>
&lt;li>​&lt;code>balloon&lt;/code>&lt;/li>
&lt;li>等少量必需设备&lt;/li>
&lt;/ul>
&lt;p>这里关键点是：Firecracker 更喜欢 &lt;strong>VirtIO&lt;/strong>，而不是模拟传统 PC 硬件。&lt;br>
因为 VirtIO 更简单、更快、攻击面更小。&lt;/p>
&lt;p>它解决的是：&lt;/p>
&lt;p>&lt;strong>“guest 如何访问网络、磁盘、串口这些外设？”&lt;/strong>&lt;/p>
&lt;hr>
&lt;h2 id="6-api-server外部怎么控制-microvm">6. API Server：外部怎么控制 microVM？&lt;a class="heading-anchor" href="#6-api-server%e5%a4%96%e9%83%a8%e6%80%8e%e4%b9%88%e6%8e%a7%e5%88%b6-microvm" aria-label="本节链接">#&lt;/a>
&lt;/h2>&lt;p>平台不可能手动敲命令控制 VM。&lt;br>
需要一个控制接口。&lt;/p>
&lt;p>Firecracker 提供的是 Unix Socket 上的 API，分为：&lt;/p>
&lt;ul>
&lt;li>preboot 配置&lt;/li>
&lt;li>runtime 操作&lt;/li>
&lt;/ul>
&lt;p>比如：&lt;/p>
&lt;ul>
&lt;li>设置 kernel&lt;/li>
&lt;li>挂 drive&lt;/li>
&lt;li>设置网卡&lt;/li>
&lt;li>start&lt;/li>
&lt;li>pause&lt;/li>
&lt;li>snapshot&lt;/li>
&lt;li>restore&lt;/li>
&lt;/ul>
&lt;p>它解决的是：&lt;/p>
&lt;p>&lt;strong>“平台控制面如何管理 VM 生命周期？”&lt;/strong>&lt;/p>
&lt;hr>
&lt;h2 id="7-mmdsguest-如何拿到自己的-metadata">7. MMDS：guest 如何拿到自己的 metadata？&lt;a class="heading-anchor" href="#7-mmdsguest-%e5%a6%82%e4%bd%95%e6%8b%bf%e5%88%b0%e8%87%aa%e5%b7%b1%e7%9a%84-metadata" aria-label="本节链接">#&lt;/a>
&lt;/h2>&lt;p>在云环境里，guest 常常要知道：&lt;/p>
&lt;ul>
&lt;li>自己是谁&lt;/li>
&lt;li>配置是什么&lt;/li>
&lt;li>应该拿什么 token / credential&lt;/li>
&lt;/ul>
&lt;p>Firecracker 提供 MMDS，模仿云平台元数据服务。&lt;/p>
&lt;p>它解决的是：&lt;/p>
&lt;p>&lt;strong>“guest 如何拿到属于自己的配置元数据？”&lt;/strong>&lt;/p>
&lt;hr>
&lt;h2 id="8-seccomp最后一层防线">8. Seccomp：最后一层防线&lt;a class="heading-anchor" href="#8-seccomp%e6%9c%80%e5%90%8e%e4%b8%80%e5%b1%82%e9%98%b2%e7%ba%bf" aria-label="本节链接">#&lt;/a>
&lt;/h2>&lt;p>即使已经有：&lt;/p>
&lt;ul>
&lt;li>Jailer&lt;/li>
&lt;li>KVM&lt;/li>
&lt;/ul>
&lt;p>仍然还要防止 Firecracker 进程乱调用系统调用。&lt;/p>
&lt;p>所以不同线程会被挂上不同的 seccomp 白名单。&lt;/p>
&lt;p>它解决的是：&lt;/p>
&lt;p>&lt;strong>“如果 VMM 出问题，如何进一步限制伤害范围？”&lt;/strong>&lt;/p>
&lt;hr>
&lt;h2 id="9-snapshot--restore解决冷启动">9. Snapshot / Restore：解决冷启动&lt;a class="heading-anchor" href="#9-snapshot--restore%e8%a7%a3%e5%86%b3%e5%86%b7%e5%90%af%e5%8a%a8" aria-label="本节链接">#&lt;/a>
&lt;/h2>&lt;p>这是 Firecracker 在 Serverless 场景非常关键的一环。&lt;/p>
&lt;p>不是每次都从：&lt;/p>
&lt;ul>
&lt;li>启 kernel&lt;/li>
&lt;li>启 OS&lt;/li>
&lt;li>启 runtime&lt;/li>
&lt;li>加载应用&lt;/li>
&lt;/ul>
&lt;p>而是先启动一次，再保存快照，后续直接恢复。&lt;/p>
&lt;p>它解决的是：&lt;/p>
&lt;p>&lt;strong>“如何把冷启动延迟压到毫秒级别？”&lt;/strong>&lt;/p>
&lt;hr>
&lt;h2 id="10-event-loop怎么把-api设备定时器vcpu-串起来">10. Event Loop：怎么把 API、设备、定时器、vCPU 串起来？&lt;a class="heading-anchor" href="#10-event-loop%e6%80%8e%e4%b9%88%e6%8a%8a-api%e8%ae%be%e5%a4%87%e5%ae%9a%e6%97%b6%e5%99%a8vcpu-%e4%b8%b2%e8%b5%b7%e6%9d%a5" aria-label="本节链接">#&lt;/a>
&lt;/h2>&lt;p>VMM 要同时处理很多事件：&lt;/p>
&lt;ul>
&lt;li>API 请求&lt;/li>
&lt;li>设备 I/O&lt;/li>
&lt;li>中断&lt;/li>
&lt;li>定时器&lt;/li>
&lt;li>guest 退出&lt;/li>
&lt;/ul>
&lt;p>Firecracker 用基于 &lt;code>epoll&lt;/code> 的事件循环来组织这些事情。&lt;/p>
&lt;p>它解决的是：&lt;/p>
&lt;p>&lt;strong>“如何高效协调整个 VMM 内部的事件流？”&lt;/strong>&lt;/p>
&lt;hr>
&lt;h1 id="五如果我只是想做一个-mini-版-firecracker最小需要什么">五、如果我只是想做一个 mini 版 Firecracker，最小需要什么？&lt;a class="heading-anchor" href="#%e4%ba%94%e5%a6%82%e6%9e%9c%e6%88%91%e5%8f%aa%e6%98%af%e6%83%b3%e5%81%9a%e4%b8%80%e4%b8%aa-mini-%e7%89%88-firecracker%e6%9c%80%e5%b0%8f%e9%9c%80%e8%a6%81%e4%bb%80%e4%b9%88" aria-label="本节链接">#&lt;/a>
&lt;/h1>&lt;p>这个问题比“Firecracker 全量实现”更有意义。&lt;/p>
&lt;p>因为大多数人第一次做 microVM runtime，不应该一上来就做：&lt;/p>
&lt;ul>
&lt;li>jailer&lt;/li>
&lt;li>seccomp&lt;/li>
&lt;li>snapshot&lt;/li>
&lt;li>mmds&lt;/li>
&lt;li>virtio-blk&lt;/li>
&lt;li>多 vCPU&lt;/li>
&lt;li>热插拔&lt;/li>
&lt;/ul>
&lt;p>你会直接淹死在复杂度里。&lt;/p>
&lt;hr>
&lt;h2 id="一个真正最小可运行的目标应该是什么">一个真正“最小可运行”的目标应该是什么？&lt;a class="heading-anchor" href="#%e4%b8%80%e4%b8%aa%e7%9c%9f%e6%ad%a3%e6%9c%80%e5%b0%8f%e5%8f%af%e8%bf%90%e8%a1%8c%e7%9a%84%e7%9b%ae%e6%a0%87%e5%ba%94%e8%af%a5%e6%98%af%e4%bb%80%e4%b9%88" aria-label="本节链接">#&lt;/a>
&lt;/h2>&lt;p>比如下面这个闭环就很好：&lt;/p>
&lt;ol>
&lt;li>本地启动 &lt;code>N&lt;/code> 个 microVM&lt;/li>
&lt;li>每个 guest 能联网&lt;/li>
&lt;li>每个 guest 启动后访问 host API&lt;/li>
&lt;li>host API 收到请求后 &lt;code>count + 1&lt;/code>&lt;/li>
&lt;/ol>
&lt;p>如果以这个目标倒推，最小需要：&lt;/p>
&lt;ul>
&lt;li>Linux host + &lt;code>/dev/kvm&lt;/code>&lt;/li>
&lt;li>1 个 vCPU&lt;/li>
&lt;li>guest memory&lt;/li>
&lt;li>kernel&lt;/li>
&lt;li>initramfs&lt;/li>
&lt;li>串口&lt;/li>
&lt;li>virtio-net&lt;/li>
&lt;li>tap / bridge&lt;/li>
&lt;li>host counter API&lt;/li>
&lt;li>一个简单 launcher&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="最重要的简化先不要磁盘">最重要的简化：先不要磁盘&lt;a class="heading-anchor" href="#%e6%9c%80%e9%87%8d%e8%a6%81%e7%9a%84%e7%ae%80%e5%8c%96%e5%85%88%e4%b8%8d%e8%a6%81%e7%a3%81%e7%9b%98" aria-label="本节链接">#&lt;/a>
&lt;/h2>&lt;p>第一版最值得做的简化是：&lt;/p>
&lt;p>&lt;strong>不要 root disk，不要 virtio-blk，直接用 initramfs。&lt;/strong>&lt;/p>
&lt;p>因为这样 guest 启动后直接执行 &lt;code>/init&lt;/code>，你把最小用户态程序打进 initramfs 就行。&lt;/p>
&lt;p>guest 的 &lt;code>/init&lt;/code> 做三件事：&lt;/p>
&lt;ol>
&lt;li>配网&lt;/li>
&lt;li>调 &lt;code>http://host/incr&lt;/code>&lt;/li>
&lt;li>打日志然后关机&lt;/li>
&lt;/ol>
&lt;p>这样能少掉非常多复杂度。&lt;/p>
&lt;hr>
&lt;h1 id="六为什么我一开始选择了-qemu--kvm-而不是直接手搓-vmm">六、为什么我一开始选择了 “QEMU + KVM” 而不是直接手搓 VMM？&lt;a class="heading-anchor" href="#%e5%85%ad%e4%b8%ba%e4%bb%80%e4%b9%88%e6%88%91%e4%b8%80%e5%bc%80%e5%a7%8b%e9%80%89%e6%8b%a9%e4%ba%86-qemu--kvm-%e8%80%8c%e4%b8%8d%e6%98%af%e7%9b%b4%e6%8e%a5%e6%89%8b%e6%90%93-vmm" aria-label="本节链接">#&lt;/a>
&lt;/h1>&lt;p>因为如果你的目标是先跑通业务闭环，QEMU 非常适合作为过渡层。&lt;/p>
&lt;p>比如你只想验证：&lt;/p>
&lt;ul>
&lt;li>guest 能起来&lt;/li>
&lt;li>guest 能通过 virtio-net 出网&lt;/li>
&lt;li>guest 能请求 host API&lt;/li>
&lt;li>host count 能变成 N&lt;/li>
&lt;/ul>
&lt;p>那一开始直接上自研 VMM，你会立刻被这些问题包围：&lt;/p>
&lt;ul>
&lt;li>Linux boot protocol&lt;/li>
&lt;li>guest memory 布局&lt;/li>
&lt;li>vCPU 初始化&lt;/li>
&lt;li>serial 模拟&lt;/li>
&lt;li>virtio-net&lt;/li>
&lt;li>TAP 转发&lt;/li>
&lt;li>VM Exit 处理&lt;/li>
&lt;/ul>
&lt;p>这些全都是对的，但&lt;strong>不该同时做&lt;/strong>。&lt;/p>
&lt;p>所以我当时的工程判断是：&lt;/p>
&lt;p>&lt;strong>先用 QEMU 作为 VMM，把 control plane、network、guest workload 跑通。&lt;/strong>&lt;br>
然后再逐步把 QEMU 替换掉。&lt;/p>
&lt;p>这条路线的好处是：&lt;/p>
&lt;ul>
&lt;li>验证闭环先成立&lt;/li>
&lt;li>排障基准先稳定&lt;/li>
&lt;li>以后替换 backend 时，CLI 和业务验收标准不变&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h1 id="七qemu-和-kvm-的关系最容易被误解的一点">七、QEMU 和 KVM 的关系，最容易被误解的一点&lt;a class="heading-anchor" href="#%e4%b8%83qemu-%e5%92%8c-kvm-%e7%9a%84%e5%85%b3%e7%b3%bb%e6%9c%80%e5%ae%b9%e6%98%93%e8%a2%ab%e8%af%af%e8%a7%a3%e7%9a%84%e4%b8%80%e7%82%b9" aria-label="本节链接">#&lt;/a>
&lt;/h1>&lt;p>很多人会说：&lt;/p>
&lt;blockquote>
&lt;p>“我都用 QEMU 了，那还跟 KVM 有什么关系？”&lt;/p>&lt;/blockquote>
&lt;p>答案是：关系非常大。&lt;/p>
&lt;p>如果你运行的是：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">qemu-system-x86_64 -accel kvm ...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>那么你的 guest CPU 其实就是跑在 KVM 上的。&lt;br>
只是你没有自己写 &lt;code>/dev/kvm&lt;/code> 的 ioctl，而是让 QEMU 帮你做了。&lt;/p>
&lt;p>所以准确说：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>QEMU without KVM&lt;/strong>：软件模拟，慢&lt;/li>
&lt;li>&lt;strong>QEMU + KVM&lt;/strong>：QEMU 管机器，KVM 管执行&lt;/li>
&lt;li>&lt;strong>Firecracker + KVM&lt;/strong>：Firecracker 管机器，KVM 管执行&lt;/li>
&lt;/ul>
&lt;p>换句话说：&lt;/p>
&lt;p>&lt;strong>Firecracker 和 QEMU 真正不同的，是 VMM 层，而不是 KVM 层。&lt;/strong>&lt;/p>
&lt;hr>
&lt;h1 id="八如果要从-qemu-逐步走向自研-firecracker-风格-vmm应该怎么走">八、如果要从 QEMU 逐步走向“自研 Firecracker 风格 VMM”，应该怎么走？&lt;a class="heading-anchor" href="#%e5%85%ab%e5%a6%82%e6%9e%9c%e8%a6%81%e4%bb%8e-qemu-%e9%80%90%e6%ad%a5%e8%b5%b0%e5%90%91%e8%87%aa%e7%a0%94-firecracker-%e9%a3%8e%e6%a0%bc-vmm%e5%ba%94%e8%af%a5%e6%80%8e%e4%b9%88%e8%b5%b0" aria-label="本节链接">#&lt;/a>
&lt;/h1>&lt;p>这是我现在觉得最靠谱的一条工程路线。&lt;/p>
&lt;hr>
&lt;h2 id="第一步把外部体验先做稳">第一步：把外部体验先做稳&lt;a class="heading-anchor" href="#%e7%ac%ac%e4%b8%80%e6%ad%a5%e6%8a%8a%e5%a4%96%e9%83%a8%e4%bd%93%e9%aa%8c%e5%85%88%e5%81%9a%e7%a8%b3" aria-label="本节链接">#&lt;/a>
&lt;/h2>&lt;p>在你真正替换 backend 之前，先把这些做稳：&lt;/p>
&lt;ul>
&lt;li>配置文件&lt;/li>
&lt;li>启动命令&lt;/li>
&lt;li>环境诊断&lt;/li>
&lt;li>日志&lt;/li>
&lt;li>运行时目录&lt;/li>
&lt;li>错误提示&lt;/li>
&lt;/ul>
&lt;p>比如我们后来补了：&lt;/p>
&lt;ul>
&lt;li>​&lt;code>doctor&lt;/code>&lt;/li>
&lt;li>​&lt;code>minivm.toml&lt;/code>&lt;/li>
&lt;li>交互式 &lt;code>init&lt;/code> 向导&lt;/li>
&lt;li>backend abstraction&lt;/li>
&lt;/ul>
&lt;p>这类改动表面看和 KVM 没关系，但其实非常关键。&lt;br>
因为它们决定了你以后调试新 backend 时，外部世界是不是稳定的。&lt;/p>
&lt;hr>
&lt;h2 id="第二步把-backend-seam-抽出来">第二步：把 backend seam 抽出来&lt;a class="heading-anchor" href="#%e7%ac%ac%e4%ba%8c%e6%ad%a5%e6%8a%8a-backend-seam-%e6%8a%bd%e5%87%ba%e6%9d%a5" aria-label="本节链接">#&lt;/a>
&lt;/h2>&lt;p>如果 &lt;code>launcher&lt;/code> 直接依赖 QEMU 命令行，那后面会很难换。&lt;/p>
&lt;p>所以需要有一个明确的 backend 边界：&lt;/p>
&lt;ul>
&lt;li>launcher 管 orchestration&lt;/li>
&lt;li>backend 管 guest runtime&lt;/li>
&lt;/ul>
&lt;p>这样之后：&lt;/p>
&lt;ul>
&lt;li>​&lt;code>qemu&lt;/code> backend 继续可用&lt;/li>
&lt;li>​&lt;code>kvm&lt;/code> backend 可以逐步补&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="第三步做-boot-only-kvm-backend">第三步：做 boot-only KVM backend&lt;a class="heading-anchor" href="#%e7%ac%ac%e4%b8%89%e6%ad%a5%e5%81%9a-boot-only-kvm-backend" aria-label="本节链接">#&lt;/a>
&lt;/h2>&lt;p>真正自研 VMM 的第一步，不应该是网络。&lt;br>
而应该是：&lt;/p>
&lt;p>&lt;strong>只让 guest kernel 跑起来，并且能输出串口。&lt;/strong>&lt;/p>
&lt;p>因为一旦串口稳定，你就有了最基础的调试手段。&lt;/p>
&lt;p>目标应该是：&lt;/p>
&lt;ul>
&lt;li>创建 VM&lt;/li>
&lt;li>分配内存&lt;/li>
&lt;li>创建 1 个 vCPU&lt;/li>
&lt;li>加载 kernel/initramfs&lt;/li>
&lt;li>guest 串口打印&lt;/li>
&lt;li>guest halt&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="第四步再接-virtio-net">第四步：再接 virtio-net&lt;a class="heading-anchor" href="#%e7%ac%ac%e5%9b%9b%e6%ad%a5%e5%86%8d%e6%8e%a5-virtio-net" aria-label="本节链接">#&lt;/a>
&lt;/h2>&lt;p>等 boot 和串口稳定后，再做网络。&lt;/p>
&lt;p>这样你只是在已有可观测 boot path 上增加一个设备，而不是同时调试整个世界。&lt;/p>
&lt;hr>
&lt;h1 id="九我对-firecracker-最大的理解转变">九、我对 Firecracker 最大的理解转变&lt;a class="heading-anchor" href="#%e4%b9%9d%e6%88%91%e5%af%b9-firecracker-%e6%9c%80%e5%a4%a7%e7%9a%84%e7%90%86%e8%a7%a3%e8%bd%ac%e5%8f%98" aria-label="本节链接">#&lt;/a>
&lt;/h1>&lt;p>以前我总以为：&lt;/p>
&lt;blockquote>
&lt;p>“Firecracker 是一个特别厉害的虚拟机软件。”&lt;/p>&lt;/blockquote>
&lt;p>后来我才意识到，这个理解太模糊了。&lt;/p>
&lt;p>更准确的理解应该是：&lt;/p>
&lt;p>&lt;strong>Firecracker 不是在发明新的 CPU 虚拟化原理，它是在 KVM 之上做了一次非常克制、非常工程化的 VMM 裁剪。&lt;/strong>&lt;/p>
&lt;p>它厉害的地方在于：&lt;/p>
&lt;ul>
&lt;li>知道什么必须有&lt;/li>
&lt;li>知道什么可以砍&lt;/li>
&lt;li>知道什么必须延后&lt;/li>
&lt;li>知道如何用多层隔离把风险压低&lt;/li>
&lt;li>知道如何把启动路径缩短到适合云场景&lt;/li>
&lt;/ul>
&lt;p>所以如果你自己也想做一个 mini Firecracker，真正重要的不只是“会不会调 KVM ioctl”，而是：&lt;/p>
&lt;p>&lt;strong>你有没有能力把问题拆成一条最短闭环。&lt;/strong>&lt;/p>
&lt;hr>
&lt;h1 id="十结语">十、结语&lt;a class="heading-anchor" href="#%e5%8d%81%e7%bb%93%e8%af%ad" aria-label="本节链接">#&lt;/a>
&lt;/h1>&lt;p>如果把这篇文章压缩成一句话，那就是：&lt;/p>
&lt;p>&lt;strong>KVM 解决的是“guest 怎么高效运行”，QEMU 和 Firecracker 解决的是“guest 作为一台机器怎么存在”。&lt;/strong>&lt;/p>
&lt;p>而 Firecracker 的核心价值，不在于“替代 KVM”，而在于：&lt;/p>
&lt;p>&lt;strong>在 KVM 之上，把 VMM 做到了极简、快速、可控、安全。&lt;/strong>&lt;/p>
&lt;p>对我来说，真正的收获不是背下了这些名词，而是终于看清了这条演进路线：&lt;/p>
&lt;ol>
&lt;li>先用 QEMU + KVM 跑通业务闭环&lt;/li>
&lt;li>再抽出 backend 边界&lt;/li>
&lt;li>再逐步替换成自研 KVM boot path&lt;/li>
&lt;li>最后才是 virtio-net、快照、安全隔离这些更复杂的能力&lt;/li>
&lt;/ol></description></item></channel></rss>