Stack: #216 -> #221 -> this. Worker breakpoint branch now calls any executor providing goal_resume_breakpoint_task (Local keeps its original path, gateway tasks still loud-fail); WarmPool reconcile_orphans is called on CHV worker startup and close with audit-on-failure; per-VM SSH host keys are provisioned before VMM start via cloud-init NoCloud seed (keyscan kept only as weak fallback, CHV_HOST_KEY_MODE=provisioned|keyscan); CHV_NET_JSON is validated in preflight and explicit direct egress is audited; chv-guest/build.sh is now real steps with --dry-run and fails fast without /dev/kvm. Tests: new test_chv_gaps.py (18), cloud full 1514 OK (skipped=4). No real VM verification: no KVM host.
5.6 KiB
Cloud Hypervisor 客机镜像(chv-guest)——内容清单与版本化构建说明
本目录有清单与真实构建步骤(build.sh,补缺口轨已实做), 但镜像本身不在本轨内实际构建发布。原因写在前面,不藏着: 当前没有带 /dev/kvm 的宿主可以构建并实测 VM 镜像(生产 主机是 CVM、无嵌套虚拟化;本 VM 容器内同样无 /dev/kvm)。 构建与实测见
docs/chv-production-readiness.md的“需镜像 构建 / 需 KVM 宿主实测”项,绝不在本轨声称镜像已建成、 已发布、已跑通。
1. 镜像定位
- 基础:Ubuntu 云镜像(与
cloud/docker/Dockerfile的任务镜像 对齐能力,不是另起一套环境口径)。 - 载体:Cloud Hypervisor 直接内核启动(vmlinux)+ raw 磁盘
镜像,执行器用
CHV_KERNEL/CHV_ROOTFS指向它们。 - 客内 host.py 位置:
/app/host.py(与 Docker 的/app:ro同款约定,只是载体从容器只读挂载换成 VM 镜像内置代码; 代码版本 = 构建时仓库 commit,见 §3 版本化)。 - 绝不进镜像的东西:任何模型 key、系统 key、用户账号数据、
生产凭证。模型 key 由客机 cloud-init 预置的运行环境变量名
注入(与 Docker 的
-e <名>同款惯例),不写进镜像层。
2. 内容清单(按现有 Docker 任务镜像能力对齐)
| 类别 | 内容 | 来源/版本口径 |
|---|---|---|
| 语言与工具链 | Python 3.12、git、Node.js(Playwright 驱动用) | 与任务镜像同款大版本,构建时钉小版本并记入构建日志 |
| 文档/图片工具 | pandoc、poppler-utils(pdftotext)、latexmk、texlive-latex-base、python-docx、openpyxl、python-pptx、PyMuPDF、Pillow | 逐项照抄 cloud/docker/Dockerfile 的 apt/pip 清单,不擅自加减 |
| agent 引擎 | codex、codex-code-mode-host、codex-resources/bwrap(成套,约 367M,缺 sibling 直接构建失败) | codex 0.164.0-alpha.9(与生产任务镜像一致);CODEX_BIN_DIR 由构建方提供,bin/ 不进仓库 |
| 浏览器 | Playwright + Chromium(浏览器自动化 MCP 用) | 与生产 playwright 镜像同款:浏览器装在固定路径、供租户用户可读;本骨架只列清单,浏览器版本在构建时钉死 |
| 客机基础 | openssh-server(SSH 通道用)、cloud-init、qemu-guest-agent(可选,宿主信息用) | sshd 默认只允许 key 登录,禁止密码登录 |
| 任务代码 | codex-app-server 仓库代码置于 /app(host.py 入口) |
版本见 §3,不挂载宿主代码目录(VM 与宿主无共享路径) |
中文 LaTeX 说明:与 Docker 镜像同款口径——xelatex + CJK 字体会再增数百 MB,本清单不默认包含;需要时单独一版镜像, 不在本轨悄悄加。
3. 版本化
镜像 tag 格式(构建时三项缺一即失败,不生成无版本镜像):
chv-guest-<ubuntu 版本>-<codex 版本>-<仓库 commit 短 hash>
例如(示例格式,非已建成):chv-guest-24.04-0.164.0-alpha.9-aebc623。
构建产物清单(构建方必须输出,执行器用它做 preflight 之外的 版本核对,v1 执行器暂不校验 tag,见就绪清单):
vmlinux(与 Ubuntu 云镜像配套的内核)disk.raw(根文件系统镜像)BUILDINFO.json:{ubuntu, codex_version, repo_commit, built_at, contents: [清单逐项版本]}
4. 构建脚本(补缺口轨:已从骨架改成真实步骤)
见 build.sh:参数校验 → 下载 Ubuntu 云镜像 → qemu-img
转 raw → virt-customize 装 §2 清单、拷入 codex 成套二进制
与仓库代码到 /app、写 host key 不重生成配置 →
virt-get-kernel 取内核 → 生成并校验 BUILDINFO.json。
./build.sh --dry-run out/ 只打印命令、不执行、不要求
KVM;全量模式在无 /dev/kvm 的机器上第一步就明确退出
(CHV_GUEST_BUILD needs a KVM host),绝不假装构建成功。
本轨未在真机上跑过全量模式,镜像未建成、未发布,仍属
“需 KVM 宿主实测”项。
6. Host key 首启注入硬性要求(补缺口轨新增)
执行器的 per-VM 预置方案(见 cloud/chv/hostkeys.py)能
跑通的前提是客机镜像必须满足以下全部,否则预置在真机
上跑不通,执行器会 fail-fast,不回落成弱方案:
- 装 cloud-init 且支持 NoCloud seed(seed 磁盘/目录由 执行器在 VM 启动前生成,含 meta-data 与 user-data);
- 首启时先应用 seed 再启动 sshd,seed 里的 user-data 把该 VM 的 host key 对写进 /etc/ssh/ 并重启 sshd;
- 镜像里已钉死
ssh_deletekeys: false与ssh_genkeytypes: [](build.sh 已写),首启不得无条件 重新生成 host key——重生成会使预置的 known_hosts 立即 失效,SSH 钉死直接拒绝,这是设计,不是 bug; - sshd 只允许 key 登录,禁止密码登录;
- seed 磁盘/目录是 per-VM 敏感物,执行器在 VM 关闭/ 回收时删除,镜像构建方不得把任何一把 host key 固化 进镜像(所有 VM 同 key 是安全事故)。
5. 与执行器的对接
- 执行器 preflight 只校验内核/镜像文件存在且可读,不校验镜像 内容版本——内容版本核对(BUILDINFO)是镜像发布流程的责任, 在就绪清单里标为“需镜像构建”项,不在本轨假装已做。
- 每任务磁盘:执行器 copy 模式下把
disk.raw复制为每任务 磁盘,任务之间文件系统独立;reuse 模式仅单租户实验,生产禁用。 - 快照基准:
CHV_SNAPSHOT_URL指向的快照必须由本镜像的干净 启动状态制成(pause 后 snapshot),预热池用它做干净 VM 来源。