极狐GitLab

极狐GitLab 父子流水线实战:把巨型 CI 拆成可维护的模块

极狐GitLab
2026年9月17日
18000
分享:

极狐GitLab 父子流水线实战:把巨型 CI 拆成可维护的模块

一个 .gitlab-ci.yml 写到八百行,是什么体验?前端构建、后端测试、安全扫描、部署、回滚全在一个文件里,改一行 Docker 镜像标签要 rebase 三次,跑一次全量流水线四十分钟——其中三十分钟在跑与本次提交毫无关系的作业。

多数团队对这份文件的处置方式是:谁也不敢动,动之前先祈祷。这其实不是 CI 配置技巧问题,而是架构问题:单体流水线和单体应用一样,都会随着业务膨胀走向失控。解法也类似——拆分,但不是拆成散落各处的脚本,而是拆成有层次、可组合、按需触发的下游流水线

一、为什么单体流水线必然走向失控

单体流水线的痛点可以归纳为三条:

  • 全量执行:不管改了什么,所有作业排队跑一遍。构建慢只是表象,反馈慢才是伤害——核心服务的 bug 要排在十几个无关作业后面才能暴露;

  • 职责混杂:测试定义、部署逻辑、安全扫描策略挤在一个文件里,任何团队想改自己的部分都要审阅全部 diff,冲突常态化;

  • 权限无界:能改 CI 配置的人就能改部署逻辑,没有隔离。

依据官方文档,极狐GitLab 的下游流水线是由另一个流水线触发的任何 CI/CD 流水线,它包含两种形态:父子流水线(同一项目内触发)与多项目流水线(跨项目触发),与上游独立、并发运行,基础版即可使用。这正是为拆分而生的机制。

二、父子流水线:同一项目内的模块化

父子流水线中,被触发的子流水线与父流水线运行在相同的项目、引用和提交 SHA 下,天然继承了本次变更的上下文。最简单的触发方式只需几行:

trigger_job:
  trigger:
    include:
      - local: path/to/child-pipeline.yml

拆分后的典型结构:主文件只保留公共变量、阶段骨架和触发作业,各模块的定义放进独立文件——frontend.ymlbackend.ymlsecurity.yml 各归其主,前端团队改前端,互不踩脚。

进阶玩法是动态子流水线:配置文件由作业在运行时生成,而不是静态提交。先用一个作业生成配置并保存为产物,再让触发作业引用它:

generate-config:
  stage: build
  script: generate-ci-config > generated-config.yml
  artifacts:
    paths: [generated-config.yml]

child-pipeline:
  stage: test
  trigger:
    include:
      - artifact: generated-config.yml
        job: generate-config

这套「先生成、再触发」的模式,非常适合按变更内容裁剪流水线——只对本次提交涉及的目录触发对应模块,也是构建目标与架构矩阵场景的通用解法。

两个细节值得注意:一是子流水线中 $CI_PIPELINE_SOURCE 的值为 parent_pipeline,可以用 rules 精确控制子流水线作业的运行条件;二是父流水线可以触发多个子流水线,且子流水线还能再触发子流水线,最多两级深度,层级约束保证了复杂度可控。

三、多项目流水线:跨仓库的编排

当部署逻辑独立成单独的部署仓库(很多团队的必然选择),父子流水线就不够用了——配置文件不在同一项目。此时用 trigger: project

staging:
  stage: deploy
  trigger:
    project: my/deployment
    branch: stable-11-2

与父子流水线的关键差异:多项目流水线影响下游项目自身引用的状态,但上游流水线对下游的控制有限,只能选择引用并传递变量;触发用户必须在下游项目拥有启动流水线的权限。若希望触发作业的状态与下游流水线保持一致,官方推荐加 strategy: mirror

deploy:
  trigger:
    project: project-group/my-deployment-project
  environment: production

从极狐GitLab 16.4 起,trigger 还可与 environment 关键字配合,从上游项目直接查看环境和部署状态——部署仓库独立维护、部署状态统一呈现,两头的便利都占到了。

四、三条实战经验

  1. 产物跨层传递用 needs,别用脚本复制。在触发作业中把 $CI_PIPELINE_ID 作为变量传给子流水线,子流水线作业用 needs: pipeline: $PARENT_PIPELINE_ID 直接取上游产物(专业版及以上)。这比把制品桶地址当变量传来传去干净得多。

  2. inputs 替代裸变量。子流水线配置用 spec: inputs 声明参数,触发方传值时自带类型检查、选项校验和默认值,比无约束的 CI/CD 变量安全得多。

  3. 合并请求场景记得对齐 rules。父流水线触发作业用 $CI_PIPELINE_SOURCE == "merge_request_event" 控制运行,子流水线作业用 $CI_PIPELINE_SOURCE == "parent_pipeline" 配合 $CI_MERGE_REQUEST_ID 判断来源,才能让 MR 流水线正确携带子流水线结果。

写在最后

流水线的演化路径和软件架构一致:单体 → 模块化 → 按需编排。父子流水线解决项目内的模块边界,多项目流水线解决组织级的职责边界,动态子流水线则把「按需执行」做到极致。如果你的 .gitlab-ci.yml 已经开始让人不敢下手,这大概就是动手拆的最好时机。

想进一步了解下游流水线的完整参数与限制,可以直接查阅官方文档。如果你的团队正在评估一体化 DevSecOps 平台的流水线能力,也欢迎注册试用极狐GitLab亲手验证。