2. GitLab CI/CD核心机制回顾
在开始排查复杂流水线故障之前,必须先建立一张清晰的“对象地图”。GitLab CI/CD 的故障往往不是单点错误,而是多个对象之间的协作断裂:job 卡住可能是 runner 标签不匹配,artifact 丢失可能是依赖关系写错,cache 未命中可能是 key 设计不合理。理解每个对象在流水线中的位置和职责,才能在日志、界面和配置之间快速定位问题。
从一次提交到流水线:对象如何被创建
当开发者向 GitLab 推送代码或创建合并请求时,GitLab 会读取仓库根目录下的 .gitlab-ci.yml,解析其中的 stages、jobs、script、rules 等关键字,生成一条 pipeline。pipeline 是一次完整的持续集成运行实例,它包含若干 stage,每个 stage 下又包含一个或多个 job。stage 决定执行顺序:同一 stage 内的 job 可以并行,只有当前 stage 全部成功,下一 stage 才会开始。job 是实际执行的最小单元,它声明了要运行的脚本、依赖的 artifact、使用的 cache、以及由哪类 runner 来执行。
pipeline、stage、job 三者是“定义层”的对象,它们描述“要做什么”。而 runner、executor 是“执行层”的对象,它们决定“在哪里、以什么方式做”。artifact 和 cache 则是“数据层”的对象,它们解决“执行过程中产生的文件如何传递和复用”。故障诊断时,先判断问题发生在哪一层,能大幅缩小排查范围。
Runner 与 Executor:执行层的两个关键角色
Runner 是安装在某台机器上的 GitLab 代理进程,它向 GitLab 注册后,持续轮询是否有可执行的 job。Runner 可以携带 tags,job 通过 tags 声明自己需要哪类 runner。如果 job 的标签与任何在线 runner 都不匹配,job 会一直处于 pending 状态,界面显示“This job is stuck”。这是故障诊断中最常见的“卡住”原因之一,排查时应先确认 runner 是否在线、标签是否拼写一致、runner 是否被暂停或达到并发上限。
Executor 是 runner 内部真正执行 job 的机制,常见类型包括 shell、docker、docker-machine、kubernetes 等。Executor 决定 job 运行在宿主机 shell 中,还是运行在容器、Kubernetes Pod 中。不同 executor 的故障特征不同:docker executor 可能因镜像拉取失败、私有仓库认证失败而报错;shell executor 可能因宿主机缺少依赖、权限不足而失败;kubernetes executor 可能因 Pod 调度失败、资源配额不足而超时。诊断时看到 job 日志开头几行,通常就能判断 executor 类型和初始化是否成功。
Artifact 与 Cache:数据层的传递与复用
Artifact 是 job 执行后上传到 GitLab 的文件集合,用于在后续 stage 的 job 之间传递构建产物。例如 build job 生成 dist/ 目录,通过 artifacts:paths 声明后,deploy job 可以用 dependencies 或 needs 获取它。artifact 的故障通常表现为“文件找不到”或“下载失败”:路径写错、文件未生成、artifact 已过期、或者下游 job 没有声明依赖。诊断时应先确认上游 job 的 artifact 是否上传成功,再检查下游 job 的依赖声明和路径是否一致。
Cache 用于加速重复执行,典型场景是缓存依赖包目录,如 node_modules/、.m2/、vendor/。cache 通过 key 区分不同分支或不同依赖版本。cache 未命中不会导致 job 失败,但会显著拖慢流水线。诊断 cache 问题时,重点看 key 是否随分支或锁文件变化、paths 是否与恢复路径一致、cache 是否被 policy: pull 或 push 限制。一个常见误区是把 artifact 和 cache 混用:artifact 保证“一定有”,cache 只保证“可能有”,关键产物必须走 artifact。
Downloading artifacts 和 Checking cache 两段输出,能快速判断数据层是否正常。
对象之间的依赖与故障传播
这些对象不是孤立的。pipeline 的状态由 stage 和 job 决定;job 能否执行由 runner 标签和 executor 决定;job 之间的数据传递由 artifact 和 cache 决定。一个对象的异常会沿依赖链传播:runner 离线导致 job pending,job pending 导致 stage 阻塞,stage 阻塞导致 pipeline 无法完成。反过来,pipeline 失败时,也应沿着“pipeline → stage → job → runner/executor → artifact/cache”的顺序逐层下钻,而不是一上来就翻看完整日志。
在实际排查中,可以按以下顺序快速建立判断:
- Pipeline 级别:确认是 failed、canceled 还是 blocked,查看失败发生在哪个 stage。
- Stage 级别:确认同 stage 内是否有 job 被跳过或卡住,判断是顺序问题还是并行资源问题。
- Job 级别:查看 job 日志的退出码和最后 20 行,区分是 script 报错、环境初始化失败还是超时。
- Runner/Executor 级别:确认 runner 标签、在线状态、executor 类型、镜像拉取和资源配额。
- Artifact/Cache 级别:确认路径、key、过期时间和依赖声明是否匹配。
把这张对象地图记牢,后续面对“job 卡住”“artifact 丢失”“cache 不命中”“runner 不接单”等具体故障时,就能迅速判断问题属于哪一层、应该查看哪个界面或日志、以及需要修改哪一段配置。故障诊断的效率,很大程度上取决于对核心对象职责边界的清晰程度。