构建失败类型概览

说实话,干了这么多年 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 环境与目标部署环境一致。

测试失败——比编译失败更让人头大

编译通过了,但测试没通过。这种失败说明代码逻辑可能出了问题,或者测试用例写得不够健壮。你想想看,如果单元测试跑一半全绿,但突然一个集成测试挂了,你是不是得排查半天?

我把测试失败分成三种典型场景:

  1. 单元测试断言失败——比如你期望一个函数返回 true,但实际返回了 false。这种最好定位,看具体断言语句就行。
  2. 集成测试超时或连接失败——比如测试中需要启动一个 Redis 容器,但容器没及时就绪,导致测试超时。我有个项目就是因为测试容器资源不足,经常随机失败。
  3. 覆盖率不达标——有些流水线会设置覆盖率门槛(比如 > 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 构建失败。你只要掌握了分类,下一步就是每种类型对应的具体排查方法——后面的章节我会逐一展开讲。