CI管道基础:CI/CD概念与三大工具核心工作流
说实话,干了这么多年DevOps,我见过太多团队把CI/CD当成「玄学」——配置了半天,一提交代码就崩。其实CI/CD没你想的那么复杂。咱们今天就把这三个主流工具掰开了聊,顺带讲讲我踩过的坑。
CI/CD到底在解决什么问题?
我先问你个问题:每次代码合并到主分支,你是不是提心吊胆?生怕一个冲突把线上搞挂了?CI/CD说白了就是帮你自动化这个「提心吊胆」的过程。
- 持续集成(CI):每次代码提交都自动构建、跑测试。早期发现问题,别拖到上线前。
- 持续交付(CD):通过CI的代码自动部署到类生产环境。注意,不一定直接上生产。
- 持续部署(CD):CI通过后直接自动推到生产。嗯,这需要你足够自信,或者测试覆盖率足够高。
我个人习惯:团队还没达到80%单元测试覆盖率之前,别开持续部署。我曾经在一个项目里强行上CD,结果一次测试漏报导致生产宕机两小时……从那以后我学会了「保守一点」。
三大CI/CD工具核心工作流对比
市面上工具很多,但主流就这三个:Jenkins、GitLab CI、GitHub Actions。我分别讲下它们的核心逻辑。
1. Jenkins —— 老牌王者
Jenkins的核心是「主从架构」。主节点负责任务调度,从节点(Agent)负责执行。工作流靠Pipeline DSL描述。
pipeline {
agent any
stages {
stage('Checkout') {
steps { git 'https://github.com/example/repo.git' }
}
stage('Build') {
steps { sh 'mvn clean package' }
}
stage('Test') {
steps { sh 'mvn test' }
}
stage('Deploy') {
steps { sh 'kubectl apply -f deploy.yaml' }
}
}
}
我记得第一次配Jenkins,被它的插件生态吓到了——两千多个插件,但真正常用的就二十来个。别贪多,装多了反而容易版本冲突。
2. GitLab CI —— 一体化体验
GitLab CI把代码托管、CI/CD、容器注册表全揉在一起。工作流靠.gitlab-ci.yml文件控制,每个任务叫Job,任务集合叫Stage。
stages:
- build
- test
- deploy
build-job:
stage: build
script:
- mvn clean package
test-job:
stage: test
script:
- mvn test
deploy-job:
stage: deploy
script:
- kubectl apply -f deploy.yaml
only:
- main
这里有个坑:stages必须按拓扑顺序定义,Job之间如果有依赖,你得自己控制。我踩过「test跑完了才开始build」的荒唐事,因为stage写反了。
3. GitHub Actions —— 云原生的新秀
GitHub Actions的核心概念是「Workflow」→「Job」→「Step」。每个Workflow由事件触发(比如push、pull_request),运行在GitHub托管的Runner上。
name: CI Pipeline
on: [push, pull_request]
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: '17'
- run: mvn clean test
- run: mvn package
GitHub Actions最大的好处是「开箱即用」,不需要自己维护Runner。但我建议你们公司人多的话还是自建Runner,免费额度跑一个月就没。
要点速览:三个工具本质都是在「事件触发→流水线执行→产物输出」这个循环里转。区别在于:
- Jenkins:灵活,插件多,但搭建维护成本高。
- GitLab CI:一体,天然与GitLab仓库绑定,适合GitLab生态。
- GitHub Actions:轻量,云端,社区Actions库丰富。
核心工作流:一个通用模型
不管用哪个工具,CI管道的核心工作流其实都差不多。我画了个图帮你梳理下——
避坑指南:我曾经在一个项目里把「测试通过」和「制品打包」放在同一个Stage里,结果测试失败时构建产物已经上传了。正确做法是保证Stage之间的依赖走向是单向的,失败就立即中断,别让后续步骤捡到脏数据。
Pipeline阶段的核心分工
不管用Jenkins的Declarative Pipeline,还是GitLab CI的YAML,亦或是GitHub Actions的Workflow,你都得把下面这几个阶段想清楚。我习惯用这张表来跟团队对齐——
| 阶段 | 核心目标 | 常见工具 | Mock回放能做什么? |
|---|---|---|---|
| 1. Checkout | 获取最新代码 | git, svn | 无直接关系 |
| 2. Build | 编译、依赖解析 | Maven, Gradle, npm | 无直接关系 |
| 3. Test | 验证代码正确性 | JUnit, pytest, Jest | 注入Mock数据,回放录制流量 |
| 4. Package | 打包成可部署制品 | Docker, tar, jar | 无直接关系 |
| 5. Deploy | 发布到环境 | kubectl, ansible | 部署后验证时可回放Mock |
关键认知:Mock回放不是替代测试,而是把那些依赖外部服务(第三方API、数据库、云服务)的测试场景「固化」下来。这样你的CI管道就不再受外部环境波动影响了。我曾在电商项目里用Mock回放模拟支付回调,从此再也不用担心测试环境没钱扣。
三种工具在Mock回放场景下的配置差异
虽然核心工作流一样,但三种工具的配置方式各有千秋。我给你列几个实战中常见的配置点——
- Jenkins:通常用Pipeline插件里直接跑
sh 'python mockserver.py',或者用docker run启动Mock容器。注意清理,别让Mock服务占着端口。 - GitLab CI:可以在
services字段声明一个Mock容器作为服务依赖。这招特别好用,因为GitLab CI会自动帮你管理容器生命周期。 - GitHub Actions:用
services类似,但可以配合job.services来实现。另外GitHub生态里有现成的Mock Actions,比如MockServer action。
嗯,这里要特别提醒一下:不管用哪个工具,Mock服务的端口映射一定要和你的被测代码里写的地址一致。我有一次忘了映射端口,Mock回放跑了一小时全失败——因为代码连的是localhost:8080,Mock却跑在8081。
个人建议:先在本地跑通Mock回放脚本,再塞进CI管道。别像我一样,直接在Jenkins里写十行sh,结果排错排了一天。
好了,CI管道的核心概念和三大工具的工作流就先聊到这儿。接下来你就可以拿着这张图去给团队画大饼了——不对,是讲解CI管道的最佳实践。