4. 流水线未触发或未创建
在 GitLab CI/CD 中,最令人困惑的故障之一不是流水线失败,而是流水线根本没有被创建。提交代码后,Pipelines 页面空空如也,或者只显示“No pipeline”,既没有报错日志,也没有可重试的作业。这类问题的根源几乎都集中在“触发条件”这一层:GitLab 在创建流水线之前,会先判断当前事件是否满足 .gitlab-ci.yml 中定义的各种规则。只要规则判定为“不创建”,就不会有任何流水线记录,自然也无从调试。
要系统排查,需要理解 GitLab 决定是否创建流水线的判断顺序。它大致遵循这样一条链路:先看是否存在可用的 CI 配置,再看 workflow:rules 是否允许该事件创建流水线,然后针对每个作业评估 rules 或 only/except,最后还要确认事件类型本身是否属于会触发流水线的事件。下面这张图展示了从代码事件到流水线创建之间的判断链路,以及各环节“被拦截”时的典型表现。
一、先确认配置本身是否可用
流水线未创建时,第一步不是怀疑规则,而是确认 GitLab 是否成功解析了 CI 配置。进入项目的 CI/CD → Editor(CI Lint),粘贴当前分支的 .gitlab-ci.yml 内容进行校验。如果存在 YAML 缩进错误、include 指向的文件不存在、或引用了未定义的变量,GitLab 会直接判定“无有效配置”,此时任何事件都不会创建流水线。常见错误包括:include:local 路径写错、extends 的模板名拼写错误、以及 rules 与 only 同时出现在一个作业中导致配置非法。
需要特别注意的是,rules 和 only/except 是互斥的。如果某个作业同时写了 rules 和 only,GitLab 会报配置错误,整个流水线无法创建。排查时可以用下面的命令在本地快速检查是否存在混用:
# 在仓库根目录检查是否存在 rules 与 only/except 混用
grep -nE "^\s*(rules|only|except):" .gitlab-ci.yml
# 若同一 job 下同时出现 rules 和 only,即为冲突
# 正确做法:统一使用 rules,删除 only/except
二、workflow:rules 是全局总闸门
workflow:rules 决定“哪些事件可以创建流水线”,它比作业级规则更早生效。如果 workflow 中没有匹配当前事件的 when: always 或 when: never 分支,GitLab 默认允许创建;但一旦显式写了 when: never 且命中,整条流水线就不会出现。典型误配如下:
workflow:
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
when: always
- if: '$CI_COMMIT_BRANCH == "main"'
when: always
- when: never # 其他所有情况都不创建流水线
这段配置意味着:只有合并请求事件和 main 分支推送会创建流水线。如果你在 dev 分支推送代码,即使作业规则允许,流水线也不会出现。排查时应先打印当前事件类型,确认 CI_PIPELINE_SOURCE 的实际取值,再对照 workflow 分支逐一比对。
三、合并请求事件的特殊性
合并请求(MR)事件不创建流水线,最常见的原因是源分支上不存在 .gitlab-ci.yml,或者 MR 的源分支与目标分支配置不一致。GitLab 在 MR 事件中默认使用“合并后的结果”或“源分支”的配置,具体取决于项目设置中的 Merge request pipelines 选项。如果源分支没有 CI 配置,MR 流水线就不会创建。此外,如果 MR 是从 fork 发起的,且项目未开启“允许来自 fork 的合并请求流水线”,同样不会触发。
另一个高频陷阱是 rules 中使用了 $CI_MERGE_REQUEST_ID 等变量,但该变量只在 MR 事件中存在。若在普通 push 事件中引用它,条件恒为假,作业被排除。正确写法是显式区分事件:
build:
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
when: on_success
- if: '$CI_COMMIT_BRANCH == "main"'
when: on_success
- when: never
四、only/except 与 rules 的冲突排查
老项目常使用 only/except,新项目推荐 rules。两者语义不同:only 是白名单,except 是黑名单,且不支持复杂条件组合;rules 支持 if、changes、exists 和 when,表达力更强。当同一作业混用时,GitLab 会直接拒绝该配置。排查清单如下:
- 检查每个 job 是否同时出现
rules与only/except,有则删除旧写法。 - 检查
rules中是否存在多个when: never且全部命中,导致作业被完全排除。 - 检查
changes规则是否因文件路径不匹配而恒为假,例如只监听src/**但本次提交只改了README.md。 - 检查
exists规则指向的文件是否真的存在于当前分支。 - 使用 GitLab 的 CI/CD → Pipeline editor → Validate 和 Simulate pipeline 功能,输入事件类型和分支,观察每个作业的判定结果。
CI_PIPELINE_SOURCE、分支名和变量,直接显示每个作业是否被纳入,比反复推送代码高效得多。五、一个可复用的排查决策表
把上述判断整理成一张决策表,可以在实际排障时逐行核对,避免遗漏。表中“现象”指 Pipelines 页面的表现,“优先检查”指最可能的原因。
| 现象 | 优先检查 | 典型修复 |
|---|---|---|
| 完全无流水线记录 | workflow:rules 是否命中 when: never | 补充匹配当前事件的分支,或删除兜底 never |
| MR 页面无流水线 | 源分支是否有 CI 配置、MR pipelines 是否开启 | 在源分支添加配置,开启 MR pipeline 选项 |
| push 后无流水线 | 作业 rules 是否全部排除、changes 路径是否匹配 | 调整 if 条件或 changes 路径 |
| CI Lint 报配置错误 | rules 与 only/except 是否混用 | 统一改为 rules,删除 only/except |
| 流水线存在但无作业 | 所有 job 的 rules 是否都判定为 never | 至少保留一个无条件或匹配当前事件的 job |
最后需要强调一个原则:流水线未创建不是运行时错误,而是配置判定结果。它不会出现在作业日志里,只能通过规则模拟和事件变量比对来定位。养成在修改 rules 或 workflow 后立即用 CI Lint 模拟验证的习惯,可以避免绝大多数“提交了却没反应”的问题。当规则复杂时,建议在作业中临时加入 echo $CI_PIPELINE_SOURCE 和 echo $CI_COMMIT_BRANCH,先确认事件上下文,再回头审视规则条件,往往能快速锁定被拦截的那一环。