- Chromium 钉死:CHROMIUM_HEADLESS_SHELL_REV(纯数字修订号) 设即钉死,buildinfo.py 校验读回的 ms-playwright 缓存目录名 须恰好是该修订号,否则构建失败;generate/check 的 --verify 也复核;未设时只记录、构建输出明说未钉死,BUILDINFO 记 null - /app 最小集:build.sh 不再把整个 $REPO_DIR/cloud/ 拷进客机, 只拷 host.py(只用标准库,不依赖 cloud/);REPO_DIR 预检 不再要求 cloud/ 存在 - generate_lockfile.py 只读 BUILDINFO.versions 一事已在 to10 轨 改写,本棒以合成 BUILDINFO 干跑复核(假版本 9.9.9 进 lockfile, 宿主 git 1:2.43.0 未混入)并补钉死复核;真实 lockfile 产出 仍待 V-9 真机构建,不编造版本号
166 lines
11 KiB
Markdown
166 lines
11 KiB
Markdown
# 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;浏览器在系统路径 /usr/local/share/ms-playwright(B-22:virt-customize 里 HOME=/,默认缓存会落到根目录 /.cache),agent 运行时须设 PLAYWRIGHT_BROWSERS_PATH 指向它;单独钉死见 §3:CHROMIUM_HEADLESS_SHELL_REV 设为纯数字修订号即钉死,未设时只记录、不强制 |
|
||
| 客机基础 | 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 |
|
||
| 任务代码 | 仅 `/app/host.py` 一个文件(host.py 只用标准库,不依赖 cloud/;旧版把整个 cloud/ 拷进 /app/,客内可读全套 server/worker 代码,M4 收尾已收紧为最小集) | 版本见 §3(repo_commit),不挂载宿主代码目录(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` 以它为唯一来源。
|
||
Chromium 单独钉死:构建时设 CHROMIUM_HEADLESS_SHELL_REV
|
||
为纯数字修订号(如 1248),buildinfo.py 校验读回的缓存
|
||
目录名须恰好是 `chromium_headless_shell-<rev>`,否则构建
|
||
失败,BUILDINFO.chromium_pinned_rev 记该值;未设时记 null、
|
||
只记录不强制,构建输出明说“未钉死”。真实 lockfile 产出
|
||
须等 V-9 真机构建(本机无 /dev/kvm,版本号绝不编造)。
|
||
|
||
## 4. 构建脚本(补缺口轨:已从骨架改成真实步骤)
|
||
|
||
见 `build.sh`:参数校验 → 下载 Ubuntu Minimal 云镜像(SHA256
|
||
必填)→ qemu-img 转 raw(轻量版不扩盘,底座根分区 2.4G 够用;
|
||
全量版 B-16 的 +12G 扩盘已删除)→ virt-customize 装 §2 清单、
|
||
拷入 codex 成套二进制与 host.py(仅此一个文件,不拷 cloud/)
|
||
到 /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/(write_files,
|
||
0600);seed 里绝不能带 `runcmd:`——user-data 的
|
||
runcmd 会整体替换镜像 `/etc/cloud/cloud.cfg.d/` 里
|
||
的 runcmd(cloud-init 不跨配置类型合并),旧版 seed
|
||
的 restart ssh 两行就这样顶掉了 `99-chv-sync.cfg`
|
||
的 `chv-sync boot` 钩子(sync-test 首轮实测);sshd
|
||
重启由镜像自己的 runcmd(`99-chv-sync.cfg`,cloud-final
|
||
阶段)做,见 `cloud/chv/hostkeys.py` 根因禁令;
|
||
- 镜像里已钉死 `ssh_deletekeys: false`(build.sh 已写),首启
|
||
不得无条件重新生成 host key——重生成会使预置的 known_hosts
|
||
立即失效,SSH 钉死直接拒绝,这是设计,不是 bug;无预置 key
|
||
时首启 bootcmd 只在缺 key 时 `ssh-keygen -A` 生成(B-23:
|
||
曾写 `ssh_genkeytypes: []` 彻底关掉首启生成,客机 sshd 起
|
||
不来,已删,绝不再写);
|
||
- 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 能同步回来。双向都通才算集成通。
|
||
- 集成(2026-11-07,第二轮第一棒):执行器生成 seed 时自动写
|
||
guest-env 已做(`cloud/chv/gitea_sync.py` + `wake_vm`):
|
||
GITEA_TOKEN 进密钥集(只进 seed,绝不进 argv),其余 5 键
|
||
也随 seed 进 guest-env;来源是宿主 `CHV_GITEA_*` 环境变量
|
||
或任务 `gitea_sync` dict;必填 4 键缺失时起 VMM 前
|
||
fail-closed(`gitea_sync_incomplete`),无同步变量时静默
|
||
不同步。客机用户与静态网络由 seed 附加项供给:
|
||
`CHV_SEED_USER_DATA_EXTRA_FILE`(含 `users:` 块的文件)与
|
||
`CHV_SEED_NETWORK_CONFIG_FILE`(NoCloud network-config),
|
||
路径配了但文件读不出时 wake 前 fail-closed
|
||
(`seed_extra_missing`);附加 user-data 里禁 `runcmd:`。
|
||
专用 token 与测试仓名须用户给,本轨不自编 token、不动
|
||
生产 Gitea 配置。
|