下游流水线

下游流水线是由另一个流水线触发的任何极狐GitLab CI/CD 流水线。 下游流水线独立运行,并且与触发它们的上游流水线同时运行。

  • 一个父子流水线,它是与第一个流水线在同一个项目中触发的下游流水线。
  • 多项目流水线,它是在与第一个流水线不同的项目中触发的下游流水线。

父子流水线和多项目流水线有时可用于类似目的,但存在一些关键差异。

父子流水线

父流水线是在同一项目中触发下游流水线的流水线。 下游流水线称为子流水线。

子流水线:

  • 在与父流水线相同的项目、ref 和提交 SHA 下运行。
  • 不直接影响流水线运行相关的 ref 的整体状态。例如, 如果主分支的流水线出现故障,通常会说“主分支已损坏”。 如果子流水线由 strategy:depend 触发,子流水线的状态只影响 ref 的状态。
  • 当为同一 ref 创建新流水线时,如果使用 interruptible 配置流水线,则自动取消。
  • 不显示在项目的流水线列表中。您只能在其父流水线的详情页面查看子流水线。

嵌套子流水线

  • 引入于极狐GitLab 13.4。
  • 功能标志移除于极狐GitLab 13.5。

父子流水线的最大深度为两级子流水线。

一个父流水线可以触发多个子流水线,这些子流水线又可以触发自己的子流水线。您不能触发另一级别的子流水线。

多项目流水线

一个项目中的流水线可以触发另一个项目中的下游流水线,称为多项目流水线。触发上游流水线的用户必须能够启动下游项目中的流水线,否则下游流水线无法启动

多项目流水线:

  • 从另一个流水线触发,但上游(触发)流水线对下游(被触发)流水线没有太多控制。但是,它可以选择下游流水线的 ref,并将 CI/CD 变量传递给它。
  • 影响它运行的项目的 ref 的整体状态,但不影响触发流水线的 ref 的状态,除非用 strategy:depend
  • 如果在上游流水线中为相同的 ref 运行新流水线,则在使用 interruptible 时不会在下游项目中自动取消。如果为下游项目上的相同 ref 触发了新流水线,它们可以自动取消。
  • 在下游项目的流水线列表中可见。
  • 是独立的,因此没有嵌套限制。

如果您使用公共项目来触发私有项目中的下游流水线,请确保不存在保密问题。上游项目的流水线页面始终显示:

  • 下游项目的名称。
  • 流水线的状态。

.gitlab-ci.yml 文件中的作业触发下游流水线

.gitlab-ci.yml 文件中使用 trigger 关键字来创建触发下游流水线的作业。该作业称为触发作业。

例如:

::Tabs

:::TabTitle 父子流水线

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

:::TabTitle 多项目流水线

trigger_job:
  trigger:
    project: project-group/my-downstream-project

::EndTabs

触发作业启动后,当极狐GitLab 尝试创建下游流水线时,作业的初始状态为 pending。如果下游流水线创建成功,则触发器作业显示 passed,否则显示 failed。或者,您可以设置触发作业显示下游流水线的状态

使用 rules 控制下游流水线作业

在下游流水线中使用 CI/CD 变量或 rules 关键字来控制作业行为

当您使用 trigger 关键字触发下游流水线时,适用于所有作业的 $CI_PIPELINE_SOURCE 预定义变量的值是:

  • 多项目流水线:pipeline
  • 父子流水线:parent_pipeline

例如,要在同时运行合并请求流水线的项目中,控制多项目流水线中的作业:

job1:
  rules:
    - if: $CI_PIPELINE_SOURCE == "pipeline"
  script: echo "This job runs in multi-project pipelines only"

job2:
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
  script: echo "This job runs in merge request pipelines only"

job3:
  rules:
    - if: $CI_PIPELINE_SOURCE == "pipeline"
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
  script: echo "This job runs in both multi-project and merge request pipelines"

在不同的项目中使用子流水线配置文件

引入于极狐GitLab 13.5。

您可以在触发器作业中,使用 include:project 来使用不同项目中的配置文件触发子流水线:

microservice_a:
  trigger:
    include:
      - project: 'my-group/my-pipeline-library'
        ref: 'main'
        file: '/path/to/child-pipeline.yml'

组合多个子流水线配置文件

定义子流水线时,您最多可以包含三个配置文件。子流水线的配置由合并在一起的所有配置文件组成:

microservice_a:
  trigger:
    include:
      - local: path/to/microservice_a.yml
      - template: Security/SAST.gitlab-ci.yml
      - project: 'my-group/my-pipeline-library'
        ref: 'main'
        file: '/path/to/child-pipeline.yml'

动态子流水线

您可以从作业中生成的 YAML 文件而不是项目中保存的静态文件触发子流水线。这种技术对于生成针对已更改内容的流水线或构建目标和体系结构矩阵非常强大。

包含生成的 YAML 文件的产物不得大于 5MB。

有关生成动态子流水线的项目示例,请参阅使用 Jsonnet 的动态子流水线。 该项目展示了如何使用数据模板语言在运行时生成 .gitlab-ci.yml。 您可以对其他模板语言使用类似的过程,例如 Dhallytt

触发动态子流水线

从动态生成的配置文件触发子流水线:

  1. 在作业中生成配置文件,保存为产物

    generate-config:
      stage: build
      script: generate-ci-config > generated-config.yml
      artifacts:
        paths:
          - generated-config.yml
    
  2. 将触发器作业配置为在生成配置文件的作业之后运行。将 include: artifact 设置为生成的产物并将 include: job 设置为创建产物的作业:

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

在此示例中,极狐GitLab 检索 generated-config.yml 并使用该文件中的 CI/CD 配置触发子流水线。

产物路径由极狐GitLab 而非 runner 解析,因此该路径必须与运行极狐GitLab 的操作系统的语法相匹配。如果极狐GitLab 在 Linux 上运行但使用 Windows runner 进行测试,则触发作业的路径分隔符为 /。使用 Windows runner 的作业的其他 CI/CD 配置,如脚本,使用 \

使用合并请求流水线运行子流水线

当不使用 rulesworkflow:rules 时,流水线(包括子流水线)默认作为分支流水线运行。

要将子流水线配置为在从合并请求(父)流水线触发时运行,请使用 rulesworkflow:rules。例如,使用 rules

  1. 将父流水线的触发作业设置为在合并请求时运行:

    trigger-child-pipeline-job:
      trigger:
        include: path/to/child-pipeline-configuration.yml
      rules:
        - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    
  2. 使用 rules 将子流水线作业配置为在父流水线触发时运行:

    job1:
      script: echo "This child pipeline job runs any time the parent pipeline triggers it."
      rules:
        - if: $CI_PIPELINE_SOURCE == "parent_pipeline"
    
    job2:
      script: echo "This child pipeline job runs only when the parent pipeline is a merge request pipeline"
      rules:
        - if: $CI_MERGE_REQUEST_ID
    

在子流水线中,$CI_PIPELINE_SOURCE 的值始终为 parent_pipeline,因此:

  • 您可以使用 if: $CI_PIPELINE_SOURCE == "parent_pipeline" 来确保子流水线作业始终运行。
  • 您不能使用 if: $CI_PIPELINE_SOURCE == "merge_request_event" 来配置子流水线作业来运行合并请求流水线。 相反,使用 if: $CI_MERGE_REQUEST_ID 将子流水线作业设置为仅在父流水线是合并请求流水线时运行。父流水线的 CI_MERGE_REQUEST_* 预定义变量被传递给子流水线作业。

为多项目流水线指定一个分支

您可以指定在触发多项目流水线时使用的分支。极狐GitLab 使用分支头部的提交来创建下游流水线。例如:

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

使用:

  • project 关键字指定下游项目的完整路径。在 15.3 及更高版本中,您可以使用变量扩展
  • branch 关键字指定 project 指定的项目中的分支或标签的名称。您可以使用变量扩展。

使用 API 触发多项目流水线

您可以将 CI/CD 作业令牌(CI_JOB_TOKEN流水线触发器 API 端点,从 CI/CD 作业中触发多项目流水线。极狐GitLab 将使用作业令牌触发的流水线设置为包含进行 API 调用的作业的流水线的下游流水线。

例如:

trigger_pipeline:
  stage: deploy
  script:
    - curl --request POST --form "token=$CI_JOB_TOKEN" --form ref=main "https://gitlab.example.com/api/v4/projects/9/trigger/pipeline"
  rules:
    - if: $CI_COMMIT_TAG
  environment: production

查看下游流水线

流水线图视图中,下游流水线显示为图表右侧的卡片列表。在此视图中,您可以:

  • 选择一个触发作业,查看触发的下游流水线的作业。
  • 在流水线选项卡上选择 展开作业 ,展开包含下游流水线作业的视图。您一次可以查看一个下游流水线。
  • 将鼠标悬停在流水线选项卡上,突出显示触发下游流水线的作业。

重试下游流水线中失败和取消的作业

  • 从图表视图重试功能引入于 15.0 版本,功能标志downstream_retry_action。默认禁用。
  • 从图表视图重试功能一般可用于 15.1 版本。功能标志删除。

要重试失败的和取消的作业,请选择 重试 ( ):

  • 从下游流水线的详细信息页面。
  • 在流水线图视图中的流水线选项卡上。

重新创建下游流水线

  • 从流水线图视图重试触发作业功能引入于 15.10 版本,功能标志ci_recreate_downstream_pipeline。默认禁用。
  • 一般可用于 15.11 版本,删除功能标志 ci_recreate_downstream_pipeline

您可以通过重试相应的触发作业来重新创建下游流水线。新创建的下游流水线将替换流水线图中当前的下游流水线。

要重新创建下游流水线:

  • 在流水线图视图中的触发作业卡上选择 再次运行 ( )。

取消下游流水线

  • 从图表视图重试引入于极狐GitLab 15.0,功能标志downstream_retry_action。默认禁用。
  • 从图表视图重试普遍可用并移除功能标志于极狐GitLab 15.1。

要取消仍在运行的下游流水线,请选择 取消 ( ):

  • 从下游流水线的详细信息页面。
  • 流水线图视图中的流水线卡上。

在触发器作业中镜像下游流水线的状态

您可以使用 strategy: depend 在触发器作业中镜像下游流水线的状态:

::Tabs

:::TabTitle 父子流水线

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

:::TabTitle 多项目流水线

trigger_job:
  trigger:
    project: my/project
    strategy: depend

::EndTabs

在流水线图中查看多项目流水线

当您触发多项目流水线时,下游流水线会显示在流水线图的右侧。

流水线迷你图中,下游流水线显示在迷你图的右侧。

从上游流水线获取产物

::Tabs

:::TabTitle 父子流水线

使用 needs:project 从上游流水线获取产物:

  1. 在上游流水线中,使用 artifacts 关键字将产物保存在作业中,然后使用触发器作业触发下游流水线:

    build_artifacts:
      stage: build
      script:
        - echo "This is a test artifact!" >> artifact.txt
      artifacts:
        paths:
          - artifact.txt
    
    deploy:
      stage: deploy
      trigger:
        include:
          - local: path/to/child-pipeline.yml
      variables:
        PARENT_PIPELINE_ID: $CI_PIPELINE_ID
    
  2. 在下游流水线的作业中使用 needs:project 来获取产物。

    test:
      stage: test
      script:
        - cat artifact.txt
      needs:
        - pipeline: $PARENT_PIPELINE_ID
          job: build_artifacts
    

    job 设置为创建产物的上游流水线中的作业。

:::TabTitle 多项目流水线

使用 needs:project 从上游流水线获取产物:

  1. 在 15.9 及更高版本中,将下游项目添加到上游项目的作业令牌范围许可列表中
  2. 在上游流水线中,将产物保存到带有 artifacts 关键字的作业中,然后触发带有触发作业的下游流水线:

    build_artifacts:
      stage: build
      script:
        - echo "This is a test artifact!" >> artifact.txt
      artifacts:
        paths:
          - artifact.txt
    
    deploy:
      stage: deploy
      trigger: my/downstream_project   # Path to the project to trigger a pipeline in
    
  3. 使用下游流水线中的作业中的 needs:project 以获取产物。

    test:
      stage: test
      script:
        - cat artifact.txt
      needs:
        - project: my/upstream_project
          job: build_artifacts
          ref: main
          artifacts: true
    

    进行以下设置:

    • job 设置为创建产物的上游流水线中的作业。
    • ref 设置为分支。
    • artifacts 设置为 true

::EndTabs

从上游合并请求流水线中获取产物

当您使用 needs:project将产物传递到下游流水线时,ref 值通常是分支名称,例如 maindevelopment

对于合并请求流水线,ref 值的格式为 refs/merge-requests/<id>/head,其中 id 是合并请求 ID。您可以使用 CI_MERGE_REQUEST_REF_PATH CI/CD 变量检索此 ref。不要将分支名称用作合并请求流水线的 ref,因为下游流水线会尝试从最新的分支流水线中获取产物。

要从上游 merge request 流水线而不是 branch 流水线获取产物,请使用变量继承将 CI_MERGE_REQUEST_REF_PATH 传递给下游流水线:

  1. 在 15.9 及更高版本中,将下游项目添加到上游项目的作业令牌范围许可列表中
  2. 在上游流水线的作业中,使用 artifacts 关键字保存产物。
  3. 在触发下游流水线的作业中,传递 $CI_MERGE_REQUEST_REF_PATH 变量:

    build_artifacts:
      rules:
        - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
      stage: build
      script:
        - echo "This is a test artifact!" >> artifact.txt
      artifacts:
        paths:
          - artifact.txt
    
    upstream_job:
      rules:
        - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
      variables:
        UPSTREAM_REF: $CI_MERGE_REQUEST_REF_PATH
      trigger:
        project: my/downstream_project
        branch: my-branch
    
  4. 在下游流水线的作业中,使用 needs:project 和传递的变量作为 ref 从上游流水线获取产物:

    test:
      stage: test
      script:
        - cat artifact.txt
      needs:
        - project: my/upstream_project
          job: build_artifacts
          ref: $UPSTREAM_REF
          artifacts: true
    

您可以使用此方法从上游合并请求流水线中获取产物,但不能从合并结果流水线中获取产物。

将 CI/CD 变量传递到下游流水线

您可以根据创建或定义变量的位置,使用几种不同的方法将 CI/CD 变量传递到下游流水线。

传递 YAML 定义的 CI/CD 变量

您可以使用 variables 关键字将 CI/CD 变量传递到下游流水线。这些变量是变量优先级的”触发变量”。

例如:

::Tabs

:::TabTitle 父子流水线

variables:
  VERSION: "1.0.0"

staging:
  variables:
    ENVIRONMENT: staging
  stage: deploy
  trigger:
    include:
      - local: path/to/child-pipeline.yml

:::TabTitle 多项目流水线

variables:
  VERSION: "1.0.0"

staging:
  variables:
    ENVIRONMENT: staging
  stage: deploy
  trigger: my-group/my-deployment-project

::EndTabs

ENVIRONMENT 变量在下游流水线中定义的每个作业中都可用。

VERSION 全局变量在下游流水线中也可用,因为流水线中的所有作业(包括触发器作业)都会继承全局 variables

防止全局变量被传递

您可以使用 inherit:variables:false 阻止全局 CI/CD 变量到达下游流水线。

例如:

::Tabs

:::TabTitle 父子流水线

variables:
  GLOBAL_VAR: value

trigger-job:
  inherit:
    variables: false
  variables:
    JOB_VAR: value
  trigger:
    include:
      - local: path/to/child-pipeline.yml

:::TabTitle 多项目流水线

variables:
  GLOBAL_VAR: value

trigger-job:
  inherit:
    variables: false
  variables:
    JOB_VAR: value
  trigger: my-group/my-project

::EndTabs

在此示例中,GLOBAL_VAR 变量在触发流水线中不可用,但 JOB_VAR 可用。

传递一个预定义的变量

使用预定义的 CI/CD 变量传递有关上游流水线的信息,使用插值。将预定义变量保存为触发作业中的新作业变量,传递给下游流水线。

::Tabs

:::TabTitle 父子流水线

trigger-job:
  variables:
    PARENT_BRANCH: $CI_COMMIT_REF_NAME
  trigger:
    include:
      - local: path/to/child-pipeline.yml

:::TabTitle 多项目流水线

trigger-job:
  variables:
    UPSTREAM_BRANCH: $CI_COMMIT_REF_NAME
  trigger: my-group/my-project

::EndTabs

包含上游流水线的 $CI_COMMIT_REF_NAME 预定义 CI/CD 变量值的 UPSTREAM_BRANCH 变量在下游流水线中可用。

不要使用此方法将隐藏的变量传递到多项目流水线。CI/CD 隐藏配置不会传递到下游流水线,变量可能会在下游项目的作业日志中被取消隐藏。

您不能使用此方法将作业级持久变量转发到下游流水线,因为它们在触发器作业中不可用。

上游流水线优先于下游流水线。如果在上游和下游项目中定义了两个同名变量,则上游项目中定义的变量优先。

传递作业中创建的 dotenv 变量

您可以使用 dotenv 变量继承needs:project 将变量传递到下游的作业。这些变量仅在作业脚本中可用,不能用于配置它,例如使用 rulesartifact:paths

例如,在多项目流水线中:

  1. 将变量保存在 .env 文件中。
  2. .env 文件保存为 dotenv 报告。
  3. 触发下游流水线。

    build_vars:
      stage: build
      script:
        - echo "BUILD_VERSION=hello" >> build.env
      artifacts:
        reports:
          dotenv: build.env
    
    deploy:
      stage: deploy
      trigger: my/downstream_project
    
  4. 在下游流水线中设置 test 作业以从具有 needs 的上游项目中的 build_vars 作业继承变量。test 作业继承了 dotenv 报告中的变量,它可以访问脚本中的 BUILD_VERSION

    test:
      stage: test
      script:
        - echo $BUILD_VERSION
      needs:
        - project: my/upstream_project
          job: build_vars
          ref: master
          artifacts: true
    

控制转发到下游流水线的变量类型

使用 trigger:forward 关键字指定要转发到下游流水线的变量类型。转发的变量被视为触发流水线,具有最高优先级。

部署的下游流水线

引入于极狐GitLab 16.4。

您可以将 environment 关键字与 trigger 一起使用。 如果您的部署和应用程序项目是单独管理的,您可能希望使用触发器作业中的 environment

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

下游流水线可以配置基础设施,部署到指定环境,并将部署状态返回给上游项目。

您可以从上游项目查看环境和部署

高级示例

此示例配置具有以下行为:

  • 上游项目根据分支名称动态组成环境名称。
  • 上游项目使用 UPSTREAM_* 变量将部署上下文传递到下游项目。

上游项目中的 .gitlab-ci.yml

stages:
  - deploy
  - cleanup

.downstream-deployment-pipeline:
  variables:
    UPSTREAM_PROJECT_ID: $CI_PROJECT_ID
    UPSTREAM_ENVIRONMENT_NAME: $CI_ENVIRONMENT_NAME
    UPSTREAM_ENVIRONMENT_ACTION: $CI_ENVIRONMENT_ACTION
  trigger:
    project: project-group/deployment-project
    branch: main
    strategy: depend

deploy-review:
  stage: deploy
  extends: .downstream-deployment-pipeline
  environment:
    name: review/$CI_COMMIT_REF_SLUG
    on_stop: stop-review

stop-review:
  stage: cleanup
  extends: .downstream-deployment-pipeline
  environment:
    name: review/$CI_COMMIT_REF_SLUG
    action: stop
  when: manual

下游项目中的 .gitlab-ci.yml

deploy:
  script: echo "Deploy to ${UPSTREAM_ENVIRONMENT_NAME} for ${UPSTREAM_PROJECT_ID}"
  rules:
    - if: $CI_PIPELINE_SOURCE == "pipeline" && $UPSTREAM_ENVIRONMENT_ACTION == "start"

stop:
  script: echo "Stop ${UPSTREAM_ENVIRONMENT_NAME} for ${UPSTREAM_PROJECT_ID}"
  rules:
    - if: $CI_PIPELINE_SOURCE == "pipeline" && $UPSTREAM_ENVIRONMENT_ACTION == "stop"

故障排除

触发作业失败并且不创建多项目流水线

对于多项目流水线,如果出现以下情况,触发器作业将失败并且不会创建下游流水线:

  • 未找到下游项目。
  • 创建上游流水线的用户没有在下游项目中创建流水线的权限
  • 下游流水线以受保护分支为目标,并且用户无权针对受保护分支运行流水线。有关更多信息,请参阅受保护分支的流水线安全性

流水线运行时不创建子流水线中的作业

如果父流水线是合并请求流水线,则子流水线必须使用 workflow:rulesrules 以确保作业运行

如果由于 rules 配置缺失或不正确,子流水线中的作业无法运行:

  • 子流水线无法启动。
  • 父流水线的触发器作业失败并显示 downstream pipeline can not be created, Pipeline will not run for the selected trigger. The rules configuration prevented any jobs from being added to the pipeline.

Ref is ambiguous

当存在同名分支时,您无法使用标签触发多项目流水线。下游流水线无法创建,并出现错误 downstream pipeline can not be created, Ref is ambiguous

仅触发标签名称与分支名称不匹配的多项目流水线。

从上游流水线下载作业产物时出现 403 Forbidden 错误

在 15.9 及更高版本中,CI/CD 作业令牌的范围仅限于执行流水线的项目。因此,下游流水线中的作业令牌默认无法访问上游项目。

要解决此问题,将下游项目添加到作业令牌范围许可列表