在 Koji 构建系统中,koji build是最核心、最常用的命令之一。理解其各个参数的含义和应用场景,是每一位 Linux 发行版构建工程师和包维护者的必修课。本文将逐一拆解koji build的每个参数,并重点剖析--scratch参数的本质、NVR 唯一性规则,以及构建失败后的恢复策略。
一、命令基本结构
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)
koji build--scratch--waitf40-build git+https://pagure.io/mypkg.git--scratch:不进入正式仓库--wait:等待构建完成- 适用于快速验证代码是否能编译通过
示例 2:多架构调试
koji build--scratch--arch-override=aarch64--waitf40-build ./mypkg.src.rpm--arch-override=aarch64:仅构建 aarch64 架构- 适用于调试特定架构的构建问题
示例 3:正式发布构建
koji build--waitf40-build git+https://pagure.io/mypkg.git#main- 不带
--scratch:正式构建,产物进入仓库 - 确保代码已在 Scratch 构建中验证通过
示例 4:依赖等待场景
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 包维护者。