Files
codex-app-server/chv-guest/README.md
T
host 4c8e4eac7b fix(chv-guest): apt 用 --no-install-recommends(B-21)
Round 6 真机构建在 Playwright 步 ENOSPC 失败:--install 默认装
Recommends,python3-pip 连带拉入 python3-dev → gcc/g++/
build-essential 全套,根分区 2.4G 用到 2.2G(95M 空闲),
headless-shell 下到 70% 写满。改走 --run-command apt-get
install --no-install-recommends,必需项显式列出(fontconfig、
openssh-client),两轮 apt 后 apt-get clean + 清 lists 收尾。
buildinfo contents 与 README 同步加 openssh-client/fontconfig。
2026-11-06 10:29:59 +00:00

9.3 KiB
Raw Blame History

Cloud Hypervisor 客机镜像(chv-guest)——内容清单与版本化构建说明

本目录有清单与真实构建步骤(build.sh,补缺口轨已实做), 但镜像本身不在本轨内实际构建发布。原因写在前面,不藏着: 当前没有带 /dev/kvm 的宿主可以构建并实测 VM 镜像(生产 主机是 CVM、无嵌套虚拟化;本 VM 容器内同样无 /dev/kvm)。 构建与实测见 docs/chv-production-readiness.md 的“需镜像 构建 / 需 KVM 宿主实测”项,绝不在本轨声称镜像已建成、 已发布、已跑通。

1. 镜像定位

  • 基础:Ubuntu Minimal 24.04 官方云镜像(轻量口径,2026-11-06 用户定:停掉 5.5G 全量版,不再对齐 Manus,不做三面板/ 多租户/生产级全套;只装 codex + Python + SSH + cloud-init
    • 薄客机 agent + git + gt + 最小中文字体)。
  • 载体: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. 内容清单(轻量口径,2026-11-06 用户定)

类别 内容 来源/版本口径
语言与工具链 Python 3.12、git、curl、ca-certificates、xz-utils、fontconfig、openssh-client(Node.js 不装:Playwright 驱动是 Python playwright,见 PLAYWRIGHT=1 分支;任务镜像 Dockerfile 里也没有 Node.js,本清单不虚构它) 构建时钉小版本并记入构建日志;apt 用 --no-install-recommends(B-21:默认装 Recommends 会连带拉入 gcc 全套工具链顶满根分区)
文档/图片工具 已裁剪:pandoc、poppler-utils、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-headless-shell(默认装,不要完整 Chromium) Python playwright 装当时的 headless-shell,版本以 ms-playwright 缓存目录名记入 BUILDINFO.versions.chromium
客机基础 openssh-server(SSH 通道用)、cloud-init(qemu-guest-agent 已裁剪,CHV 不用它) sshd 只允许 key 登录,禁止密码登录——build.sh 写入 /etc/ssh/sshd_config.d/99-chv.conf 并经 sshd -t + grep 断言(feat-chv-secfix,M8,此前只是文档声称)
Gitea 同步 gt 1.0.0(官方 install.sh + SHA256 校验)、chv-sync(启动时 clone、显式 pull/push 的同步脚本) 凭证走 seed 盘 /etc/chv/guest-env(0600)投递,不进镜像;见 §7
任务代码 codex-app-server 仓库代码置于 /app(host.py 入口) 版本见 §3,不挂载宿主代码目录(VM 与宿主无共享路径)

中文 LaTeX 说明:与 Docker 镜像同款口径——xelatex + CJK 字体会再增数百 MB,本清单不默认包含;需要时单独一版镜像, 不在本轨悄悄加。字体只留最小的 fonts-wqy-microhei(中文能 看),不要全套 fonts-noto-cjk。

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: [清单逐项名]}——contents 只有名字列表;逐项版本 在 versions 里(B-02:dpkg + pip freeze 从客机读回, chromium 以 ms-playwright 缓存目录名记,gt 以 gt_version 记), generate_lockfile.py / check_lockfile.py 以它为唯一来源。

4. 构建脚本(补缺口轨:已从骨架改成真实步骤)

见 build.sh:参数校验 → 下载 Ubuntu Minimal 云镜像(SHA256 必填)→ qemu-img 转 raw(轻量版不扩盘,底座根分区 2.4G 够用; 全量版 B-16 的 +12G 扩盘已删除)→ virt-customize 装 §2 清单、 拷入 codex 成套二进制与仓库代码到 /app、装 gt 1.0.0、拷入 chv-sync 并写 cloud-init 启动钩子、写 host key 不重生成配置 → virt-get-kernel 取内核 → 生成并校验 BUILDINFO.json。 ./build.sh --dry-run out/ 只打印命令、不执行、不要求 KVM;全量模式在无 /dev/kvm 的机器上第一步就明确退出 (CHV_GUEST_BUILD needs a KVM host),绝不假装构建成功。 全量版曾在 WSL KVM 宿主(ajpkmq6i)上跑过四轮真机构建, 轻量版沿用同一宿主与流程,构建记录见 ~/workspace/chv-prod-audit/。

5. Host key 首启注入硬性要求(补缺口轨新增)

执行器的 per-VM 预置方案(见 cloud/chv/hostkeys.py)能 跑通的前提是客机镜像必须满足以下全部,否则预置在真机 上跑不通,执行器会 fail-fast,不回落成弱方案:

  • 装 cloud-init 且支持 NoCloud seed(seed 磁盘(CIDATA ISO,feat-chv-fix 起挂进 VmConfig 第二块只读盘)由执行器在 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 登录,禁止密码登录(build.sh 写入 /etc/ssh/sshd_config.d/99-chv.conf:PasswordAuthentication no、 PermitRootLogin prohibit-password、ChallengeResponseAuthentication no、 KbdInteractiveAuthentication no、PubkeyAuthentication yes,并经 sshd -t + grep 断言;feat-chv-secfix,M8);
  • seed 磁盘是 per-VM 敏感物,执行器在 VM 关闭/ 回收时删除,镜像构建方不得把任何一把 host key 固化 进镜像(所有 VM 同 key 是安全事故)。

6. 与执行器的对接

  • 执行器 preflight 只校验内核/镜像文件存在且可读,不校验镜像 内容版本——内容版本核对(BUILDINFO)是镜像发布流程的责任, 在就绪清单里标为“需镜像构建”项,不在本轨假装已做。
  • 每任务磁盘:执行器 copy 模式下把 disk.raw 复制为每任务 磁盘,任务之间文件系统独立;reuse 模式仅单租户实验,preflight 拦截(须同时设 CHV_REUSE_SINGLE_TENANT_EXPERIMENT=1 并审计放行,feat-chv-fix)。
  • 快照基准:CHV_SNAPSHOT_URL 指向的快照必须由本镜像的干净 启动状态制成(pause 后 snapshot),预热池用它做干净 VM 来源。

7. Gitea 双向同步(用户工作区口径,2026-11-06 追加)

主角是用户,不是 agent:用户在 Gitea 上的仓库在 VM 启动时 clone 到 ~/workspace,用完再同步回 Gitea;VM 是用户的工作 区,Gitea 是权威远端。同步口径沿用 Git Workspace Platform 已定的规则:分叉或冲突时失败关闭,不强制覆盖、不自动 rebase、不静默丢提交。

  • 凭证:seed 盘投递 /etc/chv/guest-env(0600,root 所有), 含 GITEA_URL / GITEA_USER / GITEA_TOKEN / SYNC_REPO / 可选 SYNC_BRANCH / 可选 GITEA_EMAIL。token 绝不进镜像、 代码、日志;chv-sync boot(root,cloud-init runcmd 调)把 token 写进 /home/chv/.git-credentials(0600,git credential store 标准机制),再以 chv 身份 clone;pull / push / status 以 chv 身份跑,只用已落盘的 credential,不再读 guest-env。无 guest-env 的启动静默不同步,VM 照常用。
  • 行为:boot 只在未 clone 时 clone,已 clone 则静默退出, 不自动 pull(避免重启时覆盖进行中的工作);pull 要求 工作树干净且只接受 fast-forward;push 无 upstream 时 push -u origin HEAD,否则普通 push,非 fast-forward 即 失败,绝不 --force。
  • gt 1.0.0 随镜像装好(官方 install.sh + SHA256 校验),登录 不 baked:运行时用 GITEA_TOKEN + GITEA_CLI_HOST 环境变量 即可用(gt repo list 等),或在 VM 里 gt auth login。
  • 验收(用户视角):VM 启动后仓在 ~/workspace 且是最新 HEAD;VM 内改文件 commit push 后 Gitea 网页可见该提交; Gitea 上改一次后 VM 内 pull 能同步回来。双向都通才算集成通。
  • 残留:执行器生成 seed 时自动写 guest-env 的集成未做(本轨 验收用手工 seed 测通链路);专用 token 与测试仓名须用户给, 本轨不自编 token、不动生产 Gitea 配置。