我们团队原来的 CI 是 Jenkins,一台老Ubuntu 服务器,Job 用网页点出来的,配置存在它肚子里,谁也说不清有哪些步骤。新人想加一条发布流水线,得先找老员工"口述"。这种不可见的配置,迟早要还债。借着一次 GitLab 迁移,我把流水线整体搬到了 GitLab CI。
不是嫌 Jenkins 不好
Jenkins 没问题,问题是我们的用法:自由风格 Job、手工配节点、脚本散落在各处。构建结果不跟代码走,分支一多就乱。GitLab CI 的卖点是"流水线即代码"——.gitlab-ci.yml 跟仓库在一起,Review 和回滚都走 MR,这正中痛点。
语法对比:从 Stage 到 Job
Jenkinsfile 的声明式写法是 pipeline { stages { stage('build') { steps { ... } } } },GitLab CI 更扁平,直接列 Job,用 stage 关键字分组:
stages:
- build
- test
- deploy
build-job:
stage: build
script:
- ./mvnw -q clean package -DskipTests
artifacts:
paths:
- target/*.jar
expire_in: 1 hour
最大的差异是产物传递:Jenkins 靠工作空间共享,GitLab CI 靠 artifacts 显式声明。一开始我漏了 artifacts,test 阶段找不到 jar 包,白白重跑 build。这个"显式传递"反而逼出更清晰的依赖关系。
Runner 配置:别用共享 Runner 跑生产
GitLab.com 的共享 Runner 免费但慢、且不可控。我们自建了 Runner,装在 K8s 里,用 gitlab-runner register 挂到项目:
[[runners]]
url = "https://gitlab.com/"
token = "xxxx"
executor = "kubernetes"
[runners.kubernetes]
namespace = "gitlab-ci"
[runners.kubernetes.pod_spec] # 限制资源,避免一个 Job 吃满节点
关键配置是给 Runner 加标签(tag),生产部署的 Job 只允许带 prod 标签的 Runner 跑,普通构建用默认的。权限隔离比图省事重要。
缓存优化:把 Maven 拉包时间砍掉
没缓存时,每次构建都重新拉依赖,光 mvn package 的下载就要 3 分 40 秒。加了缓存后:
cache:
key: maven-$CI_COMMIT_REF_SLUG
paths:
- .m2/repository
构建时间从 4 分 10 秒降到 1 分 05 秒,提速约 75%。但缓存有坑:key 用分支名时,冷分支第一次还是全拉;我们后来改成 key: maven-main 全分支共享一份,命中率更高,代价是偶尔拉到别人分支的依赖——对内部库要注意 SNAPSHOT 污染,主仓用 release 版本规避。
迁移中踩的坑
- secrets 管理:Jenkins 的凭据直接挪到 GitLab CI Variables,但注意
protected变量只在受保护分支暴露,我在 feature 分支跑部署 Job 调不到 token,排查了半小时; - 并发数:默认 Runner 并发是 1,排队严重,调到
concurrent = 8才顺畅; - Docker in Docker:构建镜像需要
docker build,Runner 用docker挂载而非 dind,速度快一半且少一个容器层级。
留个问题
关于《从 Jenkins 到 GitLab CI 的流水线迁移》里这个坑,你当时是怎么处理的?欢迎在评论区聊聊你踩过的类似情况。