从零搭建 CI/CD 流水线:DevOps 自动化核心实践
1. 先理解 DevOps 自动化要解决什么问题
1.1 自动化不是把手工步骤替换成脚本
DevOps 自动化真正要解决的是反馈速度、一致性和可追溯性。
反馈速度指的是开发人员提交代码后,能够尽快知道代码是否破坏了已有功能。没有自动化时,这个反馈往往依赖人工测试;有了流水线后,可以在提交代码后自动执行编译、单元测试和接口测试。
一致性是指每次构建、部署和测试都尽可能在相同环境中执行,减少“在我机器上可以运行”的问题。
可追溯性则要求从代码提交到最终发布的整个过程都有记录,例如哪个版本部署到了哪个环境、谁触发了发布、测试结果如何等。
1.2 一条典型 DevOps 流水线的完整阶段
一条完整的流水线通常可以划分为以下阶段:
- 持续集成:代码提交后自动进行编译、单元测试和代码检查。
- 制品管理:构建产物使用唯一版本号,例如语义化版本号或 Git Commit Hash,并保存到制品库。
- 自动部署测试环境:将构建产物部署到开发或测试环境。
- 自动化测试:执行接口测试、UI 测试以及必要的性能冒烟测试。
- 持续交付:测试通过后生成随时可以发布到生产环境的版本。
- 持续部署:在质量检查全部通过后自动发布到生产环境。
需要区分持续交付(Continuous Delivery)和持续部署(Continuous Deployment)。
持续交付强调每次代码变更后都能够产生可发布版本,但生产发布通常仍然由人工确认。
持续部署则更进一步,在质量关卡全部通过后直接自动发布到生产环境。
对于刚开始建设流水线的团队,通常先从持续交付开始,等监控、回滚和质量体系成熟后,再逐步向持续部署演进。
1.3 自动化程度越高,出问题时越难排查
自动化并不意味着问题会减少到零。随着流水线复杂度增加,故障来源也会增加,例如:
- 构建缓存异常
- 镜像拉取失败
- 配置注入错误
- 测试数据问题
- 环境变量配置错误
- 网络策略问题
- 服务启动时间过长
因此设计流水线时,每一个阶段都应该有清晰的日志和状态反馈。
构建阶段应该能够看到依赖下载、编译和测试情况;部署阶段应该能够看到目标环境、镜像版本、启动时间和健康检查结果;测试阶段应该能够看到测试总数、通过数、失败数以及具体失败日志。
2. 常用 DevOps 工具栈选型
2.1 工具不是越多越好,先满足最小闭环
DevOps 工具非常多,从代码仓库、CI 引擎到制品库、测试框架和部署平台,每一个环节都有很多选择。
学习阶段最容易出现的问题,是看到什么热门工具都想使用,最后工具很多,但完整链路没有真正跑通。
更实际的方式是先建立一个最小闭环:
环节 | 轻量方案 | 中大型团队常用方案 | 说明 |
代码仓库 | GitLab / Gitea | GitHub / GitLab | 尽量选择具备 CI/CD 能力的平台 |
CI/CD 引擎 | GitLab CI / Jenkins | Jenkins / GitHub Actions / Argo Workflows | 初期选择一个即可 |
制品管理 | 本地 Nexus / 容器镜像仓库 | Harbor / JFrog Artifactory | 镜像和软件包必须有版本 |
测试框架 | pytest + Requests | JUnit / TestNG / Pytest / Playwright | 根据语言和项目选择 |
部署目标 | Docker | Kubernetes | 没有复杂调度需求时 Docker 更简单 |
工具选型没有绝对答案。
小团队使用 GitLab CI + Docker + pytest 就可以形成完整的自动化闭环;大型团队则可以根据规模引入 Kubernetes、Harbor、监控和更加复杂的发布系统。
2.2 为什么 Jenkins 仍然是学习 DevOps 自动化的经典入口
Jenkins 的插件生态比较成熟,Git、Maven、Docker、Kubernetes、SonarQube 等都有大量现成插件。
同时 Jenkins Pipeline 有声明式和脚本式两种写法,其中声明式 Pipeline 的结构比较适合学习流水线的阶段、条件和执行逻辑。
另外,大量已有企业项目仍然在使用 Jenkins,因此掌握 Jenkins Pipeline 对理解传统 CI/CD 体系仍然有价值。
不过 Jenkins 也存在插件管理复杂、资源消耗较高、配置迁移麻烦等问题。
如果团队是从零开始建设流水线,可以根据实际情况评估 GitLab CI 或 GitHub Actions 等方案。
2.3 自动化测试工具如何选择
自动化测试需要根据测试对象选择工具。
接口自动化通常具有较高的投入产出比。Python 项目可以使用:
Java 项目则可以考虑:
接口测试执行速度快、稳定性相对较高,也比较适合作为 CI/CD 流水线中的质量关卡。
UI 自动化则需要谨慎使用。UI 测试虽然可以覆盖完整用户流程,但执行速度较慢,页面元素发生变化后也容易导致测试失败。
Web UI 可以考虑 Playwright 或 Selenium,移动端则可以考虑 Appium。
单元测试和静态代码扫描同样应该尽可能提前执行,这样能够在代码进入后续阶段之前发现问题。
3. 环境准备与项目结构
3.1 学习环境如何快速搭建
学习阶段不建议一开始就搭建复杂的生产级 DevOps 平台,否则很容易把大量时间消耗在基础设施本身,而忽略流水线的核心流程。
可以先准备一台 Linux 服务器、虚拟机或者本地 Linux 环境。
基础软件可以参考:
软件 | 版本建议 | 用途 |
Docker | 20.10+ | 运行 Jenkins、测试环境等 |
Docker Compose | 2.x | 编排本地环境 |
Git | 2.x | 代码版本管理 |
JDK | 11 / 17 | Jenkins 和 Java 项目 |
Python | 3.8+ | pytest 接口测试 |
如果机器资源比较小,需要注意 Jenkins、测试服务和其他组件之间的资源竞争。
生产环境中通常还需要进一步将 CI 节点、测试节点和部署节点进行隔离。
3.2 示例项目结构
为了完整演示流水线,可以准备一个简单的 Spring Boot 订单查询服务:
业务代码与测试代码分离,可以让流水线分别执行单元测试和接口测试。
3.3 提前确认依赖版本
流水线中的很多问题实际上来自版本不匹配。
例如 Maven 构建需要确认仓库地址;Spring Boot 需要与 JDK 版本匹配;pytest 和 Requests 也应该尽可能锁定依赖版本。
如果项目没有明确指定版本,正式搭建流水线前最好先确认:
- JDK 版本
- Spring Boot 版本
- Maven 版本
- Python 版本
- pytest 版本
- Requests 版本
- Docker 版本
不要因为开发机器可以运行,就默认 CI 环境一定可以运行。
4. 构建流水线:从代码提交到自动化测试
4.1 GitLab CI 最小流水线
GitLab CI 使用项目根目录下的
.gitlab-ci.yml 定义流水线。一个基本的构建、测试、部署流程可以写成:
这里有几个关键点。
cache 可以缓存 Maven 本地仓库,避免每次流水线都重新下载所有依赖。artifacts 可以保存构建产物,让后续 Job 使用之前生成的文件,而不需要重复编译。接口测试通过
API_BASE_URL 指定测试服务地址。部署阶段只针对
main 分支执行,可以避免开发分支每次提交都产生正式镜像。4.2 Jenkins Pipeline 对照实现
如果使用 Jenkins,可以在项目中创建
Jenkinsfile:Jenkins Pipeline 的优势是可编程能力比较强,可以利用 Groovy 实现条件判断、循环、函数、超时和并发等逻辑。
不过 Pipeline 越复杂,维护成本也会越高,因此不建议为了“高级”而进行过度抽象。
4.3 Dockerfile 和镜像构建
Spring Boot 项目可以使用多阶段构建:
多阶段构建可以将构建环境和运行环境分离。
最终镜像只需要运行 Java 应用,不需要包含 Maven 和完整 JDK,因此可以降低镜像体积。
另外,
pom.xml 单独复制后执行依赖下载,可以充分利用 Docker Layer Cache。生产环境不建议使用:
作为唯一版本标识。
更推荐:
或者:
这样可以准确知道某个容器到底运行的是哪个版本,也方便回滚。
4.4 自动化接口测试
pytest 可以编写类似这样的接口测试:
测试至少应该覆盖:
- 正常场景
- 异常场景
- 参数校验
- 关键业务字段
不能只判断 HTTP 状态码。
例如接口返回
200 并不意味着业务数据一定正确,因此还应该对响应 JSON 中的关键字段进行断言。conftest.py 可以用来定义公共 Fixture:5. 质量卡点、健康检查和回滚
5.1 质量卡点
自动化测试在 CI/CD 中不仅仅是为了“跑测试”,还承担着质量关卡的作用。
如果测试失败,就应该停止后续部署,防止有问题的构建产物进入下一阶段。
例如:
具体质量标准应该结合项目实际情况制定,例如:
- 单元测试覆盖率达到指定标准
- 接口测试全部通过
- 核心业务冒烟测试通过
- 静态代码扫描没有严重问题
需要注意的是,如果测试用例本身经常随机失败,那么流水线会被大量“假失败”阻塞。
这时候应该优先解决测试稳定性,而不是简单关闭质量检查。
5.2 部署后的健康检查
部署成功并不代表服务真正可用。
至少需要检查:
- 容器是否正常运行;
- 端口是否监听;
- HTTP 接口是否能够访问;
- 数据库、Redis 等依赖是否正常。
例如:
Spring Boot 项目可以引入 Actuator,通过:
检查应用健康状态。
在自动化测试开始之前先执行健康检查,可以避免测试请求发送到尚未启动完成的服务。
5.3 最小生产回滚方案
生产环境必须考虑回滚。
Docker Compose 可以把镜像版本作为环境变量:
需要回滚时,只需要切换到之前保存的镜像版本。
如果使用 Kubernetes,则可以通过:
回滚到之前的 Deployment 版本。
这里有一个很重要的原则:
回滚应该使用已经构建并经过验证的历史镜像,而不是临时重新编译代码。
重新编译得到的产物不一定与之前完全一致,无法保证真正恢复到原来的运行状态。
6. 常见问题排查
6.1 构建阶段失败
如果 Maven 出现依赖下载失败或编译错误,首先查看日志中真正失败的模块。
重点判断是:
还是:
或者:
网络问题可以检查 Maven
settings.xml 中的镜像配置,也可以使用内部 Maven 仓库。代码问题则应该直接修复代码后重新提交。
同时要注意,流水线日志不能输出:
- 密码
- Token
- 私钥
- API Key
- 数据库连接凭证
这些内容应该使用 Jenkins Credentials 或 GitLab CI/CD Variables 等密钥管理机制。
6.2 接口测试连接被拒绝
如果 pytest 报:
或者:
可以按照下面的顺序排查:
- 服务是否真的启动;
- 测试使用的地址是否正确;
- 测试 Job 与服务是否处于同一个网络;
- 网络策略是否允许访问;
- 服务是否监听在
0.0.0.0而不是127.0.0.1。
Docker 环境中可以查看网络:
6.3 健康检查正常,但业务测试失败
这种情况比较常见。
例如:
并不代表订单接口一定正常。
原因可能是:
- 数据库还没有初始化完成;
- Redis 没有准备好;
- 测试数据不存在;
- 测试数据状态不符合预期;
- 消息队列等依赖没有准备好。
因此健康检查与业务测试应该分开理解。
测试开始之前,需要准备测试数据;测试结束后,还应该清理测试数据。
6.4 流水线偶发失败
如果相同代码有时成功、有时失败,需要重点排查:
资源问题
例如:
测试用例问题
例如多个测试用例之间共享可变数据,导致执行顺序影响结果。
外部服务问题
例如依赖服务响应时间不稳定,需要设置合理的超时、等待和重试策略。
偶发失败通常比固定失败更加难排查,因此应该优先处理。
7. 从学习环境到生产环境
把学习环境中的流水线跑通以后,不建议直接原样用于生产。
可以按照下面的方向逐步完善:
检查项 | 学习环境 | 生产环境 |
配置管理 | 配置文件硬编码 | 配置中心 / 环境变量 |
敏感信息 | 明文或本地配置 | 密钥管理 |
日志 | 控制台输出 | ELK / Loki 等集中式日志 |
监控 | 无 | Prometheus + Grafana |
制品管理 | 单仓库 | 按环境隔离 |
权限控制 | 所有人可触发 | 限制生产发布权限 |
回滚 | 没有演练 | 定期进行发布与回滚演练 |
尤其需要注意配置和敏感信息。
生产环境不应该把数据库密码、Token、API Key 等信息直接写在 Git 仓库中。
同时,除了验证程序能够启动,还应该验证:
- 正常输入
- 异常输入
- 边界条件
- 错误处理
- 日志
- 依赖服务
- 健康检查
8. 最佳实践与扩展方向
刚开始搭建 DevOps 自动化体系时,可以优先做好下面三件事情。
8.1 优先接口自动化
接口测试通常比 UI 测试更加稳定,而且执行速度更快。
因此可以先把:
这条最小链路跑通。
之后再根据业务需要增加 UI 自动化。
8.2 测试数据必须隔离
测试环境中的数据应该能够重复创建和清理。
不要让测试用例依赖某一个长期存在的数据库状态。
比较合理的方式是:
这样流水线每次运行都尽量保持一致。
8.3 把流水线本身当成代码
.gitlab-ci.yml 和 Jenkinsfile 都应该进入版本管理。修改流水线配置时,也应该进行代码评审,而不是直接在服务器上修改。
同时可以持续记录:
- 流水线执行时间
- 成功率
- 失败率
- 失败阶段
- 测试耗时
- 部署耗时
随着项目发展,还可以进一步扩展:
- 多节点并行执行测试;
- 引入全链路追踪;
- 使用 Kubernetes 进行部署;
- 增加灰度发布;
- 增加蓝绿发布;
- 增加自动回滚;
- 增加 Prometheus + Grafana 监控。
DevOps 自动化并不是一次性完成的。
更实际的方式是先把最基础的 CI/CD 链路跑通,让每一次代码提交都可以得到快速、稳定、一致的反馈,然后再逐步增加质量检查、监控、权限、发布策略和回滚机制。
- Author:迷途
- URL:http://blog.ortech.nyc.mn/%E7%9F%A5%E8%A1%8C%E5%90%88%E4%B8%80/devops
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
Relate Posts






