聊聊持续集成工具:从“能跑就行”到“高效交付”的实战经验分享
我是在一家中型互联网公司做 DevOps 工具链开发的,主要负责内部 CI/CD 平台的设计与实现。说白了,就是让开发同学提交代码后,自动构建、测试、部署,减少人为操作带来的低效和错误。
在加入团队之前,公司的 CI 环境非常原始: Jenkins 是唯一的选择,job 用得杂乱无章,没有统一的流程规范,甚至有些项目是直接在服务器上手动执行脚本打包的。整个研发流程像是靠惯性往前推,谁也不敢动那几台老旧的 Jenkins 服务器,生怕一重启就崩盘。
这篇文章我想借这个机会,讲讲我们在推动持续集成平台升级过程中踩过的坑、用过的工具、遇到的问题以及最后的收益。如果你正在为自己的团队挑选 CI 工具或者正准备搭建一套更高效的构建流程,希望我这些亲身经历能给你一些启发。
引言:为什么我们开始重新审视 CI 工具?

2021 年底,随着公司业务快速扩张,我们迎来了几个新问题:
- 项目数量暴增:原本不到 30 个服务,一下子涨到了 80 多个。
- 构建任务排队严重:Jenkins 的 agent 数量跟不上需求,经常一个 job 得等十几分钟才排上队。
- 失败率高但定位难:很多构建失败是因为环境不一致或者脚本写法混乱,排查一次要花上半天。
- 新人上手成本高:每个项目都有一套自定义的
jenkinsfile,没人敢轻易改,文档也几乎等于没有。
这时候我们就意识到,CI 工具不能再当“后台小透明”了,它必须成为一个可维护、可扩展、可配置的基础能力,支撑起整个研发流程的稳定性与效率。
于是我们启动了一个叫“Phoenix(凤凰)计划”的项目——目标是重构 CI 系统,提升整体交付效率,同时降低使用门槛。
遇到的挑战:不只是换工具那么简单


刚开始我们以为就是换个更新的 CI 工具而已,比如 GitLab CI 或者 GitHub Actions,但实际上远没有想象中简单。
挑战一:工具选型困难重重
我们先后评估了 Jenkins、GitLab CI、GitHub Actions、CircleCI、Drone、Tekton 几种主流方案。
| 工具 | 优点 | 缺点 |
|---|---|---|
| Jenkins | 插件生态丰富,社区强大 | 架构陈旧,维护复杂 |
| GitLab CI | 原生集成 GitLab,易上手 | 如果不使用 GitLab,就没啥优势 |
| GitHub Actions | 和 GitHub 集成好,免费额度大 | 自托管 runner 成本高 |
| CircleCI | UI 友好,支持并行执行 | 国内访问慢,费用较高 |
| Drone | 轻量级,容易部署 | 插件少,社区活跃度一般 |
| Tekton | CNCF 孵化项目,适合云原生场景 | 上手难度高,学习曲线陡峭 |

最后我们选择了 Jenkins + Tekton 的混合方案 —— 把 Tekton 当作底层构建引擎来调度任务,而 Jenkins 做调度器和 UI 层,相当于做了个中间层抽象,这样既能保留已有的历史 job,又可以为未来迁移到纯 Tekton 打基础。
听起来很完美吧?其实后面坑更多……
我们的解决方案:打造灵活可控的 CI 平台

我们的核心设计思路是 “上层统一配置,下层灵活扩展”,具体包括以下几个部分:
1. 统一配置管理
我们基于 YAML 定义了一套构建模板:
pipeline:
name: "my-service"
triggers:
- type: git_push
branch: develop
stages:
- name: checkout
action: git-checkout
- name: install
action: npm-install
- name: build
action: webpack-build
- name: test
action: jest-test
然后通过中间服务将这个模板翻译成 Tekton 的 TaskRun 或 PipelineRun,大大减少了每个项目的重复工作。
2. 自研轻量 Runner Pool
Tekton 默认需要每个任务都新建一个 Pod,但我们发现对于轻量任务(比如 lint、test),这种开销太大了,影响构建效率。
所以我们自己做了一个共享式的 Runner Pool,在 Kubernetes 中预启动一组空闲容器,并根据任务类型动态注入脚本。这样避免了每次都要拉镜像、启动容器的时间浪费,实测平均构建时间下降了 40%。
3. 构建缓存优化
我们知道构建过程中的依赖下载是非常耗时的,特别是在 Node.js 和 Go 项目中。于是我们为每个项目加了一个“缓存 key”机制:
# 示例:缓存 node_modules 目录
cache_key=node_modules-${GIT_COMMIT}
结合 S3 兼容的对象存储,我们将这些缓存文件上传保存。后续相同 commit 的构建就可以直接复用缓存,极大提升了构建速度。
踩坑记录:那些年我们一起掉进去的陷阱
工具换了,问题也不少。下面是一些印象深刻的“血泪教训”。
🐞 Jenkins 插件兼容性问题
我们一开始想用 Jenkins 的 Tekton 插件来做集成,结果发现插件版本不匹配,导致部分 API 无法调用,调试起来极其痛苦。后来果断放弃插件,直接在 Jenkins 写 Groovy 脚本去调 Tekton API。
def response = sh(script: """
curl -X POST http://tekton-pipeline:8080/apis tekton.dev/v1beta1/namespaces/default/pipelineruns \
-H 'Content-Type: application/json' \
-d @tekton_run.json
""", returnStdout: true).trim()
虽然不够优雅,但至少稳定可用。
🔁 动态参数传递太难搞
初期我们尝试在 Jenkins 流水线中动态注入一些参数(比如分支名、commit hash),结果因为 Jenkins 的变量作用域和 shell 解析顺序搞错,各种莫名其妙的错误层出不穷。
最终解决方案是采用 JSON 配置文件 + sed 替换的方式:
sed -e "s/\${BRANCH}/${env.BRANCH}/" \
-e "s/\${COMMIT}/${env.GIT_COMMIT}/" \
template.yaml > generated.yaml
虽然原始,但胜在清晰明了,出问题也好查。
🧱 构建镜像拉取慢得离谱
最头疼的是在不同环境之间拉取 Docker 镜像速度太慢,尤其是在北京机房部署的节点拉上海机房仓库的镜像,简直像蜗牛爬。我们后来引入了 Harbor 的镜像代理,并且本地加了个镜像缓存加速器(类似 cnrm),效果立竿见影。
实施后的效果:不是简单的提速,而是彻底改变协作方式
经过半年多的努力,Phoenix 计划终于上线,带来了显著的变化:
| 指标 | 改造前 | 改造后 | 提升幅度 |
|---|---|---|---|
| 平均构建时间 | 6min | 3.5min | 42% |
| 构建成功率 | 78% | 92% | ↑14% |
| 新人上手所需文档时间 | 半天以上 | 30 分钟左右 | ↓60% |
| 同时并发任务数 | 最多 10 个 | 支持 50+ | ↑500% |
更重要的是,我们现在可以把 CI 配置统一管理,配合权限系统实现“谁提交谁负责”,真正做到了自动化闭环。
一些经验总结 & 建议
如果你也在规划或者重构你们的 CI 系统,这里有一些我真心建议你考虑的事情:
✅ 不要一开始就追求“一步到位”
CI 平台是个长期演进的系统,别想着一次性全部重写。最好是分阶段迭代,先从最痛的部分下手。
比如你可以:
- 先解决构建慢的问题 → 增加缓存 + 调整并发策略
- 再解决配置混乱的问题 → 推广标准化流水线模板
- 最后再考虑底层架构升级 → 引入 Tekton 或 Argo Workflows
每一步都落地后再推进下一步,不然很容易陷入“理想很丰满,现实很骨感”的泥潭。
✅ 不要过度依赖 UI 配置
虽然可视化界面看起来很方便,但它会带来一个问题:逻辑分散难以维护。我们曾经有个 Jenkins job 界面里嵌了好几个 Shell Script Block,根本没人敢动一行代码。
现在我们坚决要求所有构建流程都由代码定义(Infrastructure as Code),用 Git 来管理变更历史,这样不仅可追溯,也能方便做 diff 检查。
✅ 小心“工具万能主义”
不要觉得换一个工具就能解决所有问题。我们曾天真地以为只要换成 GitHub Actions 就万事大吉,结果发现一旦涉及私有网络、企业级权限控制,还是有很多定制开发要做。
所以一定要明确自己的需求边界。你是想要更好的开源体验?还是更看重平台成熟度?还是要跟已有系统做深度集成?这些问题想清楚,才能做出合适的决策。
最后的一点感悟
这几年折腾下来,我越来越觉得,持续集成不是一项技术活儿,更像是一种“软件工程文化”的体现。
它背后反映的其实是:
- 我们是否重视可重复的流程?
- 是否愿意为自动化投资时间和资源?
- 是否能把构建失败当作生产事故来看待?
有时候,一个好的 CI 工具可能不如一个认真的工程师重要。工具只是手段,真正的变化来源于组织对质量意识的提升。
所以如果你问我:“我现在应该用 Jenkins 还是 Tekton?”我的回答一定是:“先看看你团队能不能写出一个结构清晰的 pipeline.yml。”
毕竟,工具有尽头,而工程化的思维才是真正的生产力。
如果你喜欢这样的实战分享,欢迎留言交流你的 CI 实践经验。如果有想了解的具体技术细节,我也很乐意继续深入展开~

评论 0