CI/CD 基础概念与常见失败概述

说实话,我做了快十年的 DevOps,接触过上百个 CI/CD 流水线。每次跟新人聊,他们最容易犯的错就是——把 CI/CD 当成“一键部署神器”。可实际上,流水线跑不跑得通,往往取决于你最不在意的那行配置。

这一章我们先打好地基。搞清楚 CI/CD 到底是什么,流水线里藏着哪些坑,以及为什么失败是常态、不是意外。

CI/CD 到底是什么?

CI(持续集成)和 CD(持续交付/持续部署)是两回事,但经常被混着说。我个人习惯这样理解:

  • 持续集成(CI):每次代码合并到主干,自动触发构建和测试。目标是尽早发现问题。说白了,就是不让“我本地能跑”的借口拖到上线后才暴露。
  • 持续交付(CD):CI 通过后,自动把产物部署到类生产环境(比如预发布),再由人工决定是否上线。加了一层安全阀。
  • 持续部署(CD):CI 通过后,直接自动部署到生产环境。这个“胆量”不是每个团队都有的。

我记得有一年帮一家电商公司搭流水线,他们原来的流程是:开发写完代码,手动打包,运维手工部署。每次上线都是凌晨三点,还经常回滚。后来拆成 CI + 持续交付,光是测试时间就缩短了 70%。

一句话总结:CI 是“代码合并后自动检查和打包”,CD 是“把打包好的东西自动送到它该去的地方”。

核心流水线长什么样?

不管工具是 Jenkins、GitLab CI、GitHub Actions 还是 CircleCI,流水线的骨架都差不多。你想想看,它分这么几个阶段:

  1. 代码拉取与静态检查 – 拉分支、跑 Linter、代码规范扫描。
  2. 构建 – 编译、打包(比如 Maven、npm build)。
  3. 单元测试 & 集成测试 – 跑用例、生成覆盖率报告。
  4. 安全扫描 & 镜像构建 –(可选)扫描依赖漏洞,打容器镜像。
  5. 部署到测试/预发布环境 – 自动 push 到对应环境。
  6. 验收测试 & 人工审批 –(可选)冒烟测试,等负责人点确认。
  7. 生产部署 – 灰度、蓝绿、或直接全量。

下面是这一章的知识体系图,我把它画成了一张流程 + 失败点对应图。

CI/CD 核心流程与常见失败点 代码提交与静态检查 构建 & 单元测试 集成测试 & 安全扫描 交付/部署到环境 ❌ 构建失败(缺依赖、语法错) ❌ 测试失败(断言挂、超时) ❌ 基础设施问题(资源不足) ❌ 部署失败(凭据、配置错误) 延迟交付(阻塞合并) 回滚风险(代码质量降低) 成本浪费(重跑、人工排查) 团队信任下降(流水线噪音) 提示:每个失败点都不止一个根因,后续章节我们会逐个拆解。

最常见的 CI 失败类型

根据我在团队里看到的统计(以及踩过的坑),失败可以归成下面几类。我自己整理了一个对照表:

失败类别 典型表现 高频原因 影响等级
构建失败 编译报错、找不到依赖、版本冲突 代码合并冲突,依赖锁文件未更新,环境差异 🔴 高(阻塞合并)
测试失败 单元测试断言失败,集成测试超时 测试数据污染,Mock 不匹配,时间敏感 🟡 中(需要人工确认)
基础设施问题 Runner 离线、磁盘满、网络超时 资源不够用,证书过期,DNS 解析 🔴 高(全阻塞)
部署失败 部署脚本报错、k8s apply 失败、健康检查不通过 配置错误、权限不足、镜像 tag 不存在 🔴 高(影响上线)
人因 / 流程问题 漏提代码、忘记更新版本号、审批流程卡住 沟通不足、CI 配置过于复杂 🟡 中(可快速修复)

我的经验:很多团队把 80% 的精力花在写测试上,却忽略了构建环境的稳定性。我曾遇到一个项目,每周构建失败超过 30 次,结果八成是因为 Runner 节点内存不足。后来加了资源监控,失败率直接降到 5% 以下。

避坑指南:别让流水线变成“烂尾楼”

当我刚开始做 CI/CD 时,最常犯的一个错就是:一次性设计一个特别“完美”的流水线,恨不得把所有的扫描、测试、部署步骤都揉进去。结果呢?

  • 一个构建动不动跑 40 分钟。
  • 失败点太多,开发看到红色就麻木了。
  • 没人愿意修流水线,因为太复杂。

我建议:先让它能跑通最简单的路径,再逐步加料。比如你可以先从下面这个最小化配置开始:

# 一个极简的 GitLab CI 配置
stages:
  - build
  - test

build_job:
  stage: build
  script:
    - echo "Building..."
    - npm install
    - npm run build

test_job:
  stage: test
  script:
    - echo "Running tests..."
    - npm test

注意:别把 npm install 和 npm test 写在同一个 job 里。一旦 test 失败,你完全不知道是 install 阶段出了问题还是 test 本身挂了 —— 这是我在生产线上亲眼见过的“黑盒失败”。

失败是信号,不是噪音

其实,CI 失败本身不是坏事。它就像一个警报器,告诉你哪个环节有风险。我见过最健康的团队,他们的流水线失败率在 15%~25% 之间。为什么?因为他们设置了足够多的检查点,胆敢让流水线暴露问题。

相反,如果一个团队的 CI 从来没有红过,那才要担心——可能是测试覆盖率只有 5%,也可能是构建永远只在本地跑。