在 Koji 构建系统中,koji build 是最核心、最常用的命令之一。理解其各个参数的含义和应用场景,是每一位 Linux 发行版构建工程师和包维护者的必修课。本文将逐一拆解 koji build 的每个参数,并重点剖析 --scratch 参数的本质、NVR 唯一性规则,以及构建失败后的恢复策略。
一、命令基本结构
bash
koji build [options] <target> <srpm path or scm url>
核心参数说明:
<target>:构建目标,决定了构建根(buildroot)的内容来源以及构建产物的最终去向。需要特别注意的是,target 不同于 destination tag(构建最终落地的标签)或 build tag(构建根内容的来源标签) 。可用koji list-targets查看所有可用的构建目标。<srpm path or scm url>:源码包路径或 SCM 仓库地址。普通用户通常需要通过 SCM 发起构建,直接从 SRPM 构建通常仅限管理员操作。
二、参数详解
1. --skip-tag
含义 :构建完成后,不尝试将构建产物自动打上目标标签。
应用场景:
- 当您希望手动控制标签行为时使用。
- 配合后续的
koji tag-build命令,实现更精细的发布流程控制。 - 适用于需要先验证构建产物再决定是否正式纳入仓库的场景。
2. --scratch ⭐(核心参数)
含义 :执行草稿构建(Scratch Build) ------ 构建包但不将其打标签并入正式仓库。
Scratch Build 的本质特征:
| 特征 | Scratch Build | 正式构建(Real Build) |
|---|---|---|
| 是否打标签 | ❌ 否 | ✅ 是 |
| 是否进入正式仓库 | ❌ 否 | ✅ 是 |
| NVR 唯一性检查 | ❌ 不检查 | ✅ 严格检查 |
| 产物引用方式 | 任务 ID(Task ID) | NVR(Name-Version-Release) |
| 产物下载方式 | koji download-task 或 koji-download-scratch |
koji download-build |
| 清理策略 | 自动清理(系统周期性删除) | 长期保留 |
Scratch Build 的核心价值:
- 快速验证:在正式提交构建前,先用 Scratch 构建验证代码是否能成功编译。
- 多架构测试:在无需拥有各架构硬件的情况下,测试包在各种架构上的构建情况。
- 无污染测试:即使构建失败,也不会在正式仓库中留下任何记录。
- 无 NVR 冲突:可以反复使用相同的 NVR 进行 Scratch 构建,不受唯一性限制。
典型工作流:
开发者通常会先执行一系列 Scratch 构建进行测试,待一切正常后,增加 Release 号,再执行一次正式构建。
⚠️ 重要提示 :Scratch 构建虽然方便,但不能替代正式构建。Scratch 构建成功后,仍需发起一次正式构建才能真正将包纳入发行版仓库。
3. --rebuild-srpm 与 --no-rebuild-srpm
含义 :仅用于 Scratch 构建,控制是否强制重新构建 SRPM。
--rebuild-srpm:强制重新构建 SRPM(即使已存在)。--no-rebuild-srpm:强制不重新构建 SRPM。
应用场景:
- 当您修改了 spec 文件但不想重新生成完整的 SRPM 时,可用
--no-rebuild-srpm加速测试。 - 当您需要确保 SRPM 是最新生成的时候,使用
--rebuild-srpm。
4. --wait 与 --nowait
含义 :控制 Koji 客户端是否等待构建任务完成后再退出。
--wait:等待构建完成(即使命令在后台运行)。--nowait:不等待构建完成,提交后立即返回。
应用场景:
--wait:适用于脚本和 CI/CD 流水线,需要确保构建完成后再执行后续步骤。--nowait:适用于交互式场景,提交构建后可以继续做其他事情。
5. --wait-repo
含义 :等待给定 target 的实际构建根仓库(buildroot repo)准备就绪。
应用场景:
- 在构建依赖链场景中,确保依赖包已进入构建根后再发起当前构建。
- 配合
--wait-build使用,实现复杂的构建顺序控制。
6. --wait-build=NVR
含义 :等待指定的 NVR 出现在构建根仓库中。
应用场景:
- 构建顺序依赖:当前包依赖另一个包的最新版本,需要等待该包构建完成并进入仓库后再开始构建。
7. --quiet
含义 :不打印任务信息。
应用场景:
- 在脚本中静默执行,减少日志输出。
- 与其他命令组合使用时,避免输出干扰。
8. --arch-override=ARCH_OVERRIDE
含义 :覆盖构建架构列表。
应用场景:
- 当 target 默认包含多个架构(如 x86_64、aarch64、ppc64le),但您只想在特定架构上测试时使用。
- 调试特定架构的构建问题。
9. --fail-fast
含义 :覆盖 build_arch_can_fail 设置,尽可能快地失败。
应用场景:
- 当您希望尽早发现构建问题,而不是等待所有架构都尝试构建完成。
- 在 CI/CD 中加快反馈速度。
10. --repo-id=REPO_ID
含义 :使用指定的仓库 ID 进行构建。
应用场景:
- 高级调试场景,需要固定使用某个特定版本的仓库进行可重现构建。
- 测试仓库变更对构建的影响。
11. --noprogress
含义 :不上传进度条显示。
应用场景:
- 在日志记录场景中,避免进度条字符污染日志文件。
12. --background
含义 :以较低优先级运行构建任务。
应用场景:
- 当构建系统负载较高时,将非紧急构建任务降级。
- 大型构建(如 Kernel)在非高峰时段运行。
三、深度专题:--scratch 的本质与 NVR 唯一性
3.1 什么是 NVR?
NVR = Name-Version-Release,是 Koji 中唯一标识一个构建的三元组。
Koji 确保所有已完成的正式构建拥有唯一的 NVR。这是构建系统一致性的基石。
3.2 正式构建的 NVR 唯一性规则
规则 :Koji 不允许使用已经构建过的 NVR 再次发起正式构建。
"In koji nvrs are forever, mostly. You can rebuild over a failed or canceled build, but even a deleted build still blocks a rebuild of the same nvr."
翻译:在 Koji 中,NVR 基本上是永久性的。你可以在失败或取消的构建之上重新构建,但即使是一个已被删除的构建,仍然会阻止相同 NVR 的重新构建。
这意味着:
- 一个 NVR 一旦被使用(无论构建成功还是失败),就不能再次用于正式构建。
- 即使使用管理员权限删除构建记录,该 NVR 仍然被"占用"。
3.3 构建失败后的恢复策略
场景 :执行 koji build(不带 --scratch)时构建失败,能否再次启动相同 NVR 的正式构建?
答案 :❌ 不能。
即使构建失败,该 NVR 已经被 Koji 记录在案。再次尝试会收到类似错误:
Package xxx-N-V-R has already been built
正确的恢复方法:
| 方法 | 操作 | 适用场景 |
|---|---|---|
| 方法一(推荐) | 增加 Release 号 (如从 1 改为 2),使用新 NVR 重新构建 |
所有场景,最简单可靠 |
| 方法二(高级) | 使用 --skip-nvr-check 跳过 NVR 检查 |
需要覆盖检查的特殊场景(需谨慎) |
| 方法三(管理员) | 使用 koji call deleteBuild <nvr> 删除构建记录 |
仅管理员可操作,且需确保无标签引用 |
⚠️ 强烈建议 :直接增加 Release 号是最简单、最安全的方式。
3.4 Scratch Build 的 NVR 处理
Scratch Build 不受 NVR 唯一性约束:
- 可以使用任意 NVR(包括已被正式构建使用的 NVR)
- 可以反复使用相同 NVR 进行多次 Scratch 构建
- Scratch 构建的产物不进入正式仓库,因此不会与正式构建冲突
这正是 Scratch Build 作为"测试工具"的核心价值所在。
四、参数组合实战示例
示例 1:快速测试构建(Scratch)
bash
koji build --scratch --wait f40-build git+https://pagure.io/mypkg.git
--scratch:不进入正式仓库--wait:等待构建完成- 适用于快速验证代码是否能编译通过
示例 2:多架构调试
bash
koji build --scratch --arch-override=aarch64 --wait f40-build ./mypkg.src.rpm
--arch-override=aarch64:仅构建 aarch64 架构- 适用于调试特定架构的构建问题
示例 3:正式发布构建
bash
koji build --wait f40-build git+https://pagure.io/mypkg.git#main
- 不带
--scratch:正式构建,产物进入仓库 - 确保代码已在 Scratch 构建中验证通过
示例 4:依赖等待场景
bash
koji build --wait-repo --wait-build=dep-pkg-1.0-1.fc40 f40-build ./mypkg.src.rpm
--wait-repo:等待构建根就绪--wait-build:等待依赖包出现- 适用于复杂依赖链场景
五、总结
| 参数 | 核心作用 | 关键场景 |
|---|---|---|
--scratch |
草稿构建,不进入正式仓库 | 测试验证、多架构调试 |
--skip-tag |
跳过自动打标签 | 手动控制发布流程 |
--wait / --nowait |
控制是否等待构建完成 | 脚本自动化 vs 交互式 |
--wait-repo / --wait-build |
等待构建根或依赖包就绪 | 复杂依赖链场景 |
--arch-override |
覆盖构建架构列表 | 单架构调试 |
--fail-fast |
快速失败 | CI/CD 快速反馈 |
--background |
低优先级运行 | 非紧急大型构建 |
--rebuild-srpm / --no-rebuild-srpm |
控制 SRPM 重建 | Scratch 构建优化 |
黄金法则:
- 测试用 Scratch,发布用正式构建。
- 正式构建失败后,增加 Release 号而非重复使用相同 NVR。
- Scratch 构建不能替代正式构建 ------ 两者各有其位,不可混淆。
本文适用于 Linux 发行版构建工程师、DevOps 系统架构师及 RPM 包维护者。