替换平面仓库的元数据生成工具,同时保留发布时间、签名,以及与已有元数据缓存客户端的兼容性。
这是本节的多页打印视图。 .
教程
- 1: 搭建 YUM 仓库
- 2: 迁移已有 YUM 仓库
- 3: 搭建 APT 仓库
- 4: 仓库签名
- 5: 服务与发布仓库
- 6: 演练构建 pigsty-infra 仓库
这里的教程涵盖新建 Managed 工作区与迁移已有 Plain 仓库。请按顺序执行命令,并按你的环境 替换大写占位符与包路径。
托管 RPM 仓库:分架构视图、noarch 中性投影、debuginfo 过滤、版本数量上限,以及可用的 dnf 客户端配置。
托管 DEB 仓库:Debian 风格包池、by-hash 索引与 deb822 客户端配置。
生成专用 GPG 签名钥,为仓库元数据与 RPM 包签名,并配置客户端拒绝一切未签名内容。
用 Nginx 服务 Repository,并把已校验 Generation 发布到配置好的 filesystem target, 同时避免暴露工作区私有状态。
把 infra-pkg 已产出的双架构 RPM 与 DEB 组织成真实仓库,并演练本地安装、滚动更新、 Stable 晋升与月度快照。
先看哪篇
| 你的处境 | 从这里开始 |
|---|---|
| 已使用 createrepo_c 维护平面 RPM 目录 | 迁移现有 YUM 仓库 |
| 你要向 dnf 客户端分发 RPM | 搭建 YUM 仓库 |
| 你要为 Debian 或 Ubuntu 分发 DEB | 搭建 APT 仓库 |
| 需要已签名元数据或已签名 RPM 包体 | 仓库签名 |
| 树已经建好,但外部无法访问 | 对外服务 |
| 想把现有双架构包池变成可维护的 Infra 仓库 | 演练构建 pigsty-infra 仓库 |
YUM 与 APT 两篇是彼此独立的全新 Workspace 路径。实际使用中,如果它们适合共用同一所有权 边界,一个 Workspace 的同一 Repository 可以同时容纳 RPM 与 DEB Dist。
本板块约定
Shell 代码块里的命令不带 $ 提示符,方便整块复制。输出单独成块放在命令下方,只有一行时用注释
标注。需要你自行替换的值一律写成 大写。
每篇教程都有验证步骤。Managed 模式通过 sow check 返回 0,确认所选 Repository 完整且
与记录的 Generation 一致。Plain 模式按迁移指南验证元数据、签名和真实客户端行为;
sow check 不用于检查平面目录。
1 - 搭建 YUM 仓库
本教程从零创建一个 Managed RPM 仓库。你需要一个可写目录,以及一个或多个 RPM 文件。
1. 创建工作区
Dist 名称由你定义。SOW 不会根据 el9 推断操作系统版本。
2. 配置成员策略
编辑生成的 sow.yml。下面的配置按包名与架构各保留一个版本,并排除调试包:
手工修改配置后,先校验再写仓库状态:
策略先执行 exclude,再执行 limit。noarch 包会投影到每个启用的架构视图,不能写进
architectures。
3. 添加 RPM
add 解析包头,将每个接纳的包只保存一次,更新 Desired 成员关系并落成新 Generation。
被策略排除的输入会逐项报告,但不算命令失败。
公共树如下:
rpm-md 的 location href 通过相对路径访问根目录下的 pool/。不要只复制某个架构目录;
它不是独立仓库。
4. HTTP 预览
本地预览可以直接使用:
在另一个终端检查入口:
长期服务应使用持续维护的 HTTP Server。它必须完整暴露 pigsty/ 树,确保客户端解析后落到
pigsty/pool/ 的软件包 URL 可访问。
5. 配置 dnf
将 REPO_HOST 替换为客户端可访问的地址:
刷新并查询仓库:
这里有意使用未签名配置。只有完成仓库签名后,才应打开客户端验签。
6. 发布或导出
交付前必须通过深度校验:
向已配置的 filesystem 或 R2 目标交付时,使用 sow publish。
只有先复制到离线 staging、再原子切换上线时,才适合整根复制;不要对在线仓库做无序原地同步。
默认 dnf reposync 等工具会拒绝指向根包池的父级相对路径。遇到这种消费者时,导出一份
自包含 RPM Leaf:
目标目录必须不存在或为空。默认会复制包体;--hardlink 只适用于同一文件系统、可信且只读的
显式优化场景。
更新仓库
add 与 rm 修改 Desired 成员关系;策略或签名配置变化后用 build 收敛;发布门禁是
check,不能只看 status。
自动化客户端与平台覆盖见平台与集成。
2 - 迁移已有 YUM 仓库
本指南适用于 RPM 与 repodata/ 放在同一层目录的平面仓库,例如此前用 createrepo_c
维护的仓库。它使用 Plain sow create,不创建 Managed 工作区。发布时间参数是
SOW 0.5.0 新增功能,请使用该版本或更新版本。
1. 明确迁移范围
在候选副本上操作,并完整保留旧软件包与元数据备份。可能重签的 RPM 不要用硬链接复制。 先确认真正使用的二进制:
帮助中必须包含 --metadata-timestamp;正式版 0.4.0 不接受该参数。
| 检查项 | 需要明确的选择 |
|---|---|
| 软件包布局 | Plain 只读取顶层普通 RPM;嵌套目录需要单独规划迁移 |
| 客户端功能 | Plain 生成 primary/filelists/other XML,不生成 SQLite 数据库或模块流 |
| 包信任 | 保留合法上游签名,或明确换成自己的密钥 |
| 索引信任 | 客户端启用 repo_gpgcheck=1 时,单独签署并验证新 repomd.xml |
| 已有客户端 | 保留旧缓存,使用原来的 URL 和 repo ID 验收 |
在存在模块过滤的环境中,为普通 RPM 保留适当的 module_hotfixes=1 策略。这不会恢复
dnf module install 所需的模块流或 profile。
2. 保留发布时间历史
EL7 YUM 可能拒收 data 最大时间早于缓存的索引。检查当前 repomd.xml 与可信旧副本中的
<data><timestamp>,取客户端可能见过的最大值。如果在线索引此前已被写成零,只看这个
零值无法恢复历史。revision 和文件 mtime 不能替代该记录。
维护脚本应在同一个仓库锁内操作,并在上传目录外保存历史最大发布时间。下面的 +1 是区分新内容的
发布策略;EL7 本身也接受相等时间。真正产生新一代内容时,选择:
在切换公开索引之前持久保存该值。发布失败可以消耗一个时间值,跳号没有问题。恢复旧内容,或把 同一公开 URL 对应的本地目录移到新位置时,也必须保留这份时钟。
内容不变时,维护脚本可以在检查完整元数据内容身份、引用文件校验和以及签名后,复用旧索引与
分离签名。零时间或已经倒退的时间仍需修复。每次直接调用 create 都传入当前时间,会让索引
每次变化,从而失去空跑不写文件的效果。
3. 构建并签署候选
下面演示一次重建。先准备独立的 /srv/yum.candidate 副本,将 HISTORICAL_MAX 设为从当前
索引、持久时钟和可信历史中核实的最大值,将 SIGN_KEY 设为元数据签名密钥的完整指纹。
示例用 Python 3 选择严格递增的时间:
这段命令只生成候选,不会保存持久时钟或发布目录。切换线上内容前,还要由维护系统持久记录
PUBLISH_TIME。验签应绑定预期公钥,不能只判断大信任库里是否存在某把可用公钥。
--sign-with KEY 只为未签名 RPM 补签;已经签名的包会保留原字节,包括其他供应商签署的包。
如果策略要求每个 RPM 都由自己的密钥签署,应逐包验证目标密钥,并只在候选中重签不满足要求的
包。--overwrite 是显式的批量替代方案:它重签所有保留 RPM,改变包字节,因此必须根据最终
包字节重建索引。最后一次 create 完成后,始终重新生成对应的索引分离签名。
4. 切换前验收
对候选与预期服务端点检查以下事项:
- 三类 XML 与 RPM 集合对应,引用文件校验和正确。若只改变发布时间,RPM 与压缩 XML 应保持 逐字节一致。
- 每个软件包与索引签名都满足预期客户端信任策略。
- 包字节、选项和时间戳相同时,重复构建元数据应为空操作;此项检查不要强制重签包。维护脚本还应 保留旧的有效分离签名,避免重新签名。
- 带旧缓存的客户端接受新索引,并实际下载、验证软件包。这个测试保留原 URL、repo ID 与缓存。
- 第二次真实内容更新使用更晚的时间,同一客户端仍能接受。需要确认安装行为时,在可丢弃主机上 使用生产中的确切客户端补做安装测试。
对已有签名仓库,验收全程保留 gpgcheck=1 与 repo_gpgcheck=1。清缓存或关闭验签,会绕过
本来需要测试的行为。与旧 createrepo_c 比较时,应核对依赖含义,而非要求 XML 逐字节一致;
相关规则见平台与集成。
5. 发布与恢复资料保留
Plain 会替换多个文件,不提供整个目录的原子切换。发布层需要协调包文件、索引、分离签名以及 缓存的可见顺序。仍可能被缓存客户端请求的旧元数据文件应继续保留;直接运行 Plain 重建,可能 删除目录中不再引用的 SOW checksum 命名元数据。
保留原始备份与持久时钟。回滚软件包内容时,把它当成更晚的一次发布重新建库、签名。只恢复旧
repomd.xml、却搭配已经改变的 RPM,会重新引入校验和或时间戳问题。
Managed 的 sow check 不用于审计 Plain 目录。这里的验收依据是上述检查与真实 YUM/DNF
客户端。精确命令契约见 sow create,两层签名的区别见
仓库签名。
3 - 搭建 APT 仓库
本教程从零创建一个 Managed DEB 仓库。你需要一个可写目录,以及一个或多个 DEB 文件。
1. 创建工作区
Dist 名称会成为 APT Suite。它由你定义;SOW 不会根据 trixie 推断发行版语义。
2. 配置成员策略
如果需要过滤或限制版本,编辑生成的 sow.yml:
然后校验:
配置中保存规范架构名,渲染时使用 Debian 生态名称:x86_64 对应 amd64,aarch64
对应 arm64;中立架构 all 包会进入两个视图。
3. 添加 DEB
接纳的包体只保存一次。公共树如下:
pool/ 下的路径按规范化源码包名分组;Packages 中的 Filename 相对 Archive Root;
SOW 会写入 SHA-256 by-hash 副本,并在 Release 中声明。
4. HTTP 预览
本地预览可以直接使用:
检查协议入口:
长期服务应使用持续维护的 HTTP Server,并完整暴露 pigsty/ 树。
5. 配置 APT
将 REPO_HOST 替换为客户端可访问的地址。未签名测试仓库可使用显式信任的 deb822 配置:
刷新并查询:
Trusted: yes 会关闭真实性校验,只适合受控测试。签名仓库应删除该行并配置 Keyring:
打开 Signed-By 前,请先完成仓库签名。
6. 安全发布
交付前必须通过深度校验:
向已配置的 filesystem 或 R2 目标交付时,使用 sow publish。
如果使用其他传输方式,应把完整仓库复制到离线 staging,再原子切换上线。不要逐文件更新在线
dists/ 树,否则客户端可能同时看到不同 Generation 的元数据与包体。
更新仓库
策略或签名配置变化后用 build 收敛;发布门禁是 check,不能只看 status。
自动化客户端与平台覆盖见平台与集成。
4 - 仓库签名
SOW 提供两条互相独立的签名路径:
| 路径 | 产物 | 客户端开关 |
|---|---|---|
| RPM 元数据 | repodata/repomd.xml.asc |
repo_gpgcheck=1 |
| APT 元数据 | InRelease 与 Release.gpg |
Signed-By |
| RPM 包体 | RPM 内嵌签名 | gpgcheck=1 |
APT 通过签名的 Release 信任包哈希;SOW 不重签 DEB 包体。先配置元数据签名;只有当你负责
这些 RPM 字节的签名策略时,再启用包体签名。
1. 创建专用密钥
下面生成一把无口令的示例密钥。生产环境应使用受保护密钥并配置 passphrase 引用,详见
配置参考。
私钥必须放在 Workspace 公共 Repository 树与所有 Web Root 之外。若 SOW 由专用服务账户运行,
目录 owner 应是该账户,而不是交互用户。只向客户端分发 repo-signing.pub。
2. 配置元数据签名
在 /srv/sow/sow.yml 的 Repository 下添加所需配置;未使用的包生态可以省略:
解析密钥引用、重建并执行发布门禁:
受口令保护的密钥可在 key 旁增加 passphrase: env://SOW_METADATA_PASSPHRASE,或使用
有界文件引用。SOW 不会把密钥或口令内容写入配置、SQLite、JSON 或日志。
3. 手工验证元数据
按实际 Dist 与架构调整路径:
sow check 会在深度一致性校验中检查配置的签名身份。建立客户端信任根时,仍应手工验证一次。
4. 可选:签署 RPM 包体
只有客户端要求内嵌包签名时,才添加 rpm.packages:
将占位符替换为 $FPR 中的 40 位十六进制指纹。该操作要求:
- 安装
rpm与gpg; - 匹配的私钥存在于
rpm使用的环境 GPG Keyring 中; fill保留已经由配置 key 或trusted_keys签好的包;always重签所有未由配置身份签好的包;never保持输入字节不变。
SOW 只会对私有 staged 副本调用 rpm --addsign 或 rpm --resign,不会修改输入文件。
这些规则适用于新导入的包;build 不会重签已有的不可变包对象。在启用 fill 或更换
key 前,确认 所有已有 RPM 都由配置 key 或受信任身份签署。只检查 signature_key
是否为空还不够:已有的第三方签名也可能不受新策略信任。若确实信任该签名身份,可将其
公钥加入 trusted_keys;否则先在仓库外准备正确签名的包,使用新的包版本与文件名导入,或从
原始包重建新仓库。准备完成前保留旧策略。策略拒绝会保留已有 Desired 状态。
确认已有包兼容后,再校验并构建:
用 rpmkeys --checksig /path/to/package.rpm 检查结果。
5. 启用 dnf 验签
通过可信通道把公钥传到客户端:
再打开与你实际签名范围对应的检查:
没有配置包体签名时,将 gpgcheck 设为 0;既然已经配置元数据签名,就不要关闭
repo_gpgcheck。
6. 启用 APT 验签
将公钥安装为独立 Keyring:
在 deb822 配置中引用它,且不要设置 Trusted: yes:
执行 apt update。任何签名错误都应视为部署失败,不能靠削弱客户端配置绕过。
Plain 模式 RPM 签名
Plain 模式可以签署 RPM 包体,但不会签署仓库元数据,也不会生成 APT Release:
key 去掉可选的 0x 或 0X 前缀后,必须是恰好 16、40 或 64 位十六进制字符;SOW 会去掉
前缀并规范化为大写。匹配私钥必须能被环境中的
rpm/GPG 使用。不带 --overwrite 时,已有签名的 RPM 保持字节不变;带上该参数则显式重签
所有 RPM。SOW 先签署私有 staged 副本,再替换包体与元数据。
已有签名并不等于由 --sign-with 指定的密钥签署。如果要求全部 RPM 都使用自己的密钥,
应逐包验证,在候选副本上选择性重签不匹配的包;也可以明确使用 --overwrite 重签全部包。
已有在线 YUM 仓库还应保留发布时间。SOW 0.5.0 新增 --metadata-timestamp;最后一次
create 完成后,发布前应单独签署并验证新的 repomd.xml。包签名与索引签名是两项独立
检查。完整顺序及带缓存客户端验收见 YUM 迁移指南。
更换密钥
在 Managed 模式中,改变 key 引用或解析出的指纹会让相关 Dist 变为 dirty。元数据 key 可以先分发新公钥,再重建、
校验并切换客户端。RPM 包 key 必须分阶段轮换:Package Object 不可变,build 遇到不满足新策略的
既有 RPM 会拒绝,而不是原地重签。旧软件包坐标尚未下架或由新 Release 替代前,应使用 fill
并把旧公钥保留在 trusted_keys。最后在目标环境做真实客户端验收。
最后应使用生产中的确切 dnf/APT 版本与信任策略验收签名仓库。自动化覆盖见 平台与集成。
5 - 服务与发布仓库
SOW 只生成静态文件,不是 HTTP 服务器。本指南把可写 Workspace 与 Nginx 服务路径分开。
公共与私有路径
| 模式 | 公共单元 | 绝不能服务 |
|---|---|---|
| Plain | 传给 sow create 的目录 |
临时 .sow-plain-stage-* 输出;没有持久 journal |
| Managed | 一个 Repository 的完整 pool/ + dists/ 树 |
Workspace sow.yml、.sow/、SQLite、锁、日志与 staging |
第一个工作区里的源 Repository 是 /srv/sow/local。不要把
/srv/sow 设为 document root。
1. 校验源 Generation
只有 check 返回 0 才继续。status 适合诊断;check 才是完整只读交付证明。
2. 配置 filesystem target
先创建 endpoint 目录。它必须是真实、规范目录,不能是 symlink;SOW 不会替你创建缺失 endpoint。
第二条命令把写权限交给当前操作者;若 sow publish 由专用服务账户执行,应改为该账户。
在 /srv/sow/sow.yml 中增加 target:
三个布尔字段都是必填安全确认。endpoint 与 prefix 合并为 /srv/repo-public/local;
SOW 会在预先存在的 endpoint 下创建并拥有该 prefix。
校验并发布:
发布先复制不可变包体和元数据,再更新可变协议指针,随后校验结果并记录 target checkpoint。 同一 Generation 重复发布是幂等空操作。
不要让其他工具写入同一 target prefix。target 契约是单 writer、独占写入。
3. 用 Nginx 服务 target
校验配置后 reload Nginx。客户端 URL 为:
如果元数据或包体已签名,请单独发布对应公钥并配置 gpgkey/Signed-By;私钥绝不能放在
document root 下。
4. 验证服务入口
随后从客户端主机运行真实包管理器。HTTP 可达不等于客户端已验证,两层都要检查。
完整 Repository prefix 必须使用同一访问策略。RPM 元数据可能通过 ../../../pool/...
解析包路径,APT Filename 也直接指向 pool/...。只保护 dists/ 而误放开或拦截 pool/
都会破坏仓库。
手工与隔离交付
如果 sow publish 无法到达目标:
- 在源端运行
sow check; - 把完整 Repository 复制到新的、非 live staging/release 目录;
- 用
sow changes 0或 archive manifest 校验传输哈希; - 原子切换操作者拥有的父级引用到新目录;
- 保留上一版,直到客户端与缓存越过它。
不要直接对 live Repository root 执行无序 rsync --delete。它不保留 SOW 的指针顺序、
target checkpoint、缓存 grace 或恢复状态。sow changes 描述 Generation 差异,不代表可以
绕过这些控制直接修改 live target。
R2 target
provider: r2 使用 S3 兼容存储传输与只报告的 target GC。传输集成会针对固定的 PGSTY Silo fixture
验证 list、HEAD、GET 与单段条件 PUT;不覆盖条件式 Multipart 完成,也不能替代真实 R2 验收。启用生产目标前,请先在非生产 prefix 验证凭据、bucket
policy、公共 endpoint、缓存行为、重放与恢复。详见平台与集成。
下一步
6 - 演练构建 pigsty-infra 仓库
pgsty/infra-pkg 是 Pigsty Infra 软件包的上游构建源码。
本教程假设双架构 RPM 与 DEB 已经构建完成,只处理后半程:从一堆包开始,用 SOW 建成真正可消费、可维护的 infra 仓库。
1. 把包集中到 ~/repo
本教程固定使用 ~/repo,不再为每条路径定义环境变量。先把已有包复制进两个输入目录:
先确认四个“格式 × 架构”象限都有真实包体:
四个结果都必须大于零。此时目录只有输入包池:
2. 创建 infra Repository 与两个 Dist
初始化 Workspace,并创建名为 infra 的 Repository:
现在模型已经确定:
打开 ~/repo/sow.yml,把配置整理为:
limit: 1 按“包名 + 原生架构”只保留最新一个版本。因此 rpm 与 deb 就是两个滚动更新的
latest channel;它们仍会同时保留 x86-64 与 ARM64 两个架构。
3. 一次性导入并构建
先更新 Desired Membership,最后只构建一次:
sow check 返回 0,才算初始化完成。再核对 SOW 从包头读出的真实格式与架构:
预期至少出现:
SOW 使用规范化架构名,因此 DEB 的 amd64/arm64 在这里显示为 x86_64/aarch64。
4. 看懂生成的目录
打印实际目录:
关键结构应当是:
这里有一个容易混淆、但必须记住的路径规则:SOW 的 Dist 固定放在 dists/ 下。因此逻辑上的
infra/rpm 与 infra/deb,真实视图路径分别是 /infra/dists/rpm/ 和 /infra/dists/deb/;
包体则统一放在 /infra/pool/。发布或挂载时必须使用完整的 ~/repo/infra,不能只拿走某个 Dist。
5. 用 Nginx 只读服务仓库
使用官方 nginx:alpine 镜像,把 Repository Root 只读挂载到 /infra:
直接检查两种索引入口:
Nginx 只看得到 ~/repo/infra,既看不到 sow.yml 与 .sow/,也无法修改仓库。
6. 在 EL9 中只用 infra 安装 RPM
下面的 Rocky Linux 9 容器位于 --internal 网络中。脚本先删除所有预置仓库,再只启用刚创建的
infra,因此成功安装不能依赖公网软件源。
RPM 的 baseurl 必须落到具体架构视图。$basearch 会由 dnf 展开为 x86_64 或 aarch64。
7. 在 Ubuntu 24.04 中只用 infra 安装 DEB
APT 的 URI 指向 Repository Root,Suites 才是 Dist 名 deb:
本教程使用隔离 HTTP 仓库,所以临时关闭了验签。正式服务应配置 RPM/APT 元数据签名,并移除
gpgcheck=0 与 Trusted: yes。
Docker 默认验证宿主机架构。若要完成四格运行矩阵,分别给两条 docker run 增加
--platform linux/amd64 与 --platform linux/arm64 后各跑一次;跨架构运行需要 Docker 的
binfmt/QEMU 支持。仓库清单检查与客户端安装检查是两个独立门禁。
8. 日常维护:添加一个新版本
更新仓库的正常动作是 add,不是先删除旧包。假设已经拿到新版 pg-exporter 的四个包体:
因为 latest Dist 配了 limit: 1,新版本胜出后,旧版本会自动退出该 Dist 的 Desired Membership。
旧字节不会被立即删除,也不会因为以后放宽策略而自动回来。
可以重新运行第 6、7 节的客户端,先 makecache/update,再安装或升级,完成更新验收。
正常发布不要先 sow rm。如果某个错误包必须紧急撤回,先用 sow ls -r infra -d rpm --json
或对应的 -d deb 找到精确 SHA-256,
再依次执行 sow rm sha256:... -r infra -d rpm --check 与不带 --check 的同一命令。
rm 只删除 Dist Membership,pool 字节仍由保守的 sow gc 独立回收;不要用裸包名误删所有版本与架构。
9. 两层保留策略:latest 与 stable
rpm、deb 的 limit: 1 适合持续滚动,但不能表达“保留所有正式发布历史”。为此再创建两个 Dist:
新 Dist 的默认 limit 是 0,表示保留所有版本。最终策略是:
| Dist | 格式 | limit |
角色 |
|---|---|---|---|
rpm |
RPM | 1 | RPM latest |
deb |
DEB | 1 | DEB latest |
rpm-stable |
RPM | 0 | 累积所有已晋升 RPM |
deb-stable |
DEB | 0 | 累积所有已晋升 DEB |
注意:stable 不是把“包池里的所有历史”自动放回来,而是从现在开始,累积每次明确晋升的版本。
10. 把 latest 晋升到 stable
SOW 没有独立的 promote 命令。当前可靠做法是先冻结写入并导出源 Dist 的精确 Membership,
再把这些对象加入目标 Dist。输入直接取自 infra/pool;SOW 会校验并复用已有 Package Object,
不会重新打包,也不会在 pool 中复制第二份包体。
先确保源状态干净,并保存本次晋升清单:
在晋升结束前暂停对 rpm 与 deb 的写入,然后复用这些 pool 对象:
每次 add 应报告 reused。若中途失败,源 Dist 不受影响;修复问题后对同一清单重跑即可。
随着以后重复晋升,rpm/deb 仍只保留最新版本,而 rpm-stable/deb-stable 会逐次累积历史版本。
11. 从 stable 创建 2026-08 快照
客户端可见的月度快照也是两个新的 Dist:
在快照窗口内暂停 stable 写入,先把其精确 Membership 固化为清单:
再把清单加入对应快照 Dist:
把这次已验证的完整 Repository Generation 也加入保留集合,防止后续 GC 把它当作不可达历史处理:
retain 保留的是整个 Repository Generation,用于恢复与 GC 安全根;客户端可见的固定 URL 仍由
rpm-202608 与 deb-202608 两个 Dist 提供。SOW 尚不强制快照 Dist 只读,因而创建后不再对它们
执行 add 或 rm 是维护规约的一部分。
12. 客户端地址总表
同一个 Nginx 与同一份 infra/pool 支撑所有 channel:
| Channel | dnf baseurl |
APT URIs / Suites |
|---|---|---|
| latest | http://infra-nginx/infra/dists/rpm/$basearch/ |
http://infra-nginx/infra / deb |
| stable | http://infra-nginx/infra/dists/rpm-stable/$basearch/ |
http://infra-nginx/infra / deb-stable |
| 2026-08 | http://infra-nginx/infra/dists/rpm-202608/$basearch/ |
http://infra-nginx/infra / deb-202608 |
最终验收:
到这里,我们得到的不是一次性演示目录,而是一个可以继续收包、晋升与做月度快照的真实 Infra
Repository:rpm/deb 负责快速更新,rpm-stable/deb-stable 负责积累正式历史,月度 Dist 提供固定入口,
所有视图复用同一份不可变包体。
实验结束后可停止临时服务: