流水线(Pipeline)基本概念与阶段划分

聊到 CI/CD,我觉得第一个要搞清楚的事就是:流水线到底是个啥?很多人把它想得太复杂,其实说白了,就是一条自动化的“传送带”。你把代码放上去,经过一道道工序,最后变成可以运行的软件。嗯,就这么简单。

什么是流水线?

我习惯用工厂的流水线来打比方。一辆汽车要组装,得先冲压车身、再焊接、然后涂装、最后总装。软件也一样:代码从开发者的本地仓库里出来,要先编译、跑测试、打包、部署、再监控。每个环节都自动触发,不用人盯着按按钮。

核心意义:让每一次代码变更都能快速、可靠地经过所有验证步骤,最终交付到用户手里。没有流水线,你就得手动做这些事——那效率可想而知。

我个人刚开始做持续集成的时候,其实连“构建”和“部署”的区别都没太搞清。有一次,我把构建产物直接扔到生产环境上,结果缺少依赖、跑不起来,被群里@了好几次……后来才明白,流水线里的每个阶段都有明确的责任边界。

流水线的核心阶段

根据我的经验,一条成熟的交付流水线一般会包含下面这几个阶段。当然,不同团队可能略作增减,但骨架基本一样。

阶段职责常见工具我的踩坑提醒
代码提交 触发流水线起点,进行代码检查 Git、Code Review 别忽略分支策略,直接往master推容易乱流
构建编译 把源码变成可执行的二进制或包 Maven、Gradle、Docker build 我曾经因为缓存不清理,导致构建产物藏着旧 bug
单元测试 验证最小代码单元的逻辑正确性 JUnit、pytest、jest 覆盖率别只看数字,关键路径一定要测到
集成测试 保证各模块之间能正常协作 Testcontainers、Selenium 环境漂移问题,我踩过几次“本地跑过,CI挂了”的坑
部署发布 将验证过的制品推送到目标环境 K8s、Ansible、Terraform 蓝绿部署可以,别一次全切,留条回退路
监控反馈 上线后的运行状态跟踪与告警 Prometheus、Grafana、Sentry 没有监控的流水线等于盲飞,我见过上线半小时才发现的严重事故

阶段之间的关系与依赖

你想想看,这些阶段不是孤立存在的。代码提交之后,构建如果失败,测试根本不会跑。同样,测试不通过,部署就卡住。这就构成了一个串行依赖链。不过,有些阶段可以并行,比如你可以在构建的同时跑静态代码扫描,这样可以缩短整体时长。

我习惯用一张图来展示典型的阶段流转关系。你看下面的流程,左边是开发端,右边是运行端,中间经过一条自动化流水线。

流水线核心阶段流转 代码提交 构建编译 单元测试 集成测试 部署发布 监控反馈 反馈环: 监控发现线上问题 → 修复代码提交 → 再次进入流水线 形成持续改进的闭环

这张图里,你看到一条直线串起五个阶段,从代码提交一直到部署发布。然后监控反馈通过虚线回路重新回到起点。这就是我常说的“流水线闭环”——不只是往下流,还要能反馈回来驱动改进。

小技巧:在实际配置中,我习惯在“集成测试”后面加一个“审批门”(gate),比如人工确认或自动化准入检查。这样能防止未充分验证的制品直接冲上线。

阶段划分的最佳实践

阶段怎么切,其实没有标准答案。但我建议你记住几个原则:

  • 职责单一:一个阶段只干一件事。构建阶段不要混着改数据库迁移,那只会让排查变得痛苦。
  • 快速反馈:把跑得最快、最容易失败的阶段放前面。比如先跑那些轻量的单元测试,再跑集成测试。你想想看,如果一开始就跑几分钟的全量集成,发现一次构建失败,那前面的几分钟就白费了。
  • 稳定隔离:构建、测试、部署的环境要尽量一致。我曾经因为构建环境的 JDK 版本跟测试环境不一样,导致一些 Java 特性在本地没问题,一上 CI 就报错。后来统一用 Docker 镜像固定版本,再也没出过这个幺蛾子。
  • 可跳过可重跑:偶发失败(flaky test)怎么办?我建议在阶段定义里加手动重试的能力,但一定要记录日志,方便排查根本原因。

特别注意:不要把生产数据库的写入操作放在部署阶段里!我见过一个团队在部署脚本里直接执行了 DDL,结果线上表被锁了半个小时。数据库变更应该作为一个独立的阶段,并且经过评审和备份。

最后再聊一个点:阶段命名。很多团队喜欢用“Stage1、Stage2”这种名字,到后期出了问题都不知道对应哪个环节。我习惯用“build”、“unit-test”、“int-test”、“deploy-canary”、“deploy-prod”、“monitor”这样一看就懂的英文名。毕竟流水线的 YAML 文件是给别人看的,自解释才省心。

嗯,关于流水线的基本概念和阶段划分就说到这里。你把这些基础打牢了,后面聊瀑布图监控才有根有据。