这是本节的多页打印视图。 .
设计注记
- 1: 为什么 Barn 没有 Project
- 2: 为什么每个 Barn 节点都有两张网卡
- 3: 声明式不等于破坏式
- 4: PID 不是虚拟机身份
- 5: repo.yaml 是意图,catalog.json 是证据
Barn 源码仓库曾经把重构指令、实现期 ADR 与真机证据和代码放在一起。它们在产品快速变化时 很有价值,但其中不少早期结论后来已经被推翻。本栏目只保留仍然成立的设计理由,并以当前 源码重新表述,而不是把过时计划原样发布。
建议从产品模型开始,再沿着边界向外阅读:
- 为什么 Barn 没有 Project:一份 Inventory、一个 Owner-scope Deployment,不制造第二份事实。
- 为什么每个节点都有两张网卡:实验室固定身份与管理出网分离。
- 声明式不等于破坏式:逐节点 Drift、显式重建与删除。
- PID 不是虚拟机身份:QMP 身份、进程证据、Journal 与有界恢复。
repo.yaml是意图,catalog.json是证据:生成元数据必须与 实际 qcow2 字节一致的静态镜像仓库。
当前行为以文档为准,带日期的验证边界见当前状态。 这些设计记录解释契约为何存在;它们不会把设计、构建或本地测试升级成发布证据。
本组文章保留原始写作日期,于 2026-09-26 对照源码校准,并于 2026-09-29 同步 Barn 0.9.0 更名。涉及未发布候选的 变化会单独标记;历史验证结果仍以原有日期和范围为准。
1 - 为什么 Barn 没有 Project
2026-09-29 更名: Barn 0.9.0 尚未发布;本文名称已同步更新。2026-09-26 校准记录: 保留原始写作日期;下文已按当前实现更新。公开版本与未发布候选的 边界见当前状态,不以本文日期代替发布或验收日期。
Barn 最初采用了一套很熟悉的虚拟机管理器抽象:工作目录就是 Project,隐藏 Marker 提供 身份,注册表负责重新发现 Project,宿主全局 Lease 防止它们争用私有网络。这种模型可以承载 多套彼此独立的虚拟机,但它并不适合 Barn 最终要成为的产品。
Barn 不是通用 Hypervisor 前端,而是一套本地、固定 IP 的 Pigsty 实验室。操作者本来就有 一份完整描述:Pigsty Inventory。再加入第二份 VM Manifest 与第二套 Project 身份,只会让 每个普通问题变复杂。
决策状态:当前有效。 本文解释产品模型;当前文件名、字段与命令以 配置参考为准。
旧抽象会把普通问题转化为 Project 管理问题:
- 节点名称和地址究竟以哪份文件为准?
- 移动目录代表移动实验室,还是创建新实验室?
- Marker 还在、注册表丢了怎么办?
- 目录消失代表废弃 Project,还是移动硬盘暂时没有挂载?
- 唯一的宿主私有网络归哪个 Project 所有?
这些都是合理的多 Project 问题。Barn 的选择是不再制造它们。
一份 Inventory 已经足够
交给 Pigsty 的 Inventory 同时就是 Barn 的期望状态。Barn 只读取一个很小、明确记录的
边界:Host 地址、少量 Pigsty 原生身份字段,以及 vm_* 命名空间。命名空间内部严格校验,
Inventory 的其余部分保持不透明,原样留给 Pigsty。
这种不对称很重要。vm_mem 拼错必须报错,因为它会改变 Barn 创建的机器;新增一项
PostgreSQL 调优参数却不应该因为 VM 层从未见过而失败。于是同一份文件可以继续作为 Pigsty
Inventory 演进,而不会暗中变成第二种 Barn 配置格式。
命名遵循同一原则:优先使用 nodename,其次按 Pigsty Cluster/Sequence 稳定派生,最后才
回退到地址尾段。Barn 不再增加一个可能与 Pigsty Hostname 冲突的 vm_name。
一个 Owner-scope 状态根
应用状态位于 BARN_HOME,默认是 ~/.barn。工作目录里没有 Marker,也没有按目录维护
的注册表。只读取应用状态的命令可以从任何目录运行;提出新期望状态的命令才需要发现或显式
接收 Inventory。
这里的“一个 Deployment”是 Owner-scope,而不是 root 强制的整机单例。每个 Unix 用户拥有 独立状态根。Barn 面向可信开发工作站,不承诺共享服务器上的敌对用户仲裁。
这项简化带来直接结果:
- 移动或重命名源码目录不会改变 Deployment 身份;
- Inventory 丢失不会擦除已经应用的状态;
- 清理通过显式生命周期命令完成;删除状态目录不能替代停止 VM 或移除托管集成;
- 镜像缓存、密钥、节点、磁盘、锁与 Deployment 状态集中在同一个可检查的 Home 中; 短 QMP/PID 路径、SSH 客户端集成与宿主全局网络仍有各自的托管位置,完整清理见 卸载。
配置缺席不是操作意图
单 Deployment 并不意味着 Inventory 可有可无,而是让 Barn 可以区分“期望配置”与“已应用 证据”。需要期望状态时,命令契约允许的场景可以回退到已有 Deployment 的 Applied Spec; 文件缺失永远不会被理解成删除节点的请求。
这条规则贯穿生命周期的每一层:规划与删除必须显式, 恢复流程也会保留有歧义的资源,而不是猜测用户意图。
这是刻意接受的取舍
Barn 不支持同一用户同时运行多套 Deployment。Project、注册表与地址级 Lease 不是藏起来 等待未来开启的功能;它们被明确否决,因为会重新引入产品刚刚删除的抽象。
如果需求变成多租户或多宿主编排,那已经是另一个产品边界。对本地 Pigsty 实验室而言,一份 Inventory 与一个 Deployment 能让地址、属主、Drift、恢复和清理都更容易解释,也更容易证明。
下一篇:为什么每个 Barn 节点都有两张网卡。
2 - 为什么每个 Barn 节点都有两张网卡
2026-09-29 更名: Barn 0.9.0 尚未发布;本文名称已同步更新。2026-09-26 校准记录: 保留原始写作日期;下文已按当前实现更新。公开版本与未发布候选的 边界见当前状态,不以本文日期代替发布或验收日期。
Pigsty Inventory 用稳定地址标识机器。PostgreSQL 复制、etcd 成员、HAProxy 后端、VIP、
监控目标与 Ansible 都假设 10.10.10.11 始终代表同一个节点。回环端口转发可以把 SSH 或
PostgreSQL 暴露给宿主,却无法把这种网络身份提供给其它节点。
因此 Barn 不让用户在“方便的 NAT 模式”和“高级固定网络模式”之间二选一。每个正常节点 同时获得两种能力,并由两张网卡分别承担。
一张网卡不该承担两项冲突职责
| 网卡 | 地址方式 | 职责 |
|---|---|---|
| 管理网卡 | QEMU User-mode NAT、DHCP | DNS、默认路由、互联网出站与回环 SSH 备用路径 |
| 私网网卡(按 MAC 匹配) | Inventory 固定地址 | 宿主到节点、节点间、Ansible、Pigsty 服务与 VIP 流量 |
Barn 使用确定的 MAC 地址匹配两张虚拟网卡,不再修改它们的名称。Guest 中看到的名字由镜像
自身的网络栈决定(通常是 eth0 或 enp0s4);网卡角色由 MAC 与地址契约决定,而不是显示名称。
管理网卡刻意保持普通:一张新的 Cloud Image 在应用尚未安装前就能访问软件仓库,宿主无需 安装 NAT 规则或 DHCP 服务。
私有网卡使用一个确定的 RFC1918 地址,没有默认路由,也没有 DNS。客机初始化会检查
这些属性,但从 0.7 起,私网检查属于可选步骤:失败时记录 private-network 警告,
管理 SSH 与客机身份可用时仍可达到就绪。因此操作成功时,固定 IP 连通性仍可能受限。
部署依赖该网卡的服务前,应检查警告并测试相应宿主/节点间连接,修正原因后重复 up。
决策状态:当前有效。 这套拓扑属于 Barn 的正常生命周期,并不是可选的 “Private Mode”。当前平台边界见设计参考。
地址规划归 Inventory 所有
所有受管 Host 位于同一个规范 RFC1918 /24:
| 范围 | 含义 |
|---|---|
.1 |
宿主侧私有网络地址 |
.2–.8 |
保留边界,包括有效的二层 VIP 空间 |
.9–.254 |
节点固定地址 |
Guest 私有网卡不请求 DHCP:cloud-init 直接得到 Inventory 已声明的准确地址。macOS
vmnet 配置的 DHCP 范围止于 .8,受管节点从 .9 开始;Linux 使用桥接与 Guest 静态地址。
因此 VM 地址契约不依赖租约数据库,Ansible 从第一次连接到后续部署始终使用同一地址。
对于自动生成的配置,如果默认子网被占用,setup 可以从一组有限候选中选择空闲网段;显式 提供的 Inventory 绝不会为了绕过冲突而被静默改写。宿主接口、所有节点、Pigsty 地址与别名 必须对同一个子网达成一致。
后端因平台而异,Guest 契约保持一致
Guest 在所有支持宿主上看到相同拓扑,Barn 则跟随宿主真正的网络管理者:
- macOS: 固定版本的
socket_vmnet服务提供私有链路。Host Mode 默认,Shared Mode 必须显式选择;QEMU 仍以普通用户运行。 - NetworkManager 活跃的 Linux: Barn 通过
nmcli创建自有barn0Bridge, 并与活跃的 firewalld 策略配合。 - systemd-networkd 管理的 Linux: Barn 安装自有 Unit,并借助发行版
qemu-bridge-helper保持 QEMU 非特权。 - networkd 尚未启动: 只有预变更扫描能证明现有 Unit 不会接管真实宿主网卡时,才允许 激活它。
同时支持两种 Linux 管理器不是为了抽象而抽象。如果只因为 Barn 会写 .network 文件,就在
桌面或 RHEL 家族宿主上启动 networkd,可能破坏宿主真实网络;后端必须服从当前已经负责网络
的组件。
宿主网络是一项事务
Bridge 或 vmnet Daemon 会跨越一次 CLI 进程,也会跨越特权边界,因此 Barn 把安装视为 可逆宿主事务:
- 检查 Route、Interface、Service、属主与已有状态;
- 修改前打印准确计划;
- Apply 前立即重新检查前置条件;
- 用 root-owned 状态记录 Barn 创建了什么、此前存在什么;
- 证明普通用户 QEMU 确实可以接入;
- 全部 Readiness 检查通过后才接受安装。
一个碰巧占用相同 .1/24 的外部接口不会被接管;已经变化的自有文件不会被覆盖;Uninstall
会在已记录节点仍运行时拒绝,并且只恢复 Manifest 明确记录的前态。失败意味着停止,而不是
授权程序删除挡路的任何东西。
接受的取舍
Guest 互联网流量经过 QEMU User-mode Network。这不是理论上最快的转发路径,但它让普通出网 保持非特权且跨平台。真正影响 Pigsty 实验室的流量——宿主到 Guest、复制、服务调用,以及从 控制节点分发软件包——都留在私有链路上。
最终形成一个清晰的职责分离:管理网卡让机器容易 Bootstrap,私有网卡让它成为地址稳定的 实验室成员,两者都不需要假装成对方。
下一篇:声明式不等于破坏式。
3 - 声明式不等于破坏式
2026-09-29 更名: Barn 0.9.0 尚未发布;本文名称已同步更新。2026-09-26 校准记录: 保留原始写作日期;下文已按当前实现更新。公开版本与未发布候选的 边界见当前状态,不以本文日期代替发布或验收日期。
“声明式”常被简化成“让现实等于文件”。在文件完整、分支正确时,这是一句好口号;但当配置 暂时不完整、检出了错误分支,或某个 YAML Group 被误删时,把“缺席”理解成“删除”就会让普通 编辑错误直接变成破坏操作。
Barn 采用一条更窄的规则:
期望状态可以授权创建,也可以描述 Drift;它永远不能通过省略来授权销毁。
这对 VM Runtime 尤其重要。Root Disk、Data Disk、SSH Key 与本地证据并不是无状态副本。 重建可能是正确选择,但必须是操作者能看见并明确作出的决定。
从 Inventory 得到节点身份
Barn 不会对整份 Pigsty Inventory 做哈希。它先提取自己拥有的字段、填入默认值, 规范化镜像选择器与架构,再构造 Canonical Resolved Spec。精确 Catalog 工件另行解析, 因此 Channel 更新本身不会改变节点的 Spec Hash。每个节点的哈希只包含:
- 所有节点共享的 Deployment Envelope,例如子网、登录用户、架构策略与部署级默认镜像请求;
- 该节点自己的完整 Resolved Definition。
因此,增加一个同伴不会改变已有节点的哈希;修改 Barn 不消费的 Pigsty 字段——例如 PostgreSQL 版本、软件包或服务策略——也不会产生 VM Drift。VM 层只响应自己真正理解的契约。
这也避免了一项危险的半承诺:Barn 不假装实现完整 Ansible 变量系统。自有命名空间里的未知
vm_* 字段与冲突值会失败;记录边界之外的内容保持不透明,而不是只解释一半。
决策状态:当前有效。 Barn 自动收敛新增节点,但定义变更与删除都需要显式命令。 命令流程见日常管理。
Plan 只有五种结果
barn plan 对比期望状态、Applied Deployment State 与已提交的 Node State,结果刻意保持精简:
| 结果 | 含义 | 应用路径 |
|---|---|---|
| create | 期望节点没有已提交状态 | barn up 创建 |
| unchanged | 定义与运行时仍一致 | 运行中同伴不动;已停止节点可以启动 |
| recreate | 节点定义发生变化 | 显式 barn recreate --force <node> |
| missing | Applied Node 在 Inventory 中缺席或被跳过 | 显式 barn destroy <node> --force,或恢复配置 |
| envelope drift | 子网、登录身份、架构或运行时策略改变 | 整套 Deployment 重建 |
Plan 完全只读。它列出准确节点集合,并在文本模式中给出应用显式转换的命令。
为什么 up 遇到 Drift 会停下
Barn 可以把 CPU/内存变化认定为“足够安全”并自动应用,也可以在镜像变化时静默重建根盘。
Pre-1.0 刻意不这样做:任何 VM 定义变化都归类为 Recreate,up 返回类型化冲突。
这条保守边界有两个好处:
- 所有可能使 Guest 状态失效的变化共享一个可见操作;
- Barn 可以在触碰当前节点前完成全部前置检查。
Recreate 会先解析 Emulator、加速策略、Firmware、镜像字节、网络后端、Share 与 Persistent Disk 契约,再开始销毁。若外来架构 Emulator 缺失,或一个 Share 不安全,已有 VM 会保持原样。
为什么 Missing Node 会阻止收敛
节点从期望状态中消失,可能来自许多并不代表删除意图的原因:
- 调试时打开了一份缩减 Inventory;
- Group 被重命名或过滤;
vm_skip暂时标记一台真机或外部节点;- Merge Conflict 丢掉一段 YAML;
- 配置文件本身暂时不可用。
Applied State 仍包含这种节点时,up 会停止并点名报告。操作者必须恢复定义,或运行显式
Destroy 命令。这比自动垃圾回收多一点摩擦,却比恢复被意外删除的磁盘少得多。
Persistent Data Disk 还有独立边界:普通 Destroy 会保留它们;
整套部署的 destroy --delete-persistent 显式包含受管持久盘和已保留的磁盘,
不接受节点选择器;同时删除 Deployment Key
则需要整部署的 destroy --purge 或 purge。保留不是备份保证:Guest 初始化可能重置
无法识别或确认损坏的测试文件系统,包括持久盘,详见
数据盘。一次确认不能静默扩张成更宽的授权。
收敛仍然是增量的
安全并不意味着全部重建。新增节点创建时不会停止已有同伴;选中的已停止节点可以直接启动, 不会重建运行中节点;逐节点 Recreate 保留其它节点,并按磁盘契约保留 Persistent Data。
最终,Barn 在期望状态足以构成强证据的地方——创建与比较——保持声明式;在代价不可逆的 地方保持显式。它不会让操作者手工计算 Drift,也不会把 Diff 错当成权限。
下一篇:PID 不是虚拟机身份。
4 - PID 不是虚拟机身份
2026-09-29 更名: Barn 0.9.0 尚未发布;本文名称已同步更新。2026-09-26 校准记录: 保留原始写作日期;下文已按当前实现更新。公开版本与未发布候选的 边界见当前状态,不以本文日期代替发布或验收日期。
Pidfile 只能回答一个问题:写入文件时,某个进程使用了哪个整数。它不能证明进程仍然存活, 不能证明 PID 没有被复用,不能证明可执行文件就是 QEMU,也不能证明这个 QEMU 正是操作者 想停止的节点。
这些证据不足以授权 SIGKILL,更不足以授权删除 Root Disk。
Barn 把身份视为一条由独立证据组成的链。每一环承担不同职责;只有操作所需的证据全部一致, 破坏性动作才可以继续。
QMP 是主要运行时身份
每台 VM 都有生成的 UUID 与预期 QEMU Name。启动后,Barn 连接 QEMU Machine Protocol Socket,并向 QEMU 查询这两个字段。仅仅因为进程启动命令返回,或某条 Socket 路径出现,并不 代表 VM 已经启动;QMP 必须报告预期 Name 与 UUID。
同一检查也保护关机。如果 QMP Endpoint 返回另一个 Name 或 UUID,它不会被解释成“大概就是 旧 VM”,而是明确的身份不匹配;Barn 不会通过它发送任何命令。
QMP 同时提供干净关机路径:请求 Guest Powerdown,等待 Guest;若有界 Graceful Wait 到期,再 要求 QEMU Quit。进程信号只是备用工具,不是主要生命周期 API。
决策状态:当前有效。 本文解释 Fail-closed 生命周期边界。运维恢复应从 故障排查开始,而不是手工删除。
进程身份封住备用路径的缺口
Crash、Runtime Directory 损坏或半完成关机都可能让 QMP 不可用。为此 Barn 会记录一组 进程身份:
- PID;
- 可执行文件路径;
- 进程启动时间;
- 实际命令行的 SHA-256。
完整的类型化 QEMU Invocation 与它一同保存。发送 SIGTERM 前,Barn 会重新读取活进程,
要求整组身份完全匹配;升级到 SIGKILL 前还会再次捕获,专门封住有界 TERM 等待期间产生的
PID 复用窗口。
如果 QMP 仍然可用但某项 QMP 操作失败,Barn 不会绕开活控制平面直接发信号;如果 QMP 报告另一个身份,它会停止;如果进程元组无法验证,它也会停止。“无法证明”本身就是结果, 不是降低检查强度的理由。
未发布的 0.9 候选更新: QMP 不可用、且记录的 PID 已被明确证明属于无关进程时, Barn 把旧 VM 视为已停止,绝不会向那个无关进程发送信号。这与身份不可读或有歧义不同, 后两种情况仍会阻止操作。
Journal 描述 State 提交前的工作
Committed Node State 无法描述创建的最早阶段:Disk 与 Seed 必须先存在,VM 才能启动;进程 必须先启动,身份才能提交。若 CLI 在这个间隔 Crash,就可能留下没有可信 Owner 的工件。
Barn 会先写一份 0600 Prepare Journal,其中包含:
- Operation UUID 与 VM UUID;
- Node Name 与 Resolved-spec Hash;
- 固定 Kind/Path 白名单中的每个已完成工件;
- 准备完成后的类型化 QEMU Invocation;
- Commit 成功后的准确 Node-state Path。
Journal 是严格的版本化 JSON。未知字段、无效 UUID、不安全路径、重复工件、错误 Mode、Symlink, 或逃出 Node Directory 的路径都会使它无效。
于是恢复流程可以回答一个边界明确的问题:这次尚未提交的操作创建了哪些工件? 它不需要 扫描目录后猜测。
Rollback 比 Cleanup 更窄
只有在 Committed Node State 不存在,并且类型化 Invocation 对应的 QMP Socket 与 Pidfile 都不存在时,才允许 Offline Rollback。Node Directory 里只能出现 Journal 与已完成白名单工件; 随后按逆序移除已完成工件,再移除 Journal 与空节点目录。
未发布的 0.9 候选更新: 首次 up 失败后,即使已经修改 Inventory 也可以重试。
安全清理按 Journal 的已完成工件列表执行,不再要求新期望配置与失败时的旧配置一致。
已提交节点绝不会因为旧 Prepare Journal 被回滚;已有磁盘不会被补进 Action List;未知文件 会阻止目录删除,而不是作为附带损失被一扫而空。
普通 Destroy 采用同样思路:证明路径包含、文件类型、属主边界、进程已经死亡,以及准确工件 集合。Persistent Disk 有独立保留与 Purge 规则。只有已知文件全部移除后才删除目录,所以任何 未知条目都会变成错误。
原子状态让证据持久
状态更新使用同目录临时文件、fsync、原子 Rename 与父目录 fsync,并拒绝 Symlink Target;
Deployment 与 Node Lock 串行化修改。目标不是让 Crash 永不发生,而是保证 Crash 后留下的要么
是旧的完整事实,要么是新的完整事实,再加一份描述两者之间有界阶段的 Journal。
这套设计刻意保守。它有时会要求操作者检查一个更激进工具可能直接删除的歧义资源。对本地 数据库实验室而言,保留证据是更安全的失败方式。
5 - repo.yaml 是意图,catalog.json 是证据
2026-09-29 更名: Barn 0.9.0 尚未发布;本文名称已同步更新。2026-09-26 校准记录: 保留原始写作日期;下文已按当前实现更新。公开版本与未发布候选的 边界见当前状态,不以本文日期代替发布或验收日期。
静态镜像仓库看起来只是一些 qcow2 文件加一个 JSON 索引。真正困难的问题是:哪些事实允许 维护者手写,哪些事实必须从即将发布的字节中推导。
如果 Checksum 与 Size 放在手写源文件里,它们很容易被错误复制;如果策略只存在于生成 JSON 中,审查 Channel 变化或弃用决定就要阅读机器输出。Barn 把这两项工作明确分开。
repo.yaml:维护者表达什么意图
源码控制的 repo.yaml 记录作者意图:
- 仓库 Revision 与默认选择;
- Image Family 与 Alias;
stable等可移动 Channel;- Exact Version 与 Architecture;
- Boot Mode 与支持状态;
- Immutable Upstream 与 Provenance 说明。
它刻意不包含生成的 Artifact Size、SHA-256 或 Virtual Size。一条简洁配置可以表达
d13:stable 指向某个准确版本,并提供 amd64/arm64 Variant,而不假装知道只属于文件本身的事实。
下面保留的历史策略片段只演示格式;完整可用示例见镜像仓库,
当前版本以镜像参考为准:
这是适合 Review 的层:Pull Request 可以清楚展示 Channel 移动、Version 弃用或 Provenance 描述变化。
catalog.json:仓库能够证明什么
catalog.json 把策略落实到本地仓库。每个 Variant 都包含准确文件名、字节数、SHA-256、
qcow2 Virtual Size、Boot Contract、Source User 与 Immutable Upstream Provenance。
文件名、字节数、摘要与虚拟大小由工具物化并对照工件检查;启动模式、源用户、状态与溯源
则来自 repo.yaml 中经过校验的策略,文件检查本身不能独立证明这些声明。
Build 会强制解析 qcow2,拒绝 Backing File、
External Data、Encryption 与未知 Incompatible Feature,执行结构检查后才原子替换 Catalog。
Artifact 身份是 (image, exact version, architecture) 三元组,而不是选择它的 Channel。
文件保持可读、不可变的名字:
可读文件名是一项运维能力:管理员可以用普通文件系统工具检查、镜像或恢复仓库。完整性仍来自 生成元数据与验证,而不是相信名字。
三个操作,三种职责
仓库 CLI 把观察、生成与证明分开:
| 命令 | 职责 |
|---|---|
barn repo scan |
只读报告 Tracked、Missing、Untracked 与 Unsafe Artifact |
barn repo build |
校验 Source 与 Artifact,再原子生成 Catalog |
barn repo verify |
在内存中重新物化,并要求与已发布 Catalog 逐字节一致 |
build 永远不修改 repo.yaml 或 qcow2 字节。verify 比“每个 Checksum 都正确”更强:它还能
证明没有任何源策略或工件变化被漏出生成 Catalog。
发布遵循同一方向:先上传不可变镜像字节,最后发布 Catalog 与匹配签名,尽量一起切换 这两个文件。部分上传造成正文与签名不匹配时,客户端会拒绝;先工件后目录则避免声明 仍在传输中的镜像字节。
Selector 可以移动,Artifact 不能
人工配置需要方便的 Selector。随着仓库演进,d13:stable、el9@9 与 [email protected] 可以解析到
更新的准确版本。数字前缀按点分组件的整数比较,因此 9.10 排在 9.9 之后。
解析完成后,客户端保存准确 Version、Architecture、Size 与 Digest。一个已经解析的节点不会 因为 Channel 移动就变成另一台机器。便利只存在于选择阶段,不可变身份存在于执行阶段。
传输与信任是两个问题
官方 Catalog 与普通 HTTP Catalog 必须具有受信 Detached Signature。操作者显式选择本地目录 或 HTTPS Repository 时,可以使用 Unsigned Catalog,因为本地属主或认证传输本身就是显式 信任决策。即使 URL 是 HTTPS,隐式 Compiled Default 仍属于签名信任域。
Accepted Catalog State 按 Repository 独立记录。Barn 会拒绝未知 Key、低于该仓库 High-water Mark 的 Revision,以及同 Revision 不同字节。显式 Downgrade 可见且只影响选定 Repository; 重置到 Embedded Catalog 也不会擦掉防回滚记录。
接受 Catalog 只是前半程。每次 Pull 仍会检查 Byte Count、SHA-256 与 qcow2 结构。通过验证的 Base Image 变为只读,Node Root Disk 使用 Overlay,因此普通 VM 写入永远不会修改受信 Base。
不同信任域保持分离
Image Catalog Key 授权镜像策略;Release Signing 证明 Barn 应用工件与 Checksum Manifest。 两组 Key 刻意独立:有权发布 VM Image 不应自动获得发布 Barn Binary 的权限,反之亦然。
普通 Public Build 默认使用 https://repo.pigsty.io/barn,并通过 --mirror 显式选择
https://repo.pigsty.cc/barn;--repo 仍是自定义覆盖。自 0.7.0 起的更新: 两个
官方仓库在下载镜像时可以互相回退,始终校验同一 Catalog 的尺寸与 SHA-256。自定义仓库
仍是唯一工件源,Catalog 更新仍使用选定来源;Embedded Catalog 的 Upstream URL
只提供溯源,绝不会变成工件回退。源码配置、生成
Catalog、上传 Artifact、签名与公开可用性仍是彼此独立的发布门禁。
更大的设计原则是:策略应当便于人类审查,而关于已发布字节的事实必须可生成、可复现,并能 被独立验证。