Jenkins构建产物如何自动归档并保留最近10个版本

文章导读
先说一个我自己的处理习惯:接到这类需求时,我第一件事不是打开 Jenkins 配置页,而是先看产物到底被谁消费。如果构建后只生成日志和报告,那归档的意义不大;如果下游要拿安装包去部署或复现问题,那自动归档就是必须做的事。保留最近 10 个版本也不是拍脑袋定的,它比较适合“旧版本偶尔还要用”的日常交付节奏。
📋 目录
  1. 先判断:要不要启用自动归档
  2. 自由风格任务:在界面里设置保留量和归档路径
  3. Pipeline 任务:把保留和归档都写进 Jenkinsfile
  4. 保留策略的边界:小心“最近10个”把还在用的旧包删掉
  5. 验证是否真只留了最近10个
  6. 容易踩的坑:清理顺序和重名文件
A A

先说一个我自己的处理习惯:接到这类需求时,我第一件事不是打开 Jenkins 配置页,而是先看产物到底被谁消费。如果构建后只生成日志和报告,那归档的意义不大;如果下游要拿安装包去部署或复现问题,那自动归档就是必须做的事。保留最近 10 个版本也不是拍脑袋定的,它比较适合“旧版本偶尔还要用”的日常交付节奏。

自由风格作业的配置很简单:在任务设置中勾选“Discard Old Builds”,选择“Log Rotation”策略,将“Max # of builds to keep”设为10。再勾选“Archive the artifacts”,在输入框中填写要归档的文件路径,比如dist/*.tar.gz,多个模式用逗号分隔。保存后,每次构建结束时Jenkins会自动将匹配的文件复制到构建记录目录,并在页面显示“Artifacts”链接。对于已经存在的历史构建,Jenkins不会自动清理,需要手动执行“Purge Old Builds”或等待下一次构建触发清理。

先判断:要不要启用自动归档

在维护Jenkins任务时,若构建过程会产出安装包、镜像或文档等可交付文件,就应当启用自动归档。归档的作用是让构建结果与构建记录绑定,方便后续下载和追溯。判断是否需要保留最近10个版本,可以观察产物使用频率:若下游或测试人员经常回退到旧版本,那么保留最近10个构建的制品是比较合理的选择。在任务配置页面的“General”部分,确认是否已勾选“Discard Old Builds”和“Archive the artifacts”。如果只勾选了归档而没有设置保留策略,磁盘空间会持续增长;反之如果只设置了保留策略而未归档,旧构建的产物会随构建删除而丢失。

如果只是代码编译和单元测试,不产生需要下载的调试包,我一般不勾选归档。归档会复制文件到构建记录目录,对构建耗时和磁盘占用都有影响。保留最近10个版本也不是固定标准,它适合大多数内部交付场景。若每个构建产物体积很大,10 个版本也可能把磁盘占满,这时需要结合磁盘监控来确定数量。

自由风格任务:在界面里设置保留量和归档路径

自由风格任务没有额外脚本成本。在任务设置里,把“Discard Old Builds”勾上,策略选择“Log Rotation”,Max # of builds to keep 填 10。然后勾选“Archive the artifacts”,在出现的输入框里写产物相对路径,比如 dist/*.tar.gz。保存后下一次构建结束,Jenkins 会自动把匹配的文件归档到该次构建的目录里。这个路径如果写错,构建不会失败,但在构建页看不到 Artifacts 链接,因此需要实际构建一次确认。多个模式用逗号分隔。

Jenkins构建产物如何自动归档并保留最近10个版本

这里有两点我可以给出建议:一是路径尽量不用绝对路径,因为归档是相对于当前工作目录的;二是在自由风格里,如果同时配置了构建后删除工作空间,要确保归档步骤在清理之前,否则文件就没了。

Pipeline 任务:把保留和归档都写进 Jenkinsfile

如果任务是用 Jenkinsfile 定义的,就不能只靠界面配置,需要在 pipeline 的 options 块加上保留策略,并在 post 块里做归档。下面是我常用的写法:

pipeline {
    agent any
    options {
        buildDiscarder(logRotator(numToKeepStr: '10'))
    }
    stages {
        stage('Build') {
            steps {
                sh 'make dist'
            }
        }
    }
    post {
        always {
            archiveArtifacts artifacts: 'dist/**', fingerprint: true
        }
    }
}

注意 archiveArtifacts 必须运行在 agent 节点上,路径是相对当前工作目录的,不能直接写 Jenkins 主机上的路径。若产物在子目录,用通配符 dist/** 能匹配嵌套路径。fingerprint: true 会记录文件指纹,后续可以查看哪个构建从哪个上游产生,对问题追溯有帮助,但首次开启后需要积累几轮历史数据才有参考价值。

保留策略的边界:小心“最近10个”把还在用的旧包删掉

“Max # of builds to keep”控制的是构建记录总数,而非纯粹的文件数量。当达到10个构建后,每次新构建完成,最旧的构建及其归档的产物会被一并删除。因此,如果某个旧版本产物仍被生产环境依赖,直接删除会造成不可用。若需要长期保留某个特定版本,可以在该构建页面上点击“Keep this build forever”按钮,使其不受清理策略影响。这个操作只对单个构建有效,不影响其他构建的清理。若使用外部存储归档,则不受Jenkins保留策略约束,需自行设计清理任务。

也就是说,设置 10 个版本之前,需要先确认团队是否依赖更早的产物。若有发布到生产后在特定版本上回滚的需求,建议在发布时手动点击 Keep this build forever,或者把正式发布版本放到独立目录。不要指望 Jenkins 保留策略能识别“哪个版本重要”,它的逻辑只按构建顺序删除。

Jenkins构建产物如何自动归档并保留最近10个版本

验证是否真只留了最近10个

通常可以在任务状态页左侧的 Build History 看数量,也可以直接访问 API 检查。这里给出一个简单的请求:

http://jenkins/job/{jobName}/api/json?tree=builds[number]

返回的 builds 数组长度应不超过 10。如果手动 keep 过某个构建,数组里可能多一两个,这是正常的。另一个判断点:打开任意构建页,能看到 Artifacts 链接,且旧构建的 Artifacts 在清理后变成不可访问状态。需要结合环境确认 URL 是否匹配你的 Jenkins 根路径。

容易踩的坑:清理顺序和重名文件

很多用户在Pipeline中使用`deleteDir()`清理工作空间,这不会影响已归档的产物,因为归档发生在构建结束后,文件已复制到Jenkins主机的指定目录。但要注意,如果post步骤中先执行`deleteDir()`再调用`archiveArtifacts`,就会导致归档失败,因为文件已被删除。因此,archiveArtifacts必须放在cleanUp步骤之前,建议在always块中先归档再清理。另一个常见问题是归档文件名包含构建号时,需要借助`BUILD_NUMBER`环境变量,例如`artifacts: "dist/app-${env.BUILD_NUMBER}.zip"`,否则重复构建会覆盖同名文件。

如果不用构建号区分文件名,10个版本虽然保留在10个构建目录里,但下载时容易拿错包。建议在产物文件名中加上 ${BUILD_NUMBER} 或 Git commit 短哈希。同时检查日志里有没有文件已存在、正在覆盖之类的输出,留意覆盖行为是否符合预期。