Skip to Content
SpikesS6 · microVM egress

Spike S6 · microVM 内部 → 主 API 出口验证

状态:✅ 通过(2026-05-18)

补 S3+S4 当时遗留的”未覆盖”——之前 callback 验证是从 macmini host 发的, 没测过 microVM 内部 → 主 API 这条路径。

验证目标

  1. BoxLite microVM 的 NAT 出口能到达 Tailscale 100.x 网段
  2. microVM 内的 apk / wget 能正常出网(HTTPS)
  3. 从 microVM 内发起的 HMAC callback 与 NestJS 验签一致
  4. RTT 对比 host 直发(S4 26ms)能否接受 NAT 一跳的额外延迟

环境

远端机器vibe-zlyan · Apple M4 Mac mini · 16GB · macOS 26.3 · zlyan 非 admin
主 APIhttp://100.64.3.43:3000(Tailscale tailnet)
microVMalpine:latest via BoxLite 0.9.5(Hypervisor.framework)
HMAC secretdev_hmac_secret_change_in_prod_min_16_chars(来自 apps/api/.env
脚本/tmp/spike-s6-microvm-egress.py

microVM 内部网络

eth0 · 192.168.127.2/24 default route → 192.168.127.1 (BoxLite NAT gateway) DNS → 192.168.127.1 (BoxLite DNS proxy)

→ BoxLite 自带 NAT + DNS proxy,box 内不需要任何额外配置就能出公网 / Tailnet。 → 出网链路:box (192.168.127.2) → host NAT gateway (192.168.127.1) → host Tailscale (100.64.3.43)

6 个测试

#测试期望实测
1wget /health from box{"status":"ok"}
2apk add curl(HTTPS 出网)装成功✅ 1.8s — 证 NAT 工作
3POST 无 HMAC401missing_hmac
4POST 错 HMAC(0×64)401invalid_hmac · timing-safe 生效
5POST 正确 HMAC通过验签✅ 500(task_id 不存在但验签通过
6RTT n=10< S4 host (26ms) + 合理 NAT overhead✅ p50 35ms

Test 5 关键

远端 Python 计算:

hmac.new(b"dev_hmac_secret_change_in_prod_min_16_chars", b'{"type":"log","data":{"line":"hello from microvm"}}', hashlib.sha256).hexdigest() # = 7f82d7c06ecb1c98968357a083fabb0056842341c4ec1c8e912dc610af3fbc48

与 NestJS 端 createHmac('sha256', env.TASK_HMAC_SECRET).update(raw).digest('hex') 完全一致—— 说明 box 内 wget 没改 body 字节、HMAC 跨进程跨网段同步。

RTT 对比

链路nminp50avgmax
S4 macmini host → API(直 Tailscale)126ms
S6 microVM → API(经 BoxLite NAT)1029ms35ms54ms113ms

NAT 一跳额外开销约 +10ms(avg),p50 35ms 完全够支撑 task-runner 实时 SSE callback (远低于人类感知阈值 100ms)。

这个 spike 对 POC 的影响

1. 私有化路径”最后一公里”补齐

S3+S4 验证了 macmini host 上 BoxLite microVM 能启动 + Tailscale 通信。S6 补齐”box 内部主动出网”—— 这才是真实 task-runner 容器在跑时的网络模型。整个回链路全通

2. BoxLite NAT + DNS proxy 是 0 配置开箱即用

不需要手动配 iptables、自己起 dnsmasq、暴露 host network。BoxLite Python SDK 默认 BoxOptions 就能让 box 出公网+ Tailnet——这降低了 task-runner 容器镜像 / 启动脚本的复杂度。

3. NAT overhead +10ms 可忽略

放在 SSE / callback / 长任务的语境下,p50 35ms 几乎不可感知。对比之下 Fly + 公网回主 API 通常 100-200ms(跨地域),私有化反而更快。

对 design.md 的补强

D2(私有化用 BoxLite):补充——BoxLite 自带 NAT/DNS proxy,box 内 0 配置出网, 进一步降低私有化部署复杂度 → D6(HMAC callback):补充——microVM 内部 → 主 API p50 35ms(S6 实测) → 移除”S3+S4 未覆盖:microVM 内部网络出口”项

未覆盖(保留)

  • 长时 SSE 连接(>1h 持续)—— 本次只发了 ~14 个短 POST,长 SSE keep-alive 行为留 §7 真跑时观察。
  • box 内 HTTPS(不是 HTTP)callback—— 本次主 API 是 HTTP,生产环境会用 HTTPS, TLS 握手 RTT 可能更高。

清理

box 自动 auto_remove=True,无需手动清理。