从零搭建 CI/CD 流水线:DevOps 自动化核心实践

1. 先理解 DevOps 自动化要解决什么问题

1.1 自动化不是把手工步骤替换成脚本

DevOps 自动化真正要解决的是反馈速度、一致性和可追溯性。
反馈速度指的是开发人员提交代码后,能够尽快知道代码是否破坏了已有功能。没有自动化时,这个反馈往往依赖人工测试;有了流水线后,可以在提交代码后自动执行编译、单元测试和接口测试。
一致性是指每次构建、部署和测试都尽可能在相同环境中执行,减少“在我机器上可以运行”的问题。
可追溯性则要求从代码提交到最终发布的整个过程都有记录,例如哪个版本部署到了哪个环境、谁触发了发布、测试结果如何等。

1.2 一条典型 DevOps 流水线的完整阶段

一条完整的流水线通常可以划分为以下阶段:
  1. 持续集成:代码提交后自动进行编译、单元测试和代码检查。
  1. 制品管理:构建产物使用唯一版本号,例如语义化版本号或 Git Commit Hash,并保存到制品库。
  1. 自动部署测试环境:将构建产物部署到开发或测试环境。
  1. 自动化测试:执行接口测试、UI 测试以及必要的性能冒烟测试。
  1. 持续交付:测试通过后生成随时可以发布到生产环境的版本。
  1. 持续部署:在质量检查全部通过后自动发布到生产环境。
需要区分持续交付(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 部署后的健康检查

部署成功并不代表服务真正可用。
至少需要检查:
  1. 容器是否正常运行;
  1. 端口是否监听;
  1. HTTP 接口是否能够访问;
  1. 数据库、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 报:
或者:
可以按照下面的顺序排查:
  1. 服务是否真的启动;
  1. 测试使用的地址是否正确;
  1. 测试 Job 与服务是否处于同一个网络;
  1. 网络策略是否允许访问;
  1. 服务是否监听在 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 链路跑通,让每一次代码提交都可以得到快速、稳定、一致的反馈,然后再逐步增加质量检查、监控、权限、发布策略和回滚机制。
网盘脚本CI/CD 自动化部署实践:让代码提交后自动上线
Loading...
迷途
迷途
OR的博客,用知识和技术创造未来!!!
Announcement
🎉OR科技,用心服务🎉
-- 分享知识,点亮生活 ---
保持热爱追逐远方
路虽远行则将至
事虽难不为不成
为之则易不为则难
👏欢迎您的来访👏
距离2026年春节仅有
-- 免责声明 ---
⚠️ 本站内容仅代表个人观点,可以转载,但请注明出处。 ⚠️ 本站分享内容仅供学习参考使用,请勿用于其他用途。