跳转到主要内容

这是本节的多页打印视图。 .

返回本页常规视图.

Farrow 文档

安装 Farrow、启动 Pigsty Inventory、维护唯一 deployment,并查阅准确的配置与命令契约。

Farrow 把一份 Pigsty 兼容的 Inventory 启动成固定 IP 的 QEMU 虚拟机。每个 Unix 用户只有一套 deployment,状态位于 ~/.farrow,因此生命周期与 SSH 命令可在任意 目录运行。

按任务选择最短路径:

  • 开始使用:安装、第一个实验环境、日常操作与排障。
  • 参考:Inventory 字段、命令、参数、输出与退出码。
  • 关于:简化设计、真机验证、已知限制与发布门禁。

新手直接跟随教程即可。正常路径只有三步:farrow setupfarrow upfarrow status

重要

Farrow 仍是 pre-1.0。当前源码、真机验证、打包、发布与线上站点是不同门禁。 依赖开发构件前请阅读当前状态

1 - 开始使用

安装 Farrow,启动单节点或四节点,维护 deployment,并解决常见故障。

按顺序阅读:

  1. 安装:构建当前源码并检查宿主能力。
  2. 教程:启动一台、扩到四台,再交给 Pigsty。
  3. 日常操作:启动、停止、变更、检查与销毁节点。
  4. 故障排查:简短、安全的症状到修复手册。

1.1 - 安装

构建 Farrow、确认原生虚拟化,并理解一次性的宿主准备。

当前可用的安装方式

从当前工作区构建:

cd /path/to/farrow
make build
export PATH="$PWD/bin:$PATH"
farrow version
farrow doctor

目前没有公开的 v1 软件包。不要用来源不明的二进制替换同一次构建产生的 farrowfarrow-hosts-helper

源码构建需要 Go 1.27.x。macOS 还需要已经安装好的 Homebrew;Farrow 可以通过 Homebrew 安装 QEMU,但不会自行引导安装 Homebrew。当前编译默认镜像仓库是开发宿主 https://m0/farrow;需要其他可达镜像时使用 FARROW_REPO--repo

宿主要求与带日期的证据

HVF/KVM 原生加速是正常路径。任意原生失败绝不会被静默改成模拟重试;只有显式外来 vm_arch,或 Catalog 已知的 EL8 arm64/Apple Silicon 不兼容规则,才会选择 TCG。 TCG 结果只可作为兼容性证据,不能作为性能证据。

宿主 最近一次记录的证据(2026-08-27)
macOS arm64 已用 HVF、QEMU 11.1、socket_vmnet 验证
Ubuntu 26.04 amd64 已用 KVM、QEMU 10.2.1、NetworkManager 验证
macOS arm64 上的 Rocky Linux 8.10 arm64 Guest 已用自动 TCG 与完整 readiness 验证
其他 Debian/Fedora/EL9 amd64 已实现;依赖前应重新做原生验证
macOS amd64、Linux arm64 已交叉构建和单测,尚无当前真机证据

macOS 需要 Homebrew。Linux 需要 systemd,以及 NetworkManager 或 systemd-networkd 之一。farrow setup 会通过 Homebrew、APT 或 DNF 安装缺失依赖。

setup 会改什么

可以先看 dry-run:

farrow setup --dry-run
farrow setup --yes

setup 可能安装 QEMU 依赖、准备固定 IP 网络、安装权限很窄的 hosts publisher。 所有宿主变更与 sudo 原因都会先打印。

自动化环境使用 --yes。非交互 sudo 可以来自已缓存凭据或合适的 NOPASSWD 策略; 每一条真实特权命令仍使用明确的绝对路径 argv。

setup 是幂等的:健康的重复执行只会复用网络与 helper。 源码测试与这份带日期的真机矩阵是不同门禁:重新构建更新的工作树不会自动刷新上表。

1.2 - 教程

启动单节点、验证它、无重启扩到四节点,并把同一份 Inventory 交给 Pigsty。

1. 创建实验环境

mkdir -p ~/lab
cd ~/lab
export FARROW_REPO=https://m0/farrow   # 离开开发网络后替换为可达镜像
farrow setup --dry-run
farrow setup --yes
farrow up

目录中没有配置时,setup 会写入单节点 farrow.yml

all:
  vars:
    admin_ip: 10.10.10.10
  children:
    nodes:
      hosts:
        10.10.10.10: { nodename: meta }

up 下载并校验镜像,创建磁盘与 cloud-init seed,启动 QEMU,并等待 Guest 的 readiness 记录。

2. 验证节点

farrow status
farrow ssh meta
farrow exec meta -- hostname
ping 10.10.10.10

默认节点有 2 vCPU、4 GiB 内存、64 GiB 根盘,以及挂载到 /data 的 128 GiB XFS 数据盘。

farrow status 还会显示实际 Guest 架构与加速器。默认 EL9/EL10 使用原生 HVF/KVM。 Apple Silicon 上设置 vm_image: el8 时,Stock 64K Granule Kernel 会自动使用同架构 TCG。显式设置部署级 vm_arch: amd64 可运行 amd64 Guest,但会使用单线程 TCG,速度 明显更慢。EL7 仅作为 deprecated 的 Linux/amd64 原生 BIOS/KVM Guest 提供。

3. 扩到四节点

在同一个 hosts: 映射下增加三行:

        10.10.10.11: { nodename: node-1 }
        10.10.10.12: { nodename: node-2 }
        10.10.10.13: { nodename: node-3 }

然后收敛:

farrow plan       # create: node-1, node-2, node-3
farrow up
farrow status

只会创建新增节点,meta 的进程与 uptime 不变。控制节点第一次启动时就获得了 deployment 密钥,因此可以立即 SSH 到新节点:

farrow exec meta -- ssh [email protected] hostname

4. 与 Pigsty 共用同一份文件

如果 Pigsty 已生成 pigsty.yml,无需转换:

./configure -c meta
farrow setup
farrow up
./install.yml

Farrow 读取已记录的 VM 字段,以及用于命名、控制节点和登录身份的原生字段。 pg_rolepg_versionrepo_*node_packages 等未消费参数不会产生 VM drift; pg_cluster/pg_seq 与 node-admin 字段会被消费。

5. 停止或移除

farrow stop
farrow start
farrow destroy --force

普通 destroy 保留已校验镜像缓存、deployment 密钥与持久盘。只有明确需要时才使用 --delete-persistent--purge

1.3 - 日常操作

唯一 deployment 的正常生命周期:检查、访问、扩容、变更、停止与销毁。

检查与访问

farrow status
farrow ssh meta
farrow exec node-1 -- hostname
farrow logs meta --source serial
farrow ss                         # 安装 SSH 别名,之后可直接 ssh meta

应用状态位于 ~/.farrow,这些命令可在任意目录执行。 Status 会显示持久化的 Guest 架构与加速器,因此 TCG 永远不是不可见回退。 planupreloadrecreate 依次优先使用 -f、当前目录发现的 Inventory, 两者都没有时才回退到已应用规格;validate 始终需要文件。

停止与启动

farrow stop                       # 别名:halt
farrow start
farrow restart node-1
farrow reload -f farrow.yml       # 停止、重新读配置、收敛

restart 使用已应用状态;reload 会重新读取 Inventory。

变更 deployment

farrow plan
farrow up                         # 创建新增节点,并启动选中的已停止节点
farrow recreate node-1 --force    # 应用某个节点的 VM 定义变化
字段 含义 操作
create 配置有、状态无 farrow up
recreate VM 定义改变 farrow recreate <node> --force
missing 状态有、配置无 恢复配置,或显式 destroy

删除 YAML 永远不会删除 VM。未消费的 Pigsty 变更得到 action:none;命名与 node-admin 字段虽然不以 vm_ 开头,仍会被消费。

销毁

farrow destroy node-3 --force
farrow destroy --force
farrow destroy --force --delete-persistent
farrow destroy --force --purge

--delete-persistent--purge 只适用于整体销毁,不能和节点选择器一起使用。 --purge 删除持久盘、密钥和 deployment 状态,但保留镜像。宿主网络单独卸载,仍有 VM 挂接时会拒绝:

farrow network uninstall --yes

镜像

farrow image list
farrow image info u24
farrow image pull u24
farrow image prune --dry-run

镜像必须来自签名 Catalog,并在使用前通过 SHA-256 校验。当前镜像均为 testing, 只有 EOL EL7 是 deprecated,因此每次启动都会打印相应警告。

1.4 - 故障排查

面向 setup、网络、镜像、漂移、中断状态与 SSH 的简短安全手册。

先做只读检查:

farrow doctor --json
farrow network status --json
farrow status --json

找不到配置

第一次部署时,在 farrow.yml/pigsty.yml 所在目录运行 planupvalidate, 或传入 -f /path/to/file。状态存在后,planupreloadrecreate 可回退到 已应用规格;status、start、stop、SSH 与 destroy 始终使用已应用状态。如果 status 也打印同样消息,所选 FARROW_HOME 中没有已应用状态。

setup 需要 sudo

提示前一行会说明具体宿主变更;特权步骤开始时 Farrow 会直接把交互终端交给 sudo。 自动化环境需要已有凭据或合适的 NOPASSWD,再使用 --yes

原生加速或兼容运行时不可用

原生路径需要 macOS HVF 或 Linux KVM。只有显式外来 vm_arch 或内置镜像/宿主兼容规则 才会选择 TCG;任意原生失败绝不会静默回退。Homebrew QEMU 包含两个 System Emulator; Linux setup 只安装宿主原生家族,因此外来 Guest 还需要对应 qemu-system-* 与固件。

planuprecreate 会在任何破坏性修改前验证所选模拟器与固件。TCG 性能结果没有 参考意义。

网络是 partial 或 invalid

不要手工删宿主文件,先查看受控清理计划:

farrow network status --json --verbose
farrow network uninstall

确认只包含 Farrow 自有路径后再加 --yes。Linux bridge smoke 失败会自动按 manifest 回滚;只有出现 automatic rollback failed 才表示必须人工检查。

Linux bridge helper 失败

id
stat -c '%U:%G %a %n' /usr/lib/qemu/qemu-bridge-helper
dpkg-statoverride --list /usr/lib/qemu/qemu-bridge-helper

Debian/Ubuntu 使用 root:<调用者可用组> 4750。桌面系统通过 ACL 获得 /dev/kvm 权限时,调用者不必静态加入 kvm 组。

plan 报 recreate 或 missing

recreate 需要 farrow recreate <node> --forcemissing 只是报告:恢复主机条目, 或运行 farrow destroy <node> --force

SSH 失败

检查 farrow statusfarrow ssh-config 与串口日志。Farrow 自身 SSH 使用回环管理端口; Ansible 直连固定 IP。

Catalog 或镜像校验失败

当前二进制已内置 active 与 standby Catalog 公钥。未知签名者、版本回滚/同版本异内容、 工件尺寸/SHA 不符、qcow2 结构不安全属于不同完整性错误。使用正确签名仓库,或通过 farrow image import --sha256 ... 导入;不要直接向 ~/.farrow/images 复制字节。

命令被中断

运行 farrow status。可证明存活或死亡的运行时会按完整进程身份收敛;歧义进程继续阻塞。 不要只凭状态文件里的 PID 就杀进程。

如果记录的 QEMU 进程仍存在,但 QMP Socket 缺失,应先保留证据并查看串口/QEMU 日志, 再决定是否用 stop 收敛。不要手工删除运行时 Socket 或状态文件。

提交问题时请包含准确命令与退出码、farrow version、上面三份 JSON、宿主系统/架构与 QEMU 版本。

2 - 参考

Farrow 读取的 Pigsty Inventory 与命令行的准确契约。
  • 配置:发现顺序、变量、默认值、磁盘、共享、命名与漂移。
  • 命令行:命令、关键参数、输出模式与退出码。
  • 镜像:签名 Catalog、别名、本地缓存、拉取、导入与清理。
  • 镜像流水线:Candidate 校验与离线归一化。

Farrow 不提供受支持的 Go Library API;internal/ 下的包都是实现细节。

2.1 - 配置

Farrow 读取的 Pigsty Inventory 字段、默认值与节点级漂移行为。

发现顺序

依次查找:显式 -f、当前目录的 farrow.ymlfarrow.yamlpigsty.ymlpigsty.yaml。所有文件名都使用同一种 Pigsty 兼容 YAML Inventory。

旧的顶层 version:/nodes: 格式会直接报迁移提示。

planupreloadrecreate 找不到文件时,如果 deployment 已存在,会回退到 已应用规格;validate 不会回退。配置必须是最大 4 MiB 的普通非符号链接文件。

Farrow 读取什么

Farrow 读取主机 IP、nodenameadmin_ippg_clusterpg_seqnode_admin_usernamenode_admin_uid 与已记录的 vm_* 变量。admin_ip 只从 all.vars 读取,用于选择控制节点;没有匹配时使用第一台托管主机。所有节点必须解析为 同一个登录用户名;默认用户 dba 的显式 node_admin_uid 必须为 88。

其余内容完全不读,也不会产生 drift。这里指 pg_rolepg_versionrepo_*node_packages 等未消费字段,不能泛化为所有 pg_*node_*

命名空间内严格校验:未知 vm_*、错类型、Jinja 表达式、非法地址、同级分组冲突都会报错。

VM 变量

变量 默认值 含义
vm_skip false 不虚拟化这台真实/外部主机
vm_image u24 镜像别名
vm_arch native 部署级 Guest 架构:nativeamd64arm64
vm_cpu 2 vCPU 数量
vm_mem 4096 MiB 整数,或 8GiB 等尺寸
vm_disk 64 根盘 GiB
vm_disks [{path: /data}] 额外数据盘
vm_alias [] Guest /etc/hosts、SSH config 与可选宿主别名
vm_shares [] QEMU 9p 宿主目录共享

空主机条目就是一台完整 VM。每套 deployment 支持 1–20 台托管主机;vm_cpu 范围 1–256,内存至少 512 MiB。

vm_arch 比普通逐主机字段更严格:出现时必须在所有托管主机上解析为同一个值,因此 应只在 all.vars 定义一次。修改它属于 deployment envelope 变化,必须整体重建。 Linux setup 只安装宿主原生模拟器;外来架构还需要对应 qemu-system-* 与固件。

数据盘

vm_disks:
  - path: /data
    size: 128
    fs: xfs
    persistent: false

path 同时是磁盘身份与挂载点;fsxfsext4persistent: true 在普通 destroy 后保留;vm_disks: [] 表示不要额外盘。

目录共享

vm_shares:
  - host: /absolute/owned/source
    guest: /src
    readonly: true

源目录必须真实、属于调用者且互不重叠。9p 只适合可信开发文件,不能放 PostgreSQL 数据。

名称与地址

节点名依次取 nodename<pg_cluster>-<pg_seq>node-<IP末段>,且必须唯一。

所有托管主机必须位于同一个 RFC1918 /24.1 属于宿主,.2.8 保留,节点使用 .9.254

漂移

Farrow 对每个解析后节点计算哈希。新增主机由 up 创建;选中的已停止节点会启动, 运行中同伴不受影响。VM 定义变化需要节点级 recreate;删除主机条目只报告、绝不销毁。 deployment 架构、用户或子网变化需要整体重建。修改用于派生节点名的字段会表现为旧节点 missing 加新节点,建议使用稳定、显式的 nodename

2.2 - 命令行

Farrow 命令、关键参数、结构化输出与退出码。
farrow [--json|--yaml] [--verbose] <command> [flags] [node...]

已安装的二进制是当前版本最准确的参考。每一条可见命令都自带操作边界与可复制样例:

farrow --help
farrow setup --help
farrow image pull --help

文本模式下,直接运行 farrowfarrow image 这样的命名空间会展示上下文帮助并成功 退出;JSON/YAML 模式下,空命名空间返回结构化用法错误。显式 --help 始终输出供人阅读的 帮助文本。

命令

范围 命令
准备 setupinitvalidatedoctor
生命周期 planupstartstop/haltrestartreloadrecreatestatusdestroy
访问 sshexeclogsprovisionssh-configsshosts
镜像 image list/info/pull/import/sync/prune/reset-manifest
宿主网络 network status/install/uninstall
其他 versioncompletion

使用已应用状态的命令可在任意目录运行。配置来源由命令决定,-f 刻意不做全局参数:

命令 期望状态来源
setup [template] 显式 -f,否则发现配置,否则生成 meta;模板与 -f 互斥
init [template] 生成新 Inventory,不读取期望状态
validate 显式 -f,再发现配置;绝不回退到已应用状态
planupreloadrecreate 显式 -f,再发现配置,最后回退到已应用规格
其他生命周期/访问命令 不读取期望配置;按需使用已应用状态或带属主标记的状态

关键参数

参数 含义
--json--yaml stdout 机器可读;进度仍写 stderr
--verbose stderr 有界诊断
--yes 应用已展示的宿主/setup 计划
--force 跳过 destroy/recreate 交互确认;无终端时必须显式给出
--no-wait QMP/进程身份确认后返回,不等 Guest readiness
--delete-persistent 整体销毁时也删持久盘;不能与节点选择器一起使用
--purge 整体处置:删除磁盘、密钥与 deployment 状态,保留镜像

如果失败命令尚未输出更丰富的类型化结果,结构化模式会先输出一份包含 errormessage 的对象,再返回约定的非零退出码;已经携带失败状态的结果后面绝不会追加第二份 JSON/YAML 文档。

plan 是只读操作,即使 action 为 recreateblocked-removal 也返回成功;自动化必须 检查 action 与 createrecreatemissing 字段。up 会创建新增节点、启动选中的 已停止节点;破坏性 drift 则返回冲突,不会被静默应用。

status 会为每个节点报告持久化的 guest_archaccelerator;文本和结构化输出都会 明确显示 TCG。

SSH 透传与命令补全

farrow ssh [node] [--] [command ...] 打开会话或运行可选命令; farrow exec [node] [--] <command ...> 必须给出命令并透传退出码。-- 之前的展示参数 属于 Farrow,之后的参数属于 OpenSSH 或远端程序。

加载 farrow completion bash|zsh|fish|powershell 可获得命令与作用域准确的参数补全, 同时补全模板、镜像别名、枚举参数,以及从期望/已应用规格只读解析出的节点名。

退出码

代码 含义
0 成功
1 运行时失败
2 用法或配置错误
3 缺少宿主能力
4 状态冲突或需要显式收敛
5 多节点部分完成
6 资源冲突
7 完整性或属主失败

sshexec 会透传远端程序退出码;但 SSH 保留的传输失败码 255 会被 Farrow 映射为 运行时失败 1。

2.3 - 镜像

签名 Catalog、内置别名、仓库选择、本地缓存校验、导入与清理。

Farrow 使用一份签名静态 Catalog 与不可变 qcow2 工件。更新 Catalog 不需要发布新的 Farrow 二进制,但二进制决定信任哪些签名公钥与镜像安全规则。

警告

EL7 标记为 deprecated;其余内置镜像均为 testing,不是 supportedup 打印的警告是刻意保留的;拉取成功只证明完整性,不代表生产支持承诺。

别名与拉取顺序

内置 Catalog 包含 9 个 Family、17 个工件:el7 只有 amd64;el8el9el10d12d13u22u24u26 均有 amd64 与 arm64。默认使用 u24

别名 发行版 架构 启动 状态
el7 CentOS Linux 7.9 / 2211 amd64 BIOS deprecated
el8 Rocky Linux 8.10 amd64、arm64 UEFI testing
el9el10 Rocky Linux amd64、arm64 UEFI testing
d12d13 Debian amd64、arm64 UEFI testing
u22u24u26 Ubuntu amd64、arm64 UEFI testing
farrow image list
farrow image info u24
farrow image pull u24

拉取时 Farrow 会:

  1. --repoFARROW_REPO、编译期默认仓库的顺序刷新 catalog.json 与相邻 .minisig
  2. 使用内置 active 或 standby 公钥验证签名;
  3. 选择 Catalog 默认 Release;独立 image pull 使用本机架构,生命周期解析遵循 vm_arch
  4. 只有尺寸、SHA-256、qcow2 结构全部匹配时才复用本地文件;
  5. 否则下载仓库工件,仓库缺失时回退到 Catalog 中不可变的 HTTPS Upstream URL。

当前编译默认值仍是开发仓库 https://m0/farrow,尚未声称存在公开镜像服务。显式仓库 失败会报错;无法访问编译默认仓库时则回退到内置 Catalog。

运行时策略

匹配架构正常使用原生 HVF/KVM,只有一个 Catalog 已知例外:Stock EL8 arm64 的 64K Granule Kernel 无法通过 Apple HVF 运行,因此 Apple Silicon 会自动选择可见的同架构 TCG。显式外来 vm_arch 也会使用 TCG;arm64 宿主上的 amd64 Guest 使用单翻译线程, 以保留 x86 内存序。TCG 结果不能作为性能证据。

EL7 刻意仅支持 Linux/amd64 原生运行。Linux setup 只安装宿主原生 QEMU;外来架构必须 先安装对应 System Emulator 与 UEFI 固件,planuprecreate 才会继续。

farrow image pull --repo https://mirror.example/farrow u24
FARROW_REPO=/absolute/local/repository farrow up

仓库 URL 可以是 HTTP 或 HTTPS,因为 Catalog 签名与镜像摘要才是完整性权威;Catalog 中的不可变 Upstream 工件 URL 必须使用 HTTPS。

信任与校验

当前普通构建已经内置两把生产校验公钥;私有签名密钥不在源码仓库中。Catalog 激活会拒绝 未知密钥、畸形内容、同版本异内容,以及低于已记录 High-water Mark 的版本;只有操作者 显式允许时才可降级。

镜像必须是尺寸与 SHA-256 匹配的纯 qcow2,不得有 backing file、外部数据文件、加密或 未知不兼容 Feature。通过校验的 Base Image 变成只读;节点根盘使用 Overlay,永不修改 Base。

farrow image sync https://repo.example/farrow/catalog.json
farrow image sync --allow-downgrade /absolute/repo/catalog.json
farrow image reset-manifest

reset-manifest 恢复二进制内置的 Bootstrap Catalog,但不会清除防回滚 High-water Mark。

本地布局与导入

镜像位于 FARROW_HOME/images(默认 ~/.farrow/images):各 Family 目录保存下载工件, manifests/ 保存 Catalog 状态,local/local-images.json 保存导入镜像。已经没有旧的 ~/.farrow/cache 或按摘要组织的 sha256/ 层级。

farrow image import --sha256 <digest> /path/to/base.qcow2
farrow image import --name local-mybase --boot uefi \
  --source-user ubuntu --sha256 <digest> /path/to/base.qcow2

命名的本地别名必须以 local- 开头,因此未来的签名 Catalog 无法覆盖它。使用 --name 时必须同时给出 --boot--source-user;Farrow 不猜 Guest Bootstrap 契约。

清理

farrow image prune --dry-run
farrow image prune --yes

Prune 会先列出准确的未引用镜像与遗留 Staging 文件。已应用 deployment 引用的镜像永远 不是候选;destroy(包括 destroy --purge)后镜像仍保留缓存。

使用 go run ./tools/catalogexport /absolute/new/catalog.json 可逐字节导出编译期 Catalog。 公开 Catalog 若使用相同版本,就必须使用完全相同的字节;同版本不同内容会按 equivocation 拒绝。Release 签名与镜像 Catalog 签名仍属于不同信任域。

2.4 - 镜像流水线

不下载、不上传、不签名地校验或离线归一化显式 qcow2 Candidate。

packaging/image-pipeline/ 接受一份已下载的不可变 qcow2 与独立获得的 SHA-256。它绝不 下载、上传、修改 Farrow 运行时/网络状态、读取签名密钥,也不会把镜像标成 supported

模式

  • validate:复制并重哈希,强制 qcow2 检查,校验单元素 Backing Chain,运行 qemu-img check,输出明确不可发布的证据 Bundle;不会修改 Guest 凭据。
  • offline:额外在 Staged Copy 上使用 libguestfs virt-customize --no-networkvirt-cat。它拒绝无关 UID/GID 88 占用,归一化锁定的 dba/admin 身份,关闭密码与 Root SSH,清理密钥/历史/Host Identity/cloud-init Cache,恢复定向 SELinux Label, 并回读确定性 Marker。
SOURCE_DATE_EPOCH=1787486400

./packaging/image-pipeline/build.sh \
  --mode validate \
  --source /absolute/source.qcow2 \
  --expected-sha256 <digest> \
  --output /absolute/new/evidence-directory \
  --name u24 --release 20260801.0.0 --arch amd64 \
  --source-user ubuntu --boot uefi \
  --source-uri https://immutable.example/source.qcow2 \
  --artifact-url 'https://images.example/u24/{sha256}.qcow2' \
  --license NOASSERTION \
  --source-date-epoch "$SOURCE_DATE_EPOCH" \
  --manifest-version 2026082801

Source/Output 必须是绝对路径;Source 必须 Canonical、普通、非符号链接、复制期间稳定, 且不超过 16 GiB;Output 必须不存在。Builder 使用相邻排它锁、0700 Staging 与一次最终 Rename;失败只删除受保护的 Staging。

成功 Bundle 包含只读 qcow2、Recipe、SLSA Provenance、SPDX Boundary SBOM、状态为 testingmanifest-candidate.json、Validation Evidence 与 Checksums。签名刻意位于 流水线之外。固定输入/工具下 validate 模式逐字节可复现;offline Mutation 必须构建两次 并比较,才能成为 Release Evidence。

3 - 关于 Farrow

简化后的产品模型、实现边界、真机证据、当前限制与发布门禁。
  • 设计:为什么 Farrow 只有一份 Inventory、一套 deployment 与一个固定 IP 网络。
  • 当前状态:严格区分已实现、真机验证与剩余发布门禁。
  • 工程与发布:源码、生成输出、软件包、镜像流水线与证据边界。

3.1 - 设计

Farrow 简化后的单 deployment 架构、网络、状态、安全边界与评审结论。

一个有用的抽象

Farrow 把一份 Pigsty Inventory 启动成一套本地 QEMU deployment。它刻意不再拥有 project marker、项目注册表、租约模型、Provider Layer 或第二种配置格式。

状态位于当前 Unix 用户的 ~/.farrow。产品假设每台电脑只有一套运行中的 Pigsty; 这并不是 root 强制的跨用户单例。

节点级收敛

Farrow 只提取已记录的 VM 与 Pigsty 原生字段,计算逐节点哈希,并保存应用状态与完整 进程身份。新增节点增量创建;up 也会启动选中的已停止节点,运行中同伴不受影响; 变更需要显式节点重建; 配置缺席永远不授权删除。

运行时选择

Guest 架构是部署级期望状态。省略或 native 跟随宿主;显式 amd64/arm64 会准确 选择对应 Catalog 工件。HVF/KVM 原生加速仍是默认路径;外来架构或 Catalog 已知的 镜像/宿主不兼容规则才会选择固定 TCG Profile。没有用户可传的 Accelerator 参数,也不会 因任意原生失败静默回退。

实际架构与加速器保存在每个 QEMU Invocation 中,并通过 status 展示。执行破坏性 recreate 前,Farrow 会证明所选 QEMU 二进制与版本、网络后端、镜像字节、启动模式与固件。 以后若新二进制改变运行时策略,也不能把新旧节点混跑:Runtime Drift 必须整体重建。

双网卡与一个固定子网

管理网卡负责 DHCP、DNS、出网与回环 SSH;固定 IP 网卡负责宿主、节点间与 Ansible 流量。macOS 使用 socket_vmnet;Linux 优先跟随当前 NetworkManager,否则使用 systemd-networkd,并通过发行版 bridge helper 接入。若 networkd 尚未启动,只有在 Activation-safety 扫描证明现有 Unit 不会接管真实宿主链路后才启动。

Debian helper 会临时、可逆地限制给调用者真实加入的组。setup 必须通过一次非特权 QEMU bridge smoke;失败后按 manifest 自动回滚。

安全边界

QEMU 与所有 Guest 工件都以调用者身份运行。root 仅用于宿主网络与可选 hosts publisher。 销毁必须同时匹配属主、路径包含、节点身份、QMP/进程身份与工件白名单;任何歧义都会停止。

评审结论

对单实验室产品而言,删除 project 与 lease 的 pivot 是正确的,显著降低了认知与状态 复杂度。但真机审查仍不可省略:第一版在控制节点密钥、sudo 策略、Debian helper 权限、 NetworkManager 验证、运行时 preflight、结果消息与失败清理上存在跨层断裂。这些路径已修复, 并在 macOS 与 Linux 真机重放后才重写本文档。后续对抗审查又在 EL7/EL8 提交前发现并 修复了破坏前预检顺序与签名 Catalog 基线升级问题。

3.2 - 当前状态

当前简化源码已经通过哪些真机验证、哪些仍未验证、什么阻塞 1.0。

Farrow 仍是 pre-1.0。源码测试、带日期的真机重放、软件包、发布、CI 与线上站点是不同门禁。

最近一次有记录的真机重放:2026-08-27

该矩阵只属于当天真正执行过的准确 Checkpoint;后续源码或文档修改不会自动继承真机证明。

宿主 路径 结果
macOS 26.6.2 arm64 HVF、QEMU 11.1、socket_vmnet 单节点与增量四节点通过
Ubuntu 26.04 amd64(mx KVM、QEMU 10.2.1、NetworkManager setup、单节点、增量四节点与卸载通过

两台宿主均通过固定 IP、SSH readiness、默认 CPU/内存/根盘/数据盘、cloud-init、 stop/start、跨目录操作、扩容时控制节点 boot ID 不变、控制节点横向 SSH、忽略未消费的 Pigsty 变更、配置缺席不删除、显式 destroy。

Linux 还验证了 NOPASSWD 自动化、调用者可用的 Debian helper 权限、非特权 bridge smoke、 四个 tap 挂接时拒绝卸载,以及 destroy 后精确恢复宿主状态。

交互式宿主网络与 hosts 命令现在会自行调用 sudo,外部 sudo -v 只是可选优化。 Darwin 的 network.json 丢失时,也可用字节一致的接口双份证据、准确 launchd plist 与 已安装二进制摘要重建仅用于卸载的归属计划。

2026-08-28,校准后的工作树通过 unit、race、vet、staticcheck、govulncheck、四平台交叉 构建、模拟镜像流水线边界、许可证校验与 GoReleaser 配置校验。隔离的本地 GoReleaser Snapshot 还构建并验证了四个平台归档、两个架构的 DEB/RPM、SPDX、Checksum、依赖、权限 以及归档/软件包一致性。没有发布任何产物;这些结果也不会扩展本真机矩阵。

EL7/EL8 兼容性:2026-08-28

Commit 7c666c7 在两轮独立 Claude Code Opus 5 max 对抗审查后恢复 EL7/EL8。第一轮因 破坏前运行时预检顺序与签名 Catalog 基线迁移问题给出 BLOCK;修复并补回归测试后,第二轮 给出 PASS,且没有 Required Fix。

Catalog 2026082801 已在开发仓库签名激活:9 个 Family、17 个镜像工件;包含两份 socket_vmnet Archive 在内的 19 个 Repository Payload 均重新通过完整 SHA 校验。干净客户端 接受了公开签名与准确嵌入摘要。

隔离的 macOS arm64 生命周期重放用内置 TCG 兼容规则启动 Rocky Linux 8.10 arm64, stop/start 后 44.2 秒达到 readiness,并验证 NetworkManager、固定 IP/无路由/无 DNS、 dba UID/GID 88 与 generation/spec marker。EL7 字节、qcow2、BIOS 布局与 4K XFS Root 已验证;当前 Linux/amd64 原生 Farrow 生命周期仍待重放。

仍未完成

  • EL9 + NetworkManager + firewalld 真机重放;
  • 当前 systemd-networkd 重放;
  • 宿主重启持久性;
  • macOS amd64 与 Linux arm64 真机;
  • 当前 Linux/amd64 原生 EL7 生命周期;
  • 当前 9p share 重放;
  • 完整的 Pigsty configure → farrow up → install.yml
  • 公开 Homebrew/DEB/RPM 安装与发布 CI。

当前镜像仍为 testing,只有 EOL EL7 是 deprecated。active/standby Catalog 公钥已经 内置,但镜像仓库仍需迁离开发宿主,私钥托管/轮换与 Release 职责也必须在 1.0 前正式落实。

3.3 - 工程与发布

源码边界、构建测试门禁、镜像归一化、发布输出与证据纪律。

仓库边界

Farrow 源码仓库只保留代码、测试、构建/打包定义、法律声明与简短入口 README。本网站是 用户、设计、运维与发布文档的唯一权威位置。原始 Review 记录、历史 Scratch Inventory、 Demo 目录、生成二进制与 Release 输出树都不是源码输入,不应提交。

以下输出随时可重建:

  • bin/:开发构建;
  • dist/.goreleaser-*:Release/Snapshot Staging;
  • 根目录 farrowfarrow-hosts-helpercatalogsign 二进制;
  • Hugo 的 public/resources/

构建与源码门禁

make build
make test
make race
make vet
make staticcheck
make vuln
make cross-check
make image-pipeline-test
make license-check

make check 汇总这些门禁。源码绿色不等于真机验证;macOS HVF、Linux KVM/网络、软件包 消费、Release 发布与线上渲染仍是不同门禁。

Release 与软件包契约

packaging/.goreleaser.yaml.github/workflows 属于源码;它们生成的目录不是。 Archive 与 Linux Package 只携带匹配二进制、LICENSE、精简源码 README、 构建元数据,以及根据 go.mod 锁定模块版本重建的准确上游许可证字节。生成的许可证文本 在 Archive 中位于 licenses/,不作为源码跟踪。详细文档留在版本化网站,不再复制到每份 二进制 Payload。

构建成功绝不代表发布。Commit、Tag、Archive/Package、签名/证明、上传、CI 与公开消费是 彼此独立的门禁。

镜像归一化

packaging/image-pipeline/ 只接受显式本地 qcow2,不下载也不上传。它复制并哈希源文件, 强制 qcow2 解析,拒绝 Backing/External/Encryption/未知 Feature,运行 qemu-img check, 并可在显式 QEMU Sandbox 中做无网络 Offline Guest Mutation。UID/GID 88 冲突会拒绝, 不会含糊改写。

Catalog 逐字节导出命令:

go run ./tools/catalogexport /absolute/new/catalog.json

导出器原子且绝不覆盖。Catalog 签名与应用 Release 签名使用不同密钥与信任域。

证据纪律

历史 M0–M4 记录在实现期有价值,但不是产品文档。可长期保留的结论已收敛到设计当前状态。后续源码修改不会自动继承真机证明;每条状态结论都应说明日期、宿主、 路径与剩余门禁。