构建失败类型概览
说实话,干了这么多年 CI/CD,我见过最多的场景就是——开发小哥盯着红色构建记录,一脸茫然。
其实大多数失败都是有规律可循的。我把它们分成四大类:编译失败、测试失败、部署失败、环境问题。每类背后都有一套固定的排查套路。掌握了这些分类,你就能在第一时间锁定问题方向。
编译失败——最容易被揪出来的一类
编译失败,说白了就是你的代码压根没通过编译器这一关。我个人的经验是,这类问题在 CI/CD 构建日志里通常排在第一个,红字特别显眼。只要看到「Error:」开头,基本就跑不了。
常见的编译失败原因其实就那几样:
- 语法错误——少了个分号、括号不匹配,或者用了不支持的语法特性。我见过有人把 Python 的缩进和 Tab 混用,直接炸了整条流水线。
- 依赖缺失或版本冲突——比如项目里用了
lodash@4.17.21,但 package-lock.json 被篡改导致下载了旧版。或是 Java 项目里两个 jar 包冲突。 - 类型不匹配 / 接口变更——尤其在强类型语言里,比如 TypeScript 里传了个
number给string参数。或者是上游 API 改了方法签名,下游没同步更新。
我的习惯:在提交代码之前,先在本地跑一遍 mvn compile 或 tsc --noEmit。哪怕 CI 会再跑,提前发现能省下好几轮来回。
避坑指南:我曾经遇到过一个很隐蔽的编译失败——CI 节点上的 JDK 版本是 11,但本地开发用的是 17。代码里用了 var 和 record 特性,在 JDK 11 上直接报错。所以,一定要确保 CI 环境与目标部署环境一致。
测试失败——比编译失败更让人头大
编译通过了,但测试没通过。这种失败说明代码逻辑可能出了问题,或者测试用例写得不够健壮。你想想看,如果单元测试跑一半全绿,但突然一个集成测试挂了,你是不是得排查半天?
我把测试失败分成三种典型场景:
- 单元测试断言失败——比如你期望一个函数返回
true,但实际返回了false。这种最好定位,看具体断言语句就行。 - 集成测试超时或连接失败——比如测试中需要启动一个 Redis 容器,但容器没及时就绪,导致测试超时。我有个项目就是因为测试容器资源不足,经常随机失败。
- 覆盖率不达标——有些流水线会设置覆盖率门槛(比如 > 80%)。如果新增代码没写测试,流水线会直接拒绝合并。
快速定位方法:在日志里搜索 FAILED 或 ERROR,然后看测试报告的详情。如果是随机失败(flaky test),我建议先重跑一遍确认,别急着改代码。
部署失败——最让人抓狂的一类
编译和测试都过了,结果部署到服务器上失败了。说实话,这种失败最让人崩溃,因为前面所有步骤看起来都是绿的,偏偏在最后一刻红了。
部署失败的常见罪魁祸首:
- 容器启动失败——比如 Dockerfile 里
RUN apt-get update没加--no-install-recommends,导致镜像过大超时。或者是 entrypoint 脚本里路径写错了。 - 健康检查不通过——Kubernetes 的 livenessProbe 配置太严格,应用刚启动需要几秒预热,但健康检查 3 次就判定失败。
- 数据库迁移报错——比如新增了非空列但没有给旧数据设置默认值,迁移脚本直接回滚。
避坑指南:我曾经遇到一个部署失败,原因是 CI 的部署脚本用了 kubectl apply -f deployment.yaml,但镜像标签写的是 latest。最新的镜像还没推送完,部署脚本就已经拉取了旧的 latest。后来我强制改成 git commit hash 作为标签,问题再没出现过。
环境问题——最难排查的隐形杀手
环境问题不是代码逻辑有错,而是运行时环境与预期不一致。说白了就是「在我的机器上是好的」,但 CI 环境就是不行。
我遇到过最多的环境问题:
| 问题类型 | 典型表现 | 排查方向 |
|---|---|---|
| 密钥/凭据缺失 | 拉取私有仓库时 403 | 检查 CI 变量是否注入,比如 GITHUB_ |
| 资源配额不足 | Pod 一直 Pending,或构建任务被 OOM Kill | 查看节点资源使用率,调整资源请求/限制 |
| 网络策略拒绝访问 | 测试连接外部服务超时 | 查看 CI 运行环境的网络白名单是否漏配 |
| 环境变量差异 | 本地用 .env 文件,但 CI 没配置对应变量 |
逐个比对 CI 配置和本地 .env.example |
我的经验:遇到环境问题,第一步永远是在 CI 里加一行 printenv 或 env,打印出所有环境变量。很多时候你会发现,某个变量名字拼错了,或者根本就没被注入。
快速分类表——记住这个就行
为了让你在排查时能快速对号入座,我整理了一个总结表。当你看到红色构建时,先根据日志特征判断是哪一类,再按对应的套路去查。
| 失败类型 | 日志关键字 | 排查第一件事 |
|---|---|---|
| 编译失败 | error: , Cannot find module, Type mismatch |
看具体报错行号和文件 |
| 测试失败 | FAILED, expected ... but got ..., timeout |
看测试报告详情 |
| 部署失败 | CrashLoopBackOff, Exit code 1, Connection refused |
查容器日志 kubectl logs |
| 环境问题 | permission denied, No such file, resource exhausted |
检查 CI 变量和运行环境配置 |
嗯,这四种分类基本覆盖了我这几年遇到的所有 CI/CD 构建失败。你只要掌握了分类,下一步就是每种类型对应的具体排查方法——后面的章节我会逐一展开讲。