什么是CI/CD?
首先区分三个概念。持续集成(CI)要求开发者频繁集成代码,并通过自动化构建和测试尽早发现问题。持续交付(Continuous Delivery)要求通过验证的变更始终处于可发布状态,但生产发布可以由人决定。持续部署(Continuous Deployment)则把符合条件的变更自动发布到生产。
简单的说:CI是在接收到新代码后进行代码测试的流程。CD是在代码合入之后进行制品生产、发布的流程。
CI/CD 详细拆分
1. 【测试】静态检查
触发时机:PR 检查流程
静态检查分析源代码或配置文件,检查语法错误或拦截危险的语法糖。格式工具检查写法是否统一;类似 Lint 这种工具根据规则发现可疑代码;类型检查分析变量、函数参数和返回值能否匹配。它的优势是快、反馈早,但它通常不知道业务要求是什么。
2. 【测试】单元测试
触发时机:PR 检查流程
单元测试用于检查服务独立运行时的错误。单元测试把一个较小的业务单元单独拿出来,给它明确的输入,检查输出或行为。测试折扣计算函数时,不必启动数据库和整个 Web 服务。
3. 【测试】集成测试
触发时机:PR 检查流程
集成测试让两个或多个真实组件一起工作,用于检查服务共同运行时的错误。
4. 【测试】端到端测试(E2E)
触发时机:Release发布
端到端测试从用户入口出发,让前端、后端和数据库等组件共同运行,验证用户能否完成一条完整的业务流程,需要使用到一些专业的自动化测试工具,类似使用 Playwright 驱动无头浏览器。例如,自动打开网页,登录账号,使用优惠券并提交订单,最后检查页面显示和订单结果。由于它需要启动较完整的系统,通常比单元测试和集成测试慢,因此不必在每个 PR 中运行所有 E2E 场景。
5. 【测试】构建测试
触发时机:PR 检查流程,在代码合入前运行。
PR 构建验证检查当前变更能否成功编译、打包,或构建成容器镜像。例如,测试全部通过,但 Dockerfile 没有复制运行时需要的文件,构建验证就可能发现问题。这里的主要目的,是阻止"代码测试通过但根本无法构建"的变更合入;产生的结果通常不是正式发布制品。
6. 【构建】正式制品构建与保存
触发时机:代码合并后
流水线针对主分支上的确定版本构建正式制品,例如应用包或容器镜像,并赋予与代码提交关联的唯一标识,再保存到制品仓库。后续部署环境使用这份制品。
7. 【部署】测试或预发布环境部署
触发时机:手动触发
CD 流程取得正式制品,将其部署到测试或预发布环境,然后检查服务能否启动、配置是否正确,以及关键功能是否可用。涉及数据库迁移或外部服务对接时,可以在这里运行相应的部署验证和更完整的 E2E 测试。验证失败时,应阻止该制品继续发布到生产。
8. 【发布】生产环境部署
触发时机:手动触发
CD 流程将同一份已经验证的制品部署到生产环境。这个流程需要管理生产配置和密钥、控制部署权限,并记录发布的是哪个版本、何时发布以及结果如何。保留人工确认仍属于持续交付;如果检查通过后无需逐次人工确认、自动部署到生产,则属于持续部署。
9. 【恢复】发布失败处理
触发时机:部署失败
支持快速回滚
不同的阶段应当配置哪些CI/CD自动化流程?
对于一个项目来说,我们应当有合适的 CI/CD 流程。这些自动化流程不能过于简单,否则会导致日常开发中需要大量手动配置,消耗我们大量的时间;如果过于冗余,则会导致 CI/CD 的自动化管理困难,甚至可能触发一些意想不到的情况。
对于项目,我简单了划分为四个阶段:
- 原型阶段:主要目标是验证想法,代码和部署方式可能频繁变化,甚至有可能放弃项目。
- MVP阶段:项目开始进行第一版的开发。
- 正式生产阶段:项目的一些能力已经得到了验证,要进行后续的功能开发。
- 成熟运营阶段:持续迭代
原型阶段不需要搭建 CI/CD。
MVP阶段需要搭建基础测试(静态、单元、构建),构建制品流程自动化
正式生产阶段在此基础上增加E2E测试,测试或预发布环境部署
成熟运营阶段再增加生产环境自动化部署,发布失败自动化处理
其他想法补充
- LLM Check 也是一个很好的方向,但是现在笔者并不认可用于CI流程中,因为代码的编写已经交给Agent来处理了,如果需要大模型参与审核,至少我现在不会把它放到CI中。