3、持续集成(CI)实战:Jenkins/GitLab CI流水线设计、自动化构建与触发策略、构建产物管理
持续集成这件事,说白了就是让代码从提交到可部署的中间过程自动化。我见过太多团队,每天花大量时间在「等构建」、「手动打包」、「找构建产物」上。其实这些都可以交给工具去做。
今天我们就聊聊 Jenkins 和 GitLab CI 这两大主流工具。我个人习惯是:小团队用 GitLab CI,大团队或复杂场景用 Jenkins。为什么?往下看你就明白了。
3.1 流水线设计:从手动到自动
流水线设计是 CI 的核心。你想想看,如果没有清晰的流水线,构建过程就像一团乱麻。
我建议把流水线分为三个阶段:
- 触发阶段:代码提交、PR 合并、定时触发
- 构建阶段:编译、单元测试、代码扫描
- 产出阶段:打包、归档、通知
嗯,这里要注意:流水线不是越复杂越好。我在项目中遇到过,有人把部署也塞进 CI 流水线,结果每次构建都要等 20 分钟。其实 CI 只负责到「构建产物」这一步就够了。
3.1.1 Jenkins 流水线示例
Jenkins 的流水线用 Groovy 写。我个人喜欢用声明式语法,可读性更好。
pipeline {
agent any
stages {
stage('检出代码') {
steps {
checkout scm
}
}
stage('编译') {
steps {
sh 'mvn clean compile'
}
}
stage('单元测试') {
steps {
sh 'mvn test'
}
}
stage('打包') {
steps {
sh 'mvn package'
}
}
stage('归档产物') {
steps {
archiveArtifacts artifacts: 'target/*.jar'
}
}
}
}
这段代码看起来简单,但实际项目中我踩过坑。比如 archiveArtifacts 这一步,如果产物太大,Jenkins 的存储会爆炸。我曾经因为没限制归档大小,导致 Jenkins 磁盘满了,整个团队停摆半天。
3.1.2 GitLab CI 流水线示例
GitLab CI 用 YAML 写,更轻量。我特别喜欢它的 rules 语法,触发策略非常灵活。
stages:
- build
- test
- package
build-job:
stage: build
script:
- mvn clean compile
only:
- main
- merge_requests
test-job:
stage: test
script:
- mvn test
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
when: always
- when: manual
package-job:
stage: package
script:
- mvn package
artifacts:
paths:
- target/*.jar
expire_in: 7 days
你看,GitLab CI 的 artifacts 自带过期时间,这个设计比 Jenkins 聪明。我刚开始用 GitLab CI 时,没注意 expire_in 参数,结果产物越积越多。后来加了 7 天过期,磁盘压力小多了。
3.2 自动化构建与触发策略
触发策略是 CI 的「开关」。你想想看,如果每次保存代码都触发构建,那开发人员会疯掉的。
我常用的触发策略有三种:
| 触发方式 | 适用场景 | 注意事项 |
|---|---|---|
| 代码提交触发 | 主分支、开发分支 | 避免频繁提交导致排队 |
| PR/MR 触发 | 功能分支合并前 | 必须通过所有检查才能合并 |
| 定时触发 | 夜间构建、全量回归 | 避开高峰期,比如凌晨 2 点 |
我个人习惯是:主分支用提交触发,功能分支用 PR 触发,全量回归用定时触发。这样既保证了效率,又不会浪费资源。
rules 实现「只有特定文件变更时才触发」。比如只改了 README,就没必要跑全量构建。
3.2.1 避免「构建风暴」
为什么会发生构建风暴?说白了就是触发太频繁。我记得有一次,团队在合并大功能时,20 个人同时提交,Jenkins 队列排了 50 多个任务。最后构建机 CPU 跑满,所有任务都超时了。
解决方案很简单:
- 设置并发限制(Jenkins 的
throttle插件) - 使用队列优先级(紧急构建优先)
- 合并提交(GitLab CI 的
retry机制)
3.3 构建产物管理
构建产物是 CI 的「成果」。你想想看,如果产物管理混乱,部署时找不到正确的版本,那 CI 就白做了。
我建议遵循三个原则:
- 版本化:每个产物都有唯一版本号(如
app-1.0.0-20231001.jar) - 可追溯:从产物能反查到对应的代码提交
- 可清理:设置保留策略,避免存储膨胀
3.3.1 产物存储方案
| 方案 | 优点 | 缺点 |
|---|---|---|
| Jenkins 内置归档 | 简单、无需额外配置 | 占用 Jenkins 磁盘,不适合大文件 |
| GitLab Artifacts | 自带过期时间,集成度高 | 存储空间有限(免费版) |
| Nexus/Artifactory | 专业制品库,支持多种格式 | 需要额外部署和维护 |
我个人推荐:小团队用 GitLab Artifacts,大团队用 Nexus。我在项目中用过 Nexus,它支持 Docker 镜像、Maven 包、npm 包等,而且有完善的权限控制。不过部署起来稍微麻烦点。
3.3.2 产物命名规范
我习惯用这种命名格式:
{项目名}-{版本号}-{构建时间}-{构建号}.{扩展名}
举个例子:
order-service-1.2.3-20231001-45.jar
这样命名的好处是:一眼就能看出是哪个项目、什么版本、什么时候构建的。我曾经因为产物命名混乱,导致部署时拿错了版本,线上出了故障。从那以后,我强制团队统一命名规范。
3.4 实战经验总结
说了这么多,最后分享几个我踩过的坑:
- 不要把所有事情都塞进 CI:CI 只负责构建和测试,部署交给 CD
- 触发策略要精细:别让无关的提交触发构建
- 产物要定期清理:设置过期时间,不然磁盘会爆
- 流水线要可视化:用 Blue Ocean 或 GitLab 的流水线视图,方便排查问题
嗯,持续集成这件事,说白了就是「自动化 + 规范化」。工具只是手段,关键是流程设计。你想想看,如果每次构建都要手动操作,那还叫什么持续集成?
下一章我们会聊持续部署(CD),到时候会讲到怎么把构建产物自动部署到测试环境。敬请期待。