在 Koji 构建系统中koji build是最核心、最常用的命令之一。理解其各个参数的含义和应用场景是每一位 Linux 发行版构建工程师和包维护者的必修课。本文将逐一拆解koji build的每个参数并重点剖析--scratch参数的本质、NVR 唯一性规则以及构建失败后的恢复策略。一、命令基本结构koji build[options]targetsrpm 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 唯一性检查❌ 不检查✅ 严格检查产物引用方式任务 IDTask IDNVRName-Version-Release产物下载方式koji download-task或koji-download-scratchkoji 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-buildNVR含义等待指定的 NVR 出现在构建根仓库中。应用场景构建顺序依赖当前包依赖另一个包的最新版本需要等待该包构建完成并进入仓库后再开始构建。7.--quiet含义不打印任务信息。应用场景在脚本中静默执行减少日志输出。与其他命令组合使用时避免输出干扰。8.--arch-overrideARCH_OVERRIDE含义覆盖构建架构列表。应用场景当 target 默认包含多个架构如 x86_64、aarch64、ppc64le但您只想在特定架构上测试时使用。调试特定架构的构建问题。9.--fail-fast含义覆盖build_arch_can_fail设置尽可能快地失败。应用场景当您希望尽早发现构建问题而不是等待所有架构都尝试构建完成。在 CI/CD 中加快反馈速度。10.--repo-idREPO_ID含义使用指定的仓库 ID进行构建。应用场景高级调试场景需要固定使用某个特定版本的仓库进行可重现构建。测试仓库变更对构建的影响。11.--noprogress含义不上传进度条显示。应用场景在日志记录场景中避免进度条字符污染日志文件。12.--background含义以较低优先级运行构建任务。应用场景当构建系统负载较高时将非紧急构建任务降级。大型构建如 Kernel在非高峰时段运行。三、深度专题--scratch的本质与 NVR 唯一性3.1 什么是 NVRNVR 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快速测试构建Scratchkoji build--scratch--waitf40-build githttps://pagure.io/mypkg.git--scratch不进入正式仓库--wait等待构建完成适用于快速验证代码是否能编译通过示例 2多架构调试koji build--scratch--arch-overrideaarch64--waitf40-build ./mypkg.src.rpm--arch-overrideaarch64仅构建 aarch64 架构适用于调试特定架构的构建问题示例 3正式发布构建koji build--waitf40-build githttps://pagure.io/mypkg.git#main不带--scratch正式构建产物进入仓库确保代码已在 Scratch 构建中验证通过示例 4依赖等待场景koji build --wait-repo --wait-builddep-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 包维护者。