使用来自其他文件的 CI/CD 配置

您可以使用 include 在 CI/CD 作业中包含外部 YAML 文件。

包含单个配置文件

要包含单个配置文件,使用 include,并使用以下语法选项之一:

  • 在同一行:

    include: 'my-config.yml'
    
  • 以数组作为单个条目:

    include:
      - 'my-config.yml'
    

如果文件是本地文件,行为与 include:local 相同。如果文件是远端文件,它与 include:remote 相同。

包含一组配置文件

您可以包含一组配置文件:

  • 如果不指定 include 类型,根据需要,每个数组项默认为 include:localinclude:remote

    include:
      - 'https://gitlab.com/awesome-project/raw/main/.before-script-template.yml'
      - '/templates/.after-script-template.yml'
    
  • 您可以定义单个项目数组:

    include:
      - remote: 'https://gitlab.com/awesome-project/raw/main/.before-script-template.yml'
    
  • 您可以定义一个数组并明确指定多个 include 类型:

    include:
      - remote: 'https://gitlab.com/awesome-project/raw/main/.before-script-template.yml'
      - local: '/templates/.after-script-template.yml'
      - template: Auto-DevOps.gitlab-ci.yml
    
  • 您可以定义一个结合默认和特定 include 类型的数组:

    include:
      - 'https://gitlab.com/awesome-project/raw/main/.before-script-template.yml'
      - '/templates/.after-script-template.yml'
      - template: Auto-DevOps.gitlab-ci.yml
      - project: 'my-group/my-project'
        ref: main
        file: '/templates/.gitlab-ci-template.yml'
    

使用包含的配置文件中的 default 配置

您可以在配置文件中定义 default 部分。当您使用带有 include 关键字的 default 部分时,默认值适用于流水线中的所有作业。

例如,您可以使用带有 before_scriptdefault 部分。

名为 /templates/.before-script-template.yml 的自定义配置文件的内容:

default:
  before_script:
    - apt-get update -qq && apt-get install -y -qq sqlite3 libsqlite3-dev nodejs
    - gem install bundler --no-document
    - bundle install --jobs $(nproc)  "${FLAGS[@]}"

.gitlab-ci.yml 的内容:

include: '/templates/.before-script-template.yml'

rspec1:
  script:
    - bundle exec rspec

rspec2:
  script:
    - bundle exec rspec

默认的 before_script 命令在 script 命令之前在两个 rspec 作业中执行。

覆盖包含的配置值

当您使用 include 关键字时,您可以覆盖包含的配置值以使其适应您的流水线要求。

以下示例显示了在 .gitlab-ci.yml 文件中自定义的 include 文件。 特定的 YAML 定义的变量和 production 作业的详细信息被覆盖。

名为 autodevops-template.yml 的自定义配置文件的内容:

variables:
  POSTGRES_USER: user
  POSTGRES_PASSWORD: testing_password
  POSTGRES_DB: $CI_ENVIRONMENT_SLUG

production:
  stage: production
  script:
    - install_dependencies
    - deploy
  environment:
    name: production
    url: https://$CI_PROJECT_PATH_SLUG.$KUBE_INGRESS_BASE_DOMAIN
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

.gitlab-ci.yml 的内容:

include: 'https://company.com/autodevops-template.yml'

image: alpine:latest

variables:
  POSTGRES_USER: root
  POSTGRES_PASSWORD: secure_password

stages:
  - build
  - test
  - production

production:
  environment:
    url: https://domain.com

.gitlab-ci.yml 文件中定义的 POSTGRES_USERPOSTGRES_PASSWORD 变量以及 production 作业的 environment:url 覆盖了 autodevops-template.yml 文件中定义的值。其他关键字不变。这种方法称为 merging

include 的合并方法

include 配置通过以下过程与主配置文件合并:

  • 包含的文件按照配置文件中定义的顺序读取,包含的配置按照相同的顺序合并在一起。
  • 如果包含的文件也使用了 include,则嵌套的 include 配置首先(递归)合并。
  • 如果参数重叠,则在合并来自包含文件的配置时,最后包含的文件优先。
  • 所有用 include 添加的配置合并后,主配置和被包含的配置合并。

这种合并方法是深度合并,其中哈希映射在配置中的任何深度合并。要合并哈希映射 A(包含到目前为止合并的配置)和 B(下一个配置),键和值按如下方式处理:

  • 当键只存在于 A 中时,使用 A 中的键和值。
  • 当键在 A 和 B 中都存在,且它们的值都是哈希映射时,合并这些哈希映射。
  • 当键同时存在于 A 和 B 中,并且其中一个值不是哈希映射时,使用 B 中的值。
  • 否则,使用 B 中的键和值。

例如,使用包含两个文件的配置:

  • .gitlab-ci.yml 文件:

    include: 'common.yml'
    
    variables:
      POSTGRES_USER: username
    
    test:
      rules:
        - if: $CI_PIPELINE_SOURCE == "merge_request_event"
          when: manual
      artifacts:
        reports:
          junit: rspec.xml
    
  • common.yml 文件:

    variables:
      POSTGRES_USER: common_username
      POSTGRES_PASSWORD: testing_password
    
    test:
      rules:
        - when: never
      script:
        - echo LOGIN=${POSTGRES_USER} > deploy.env
        - rake spec
      artifacts:
        reports:
          dotenv: deploy.env
    

合并结果:

variables:
  POSTGRES_USER: username
  POSTGRES_PASSWORD: testing_password

test:
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
      when: manual
  script:
    - echo LOGIN=${POSTGRES_USER} > deploy.env
    - rake spec
  artifacts:
    reports:
      junit: rspec.xml
      dotenv: deploy.env

在此示例中:

  • 仅在所有文件合并在一起后才评估变量。包含文件中的作业可能最终使用在不同文件中定义的变量值。
  • rules 是一个数组,因此无法合并。顶级文件优先。
  • artifacts 是一个哈希映射,因此可以进行深度合并。

覆盖包含的配置数组

您可以使用合并来扩展和覆盖包含模板中的配置,但不能添加或修改数组中的单个项目。例如,将额外的 notify_owner 命令添加到扩展的 production 作业的 script 数组中:

autodevops-template.yml 的内容:

production:
  stage: production
  script:
    - install_dependencies
    - deploy

.gitlab-ci.yml 的内容:

include: 'autodevops-template.yml'

stages:
  - production

production:
  script:
    - install_dependencies
    - deploy
    - notify_owner

如果 .gitlab-ci.yml 文件中没有重复 install_dependenciesdeploy,那么 production 作业在脚本中将只有 notify_owner

使用嵌套的 includes

您可以在配置文件中嵌套 include 部分,然后将其包含在另一个配置中。例如,对于 include 关键字嵌套了三层深度:

.gitlab-ci.yml 的内容:

include:
  - local: /.gitlab-ci/another-config.yml

/.gitlab-ci/another-config.yml 的内容:

include:
  - local: /.gitlab-ci/config-defaults.yml

/.gitlab-ci/config-defaults.yml 的内容:

default:
  after_script:
    - echo "Job complete."

将嵌套包含与重复的 includes 条目一起使用

您可以在主配置文件和嵌套的 include 中多次包含相同的配置文件。

如果任何文件使用 overrides 修改了包含的配置,则 include 条目的顺序可能会影响最终配置。最后包含配置的时间将覆盖之前包含该文件的任何时间。例如:

  • defaults.gitlab-ci.yml 文件的内容:

    default:
      before_script: echo "Default before script"
    
  • unit-tests.gitlab-ci.yml 文件的内容:

    include:
      - template: defaults.gitlab-ci.yml
    
    default:  # Override the included default
      before_script: echo "Unit test default override"
    
    unit-test-job:
      script: unit-test.sh
    
  • smoke-tests.gitlab-ci.yml 文件的内容:

    include:
      - template: defaults.gitlab-ci.yml
    
    default:  # Override the included default
      before_script: echo "Smoke test default override"
    
    smoke-test-job:
      script: smoke-test.sh
    

有了这三个文件,它们的包含顺序会改变最终配置。

  • 先包含 unit-tests.gitlab-ci.yml 文件的内容是:

    include:
      - local: unit-tests.gitlab-ci.yml
      - local: smoke-tests.gitlab-ci.yml
    

    最终配置将会是:

    unit-test-job:
     before_script: echo "Smoke test default override"
     script: unit-test.sh
    
    smoke-test-job:
     before_script: echo "Smoke test default override"
     script: smoke-test.sh
    
  • 最后包含 unit-tests.gitlab-ci.yml 文件的内容是:

    include:
      - local: smoke-tests.gitlab-ci.yml
      - local: unit-tests.gitlab-ci.yml
    
  • 最终配置将会是:

    unit-test-job:
     before_script: echo "Unit test default override"
     script: unit-test.sh
    
    smoke-test-job:
     before_script: echo "Unit test default override"
     script: smoke-test.sh
    

如果没有文件覆盖包含的配置,则 include 条目的顺序不会影响最终配置。

将变量与 include 一起使用

在您 .gitlab-ci.yml 文件中的 include 部分,您可以使用:

比如:

include:
  project: '$CI_PROJECT_PATH'
  file: '.compliance-gitlab-ci.yml'

您不能使用定义在作业,或为所有作业定义默认变量的全局 variables 部分中定义的变量。包含会在作业之前进行评估,所以这些变量不能与 include 一起使用。

您不能在动态子流水线的配置中使用 include 部分中的 CI/CD 变量。

使用 rules with include

  • needs 作业依赖的支持引入于 15.11 版本。

您可以使用 rulesinclude 来有条件地包含其他配置文件。

您只能将 rules某些变量,以及以下关键字一起使用:

include with rules:if

  • when: neverwhen:always 的支持引入于极狐GitLab 16.1,使用名为 ci_support_include_rules_when_never特性标志。默认禁用。
  • when: neverwhen:always 的支持在极狐GitLab 16.2 中 GA。功能标志 ci_support_include_rules_when_never 已删除。

使用 rules:if 根据 CI/CD 变量的状态有条件地包含其他配置文件。例如:

include:
  - local: builds.yml
    rules:
      - if: $INCLUDE_BUILDS == "true"
  - local: deploys.yml
    rules:
      - if: $CI_COMMIT_BRANCH == "main"

test:
  stage: test
  script: exit 0

include with rules:exists

  • when: neverwhen:always 的支持引入于极狐GitLab 16.1,使用名为 ci_support_include_rules_when_never特性标志。默认禁用。
  • when: neverwhen:always 的支持在极狐GitLab 16.2 中 GA。功能标志 ci_support_include_rules_when_never 已删除。

使用 rules:exists 根据文件的存在有条件地包含其他配置文件。例如:

include:
  - local: builds.yml
    rules:
      - exists:
          - exception-file.md
        when: never
  - local: builds.yml
    rules:
      - exists:
          - important-file.md
        when: always
  - local: builds.yml
    rules:
      - exists:
          - file.md

test:
  stage: test
  script: exit 0

在此示例中,极狐GitLab 检查当前项目中是否存在 file.md

如果您使用 rules:exists 配置 include,添加来自不同项目的配置文件,则会出现一个已知问题。极狐GitLab 检查其他项目中是否存在该文件。例如:

# Pipeline configuration in my-group/my-project
include:
  - project: my-group/other-project
    ref: other_branch
    file: other-file.yml

test:
  script: exit 0

# other-file.yml in my-group/other-project on ref other_branch
include:
  - project: my-group/my-project
    ref: main
    file: my-file.yml
    rules:
      - exists:
          - file.md

在此示例中,极狐GitLab 在提交 ref other_branch 中的 my-group/other-project 中搜索 file.md 的存在,而不是流水线运行的项目/提交 ref 中搜索。

要更改搜索上下文,您可以使用 rules:exists:pathsrules:exists:project。例如:

include:
  - project: my-group/my-project
    ref: main
    file: my-file.yml
    rules:
      - exists:
          paths:
            - file.md
          project: my-group/my-project
          ref: main

使用 includerules:changes

  • 引入于极狐GitLab 16.4。

使用 rules:changes 根据更改的文件有条件地包含其他配置文件。例如:

include:
  - local: builds1.yml
    rules:
      - changes:
        - Dockerfile
  - local: builds2.yml
    rules:
      - changes:
          paths:
            - Dockerfile
          compare_to: 'refs/heads/branch1'
        when: always
  - local: builds3.yml
    rules:
      - if: $CI_PIPELINE_SOURCE == "merge_request_event"
        changes:
          paths:
            - Dockerfile

test:
  stage: test
  script: exit 0

在此示例中:

  • Dockerfile 发生更改时,包含 builds1.yml
  • Dockerfile 相对于 refs/heads/branch1 发生更改时,包含 builds2.yml
  • Dockerfile 发生更改且流水线源为合并请求事件时,包含 builds3.ymlbuilds3.yml 中的作业还必须配置为运行合并请求流水线

include:local 与通配符文件路径一起使用

您可以在 include:local 中使用通配符路径(***)。

例子:

include: 'configs/*.yml'

当流水线运行时,系统:

  • configs 目录中的所有 .yml 文件添加到流水线配置中。
  • 不在 configs 目录的子文件夹中添加 .yml 文件。 为此,请添加以下配置:

    # This matches all `.yml` files in `configs` and any subfolder in it.
    include: 'configs/**.yml'
    
    # This matches all `.yml` files only in subfolders of `configs`.
    include: 'configs/**/*.yml'
    

    <!– ## 为使用 include 添加的配置定义输入(Beta)

引入于 15.11 版本,作为 Beta 功能。

specwith 是实验性的 Open Beta 功能,如有更改,恕不另行通知。

使用 spec:inputs 定义输入参数

使用 spec:inputs 来定义 CI/CD 配置的输入参数,这些配置将被添加到带有 include 的流水线中。使用 include:inputs 定义流水线运行时要使用的值。

规范必须在配置文件顶部的 header 中声明。 使用 --- 将 header 与其余配置分开。

使用插值格式 $[[ input.input-id ]] 来引用 header 部分之外的值。 在流水线创建期间获取配置时,但在配置与 .gitlab-ci.yml 的内容合并之前,针对输入,将评估和插值一次。

spec:
  inputs:
    environment:
    job-stage:
---

scan-website:
  stage: $[[ inputs.job-stage ]]
  script: ./scan-website $[[ inputs.environment ]]

使用 spec:inputs 时:

  • 默认情况下,定义的输入是强制性的。
  • 通过指定 default 可以使输入可选。使用 default: null 没有默认值。
  • 包含插值块的字符串不得超过 1 MB。
  • 插值块内的字符串不得超过 1 KB。

custom_configuration.yml 示例:

spec:
  inputs:
    website:
    user:
      default: 'test-user'
    flags:
      default: null
---

# The pipeline configuration would follow...

在此示例中:

  • website 是强制性的,必须定义。
  • user 是可选的。如果未定义,则值为 test-user
  • flags 是可选的。如果没有定义就没有值。

使用 include:inputs 设置输入参数值

include:with 重命名为 include:inputs 于 16.0 版本。

当包含的配置添加到流水线时,使用 include:inputs 设置参数的值。

例如,要包含与上面的示例具有相同 specs 的 custom_configuration.yml

include:
  - local: 'custom_configuration.yml'
    inputs:
      website: "My website"

在此示例中:

  • 对于包含的配置,website 的值为 My website
  • user 的值为 test-user,因为未指定时这是默认值。
  • flags 没有值,因为它是可选的,并且在未指定时没有默认值。 –>

故障排除

Maximum of 150 nested includes are allowed! 错误

流水线的嵌套包含文件的最大数量为 150。 如果您在流水线中收到 Maximum 150 includes are allowed 错误消息,则可能是:

  • 一些嵌套配置包括过多的额外嵌套 include 配置。
  • 嵌套包含中存在意外循环。例如,include1.yml 包含 include2.yml,后者包含 include1.yml,从而创建递归循环。

为帮助降低发生这种情况的风险,请使用流水线编辑器,编辑流水线配置文件,以验证是否达到限制。您可以一次删除一个包含文件,以尝试缩小哪个配置文件是循环源或过多包含文件的范围。

SSL_connect SYSCALL returned=5 errno=0 state=SSLv3/TLS write client hello 和其他网络失败

当使用 include:remote 时,极狐GitLab 会尝试通过 HTTP(S) 获取远程文件。由于各种连接问题,此过程可能会失败。

SSL_connect SYSCALL returned=5 errno=0 state=SSLv3/TLS write client hello 错误发生在 GitLab 无法建立与远程主机的 HTTPS 连接时。如果远程主机对请求进行速率限制以防止服务器过载,可能会导致此问题。

如果可能,请使用 include:project 从极狐GitLab 实例中的其他项目中获取配置文件,而无需进行外部 HTTP(S) 请求。