极狐 GitLab

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

Tier: 基础版,专业版,旗舰版

Offering: JihuLab.com,私有化部署

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

包含单个配置文件#

要包含单个配置文件,请单独使用 include 并指定单个文件,可使用以下任一语法选项:

  • 在同一行中:

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

    yaml
    include: - 'my-config.yml'

如果该文件是本地文件,其行为与 include:local 相同。如果该文件是远程文件,其行为与 include:remote 相同。

包含配置文件数组#

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

  • 如果您未指定 include 类型,则每个数组条目会根据需要默认为 include:local 或 include:remote:

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

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

    yaml
    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 类型:

    yaml
    1include: 2 - 'https://gitlab.com/awesome-project/raw/main/.before-script-template.yml' 3 - 'templates/.after-script-template.yml' 4 - template: Auto-DevOps.gitlab-ci.yml 5 - project: 'my-group/my-project' 6 ref: main 7 file: 'templates/.gitlab-ci-template.yml'

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

您可以在配置文件中定义 default 部分。当您将 default 部分与 include 关键字一起使用时,这些默认值会应用于流水线中的所有作业。

例如,您可以将 default 部分与 before_script 一起使用。

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

yaml
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的内容:

yaml
1include: 'templates/.before-script-template.yml' 2 3rspec1: 4 script: 5 - bundle exec rspec 6 7rspec2: 8 script: 9 - bundle exec rspec

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

覆盖所包含的配置值#

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

以下示例展示了一个 include 文件,它在 .gitlab-ci.yml 文件中被自定义。其中特定的 YAML 定义变量以及 production 作业的详细信息被覆盖。

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

yaml
1variables: 2 POSTGRES_USER: user 3 POSTGRES_PASSWORD: testing_password 4 POSTGRES_DB: $CI_ENVIRONMENT_SLUG 5 6production: 7 stage: production 8 script: 9 - install_dependencies 10 - deploy 11 environment: 12 name: production 13 url: https://$CI_PROJECT_PATH_SLUG.$KUBE_INGRESS_BASE_DOMAIN 14 rules: 15 - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

.gitlab-ci.yml的内容:

yaml
1include: 'https://company.com/autodevops-template.yml' 2 3default: 4 image: alpine:latest 5 6variables: 7 POSTGRES_USER: root 8 POSTGRES_PASSWORD: secure_password 9 10stages: 11 - build 12 - test 13 - production 14 15production: 16 environment: 17 url: https://domain.com

在 .gitlab-ci.yml 文件中定义的 POSTGRES_USER 和 POSTGRES_PASSWORD 变量以及 production 作业的 environment:url 会覆盖 autodevops-template.yml 文件中定义的值。其他关键字不会改变。此方法称为合并。

include的合并方法#

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

  • 所包含的文件按配置文件中定义的顺序读取, 所包含的配置也按相同顺序合并在一起。
  • 如果某个所包含的文件也使用了 include,则先合并该嵌套的 include 配置(递归进行)。
  • 如果参数重叠,在合并所包含文件中的配置时,最后包含的文件优先。
  • 在使用 include 添加的所有配置合并在一起之后,主配置 会与所包含的配置合并。

此合并方法是一种深度合并,即配置中任意深度的哈希映射都会合并。要合并哈希映射“A”(包含目前合并的配置)和“B”(下一部分配置),键和值的处理方式如下:

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

例如,对于由两个文件组成的配置:

  • .gitlab-ci.yml 文件:

    yaml
    1include: 'common.yml' 2 3variables: 4 POSTGRES_USER: username 5 6test: 7 rules: 8 - if: $CI_PIPELINE_SOURCE == "merge_request_event" 9 when: manual 10 artifacts: 11 reports: 12 junit: rspec.xml
  • common.yml 文件:

    yaml
    1variables: 2 POSTGRES_USER: common_username 3 POSTGRES_PASSWORD: testing_password 4 5test: 6 rules: 7 - when: never 8 script: 9 - echo LOGIN=${POSTGRES_USER} > deploy.env 10 - rake spec 11 artifacts: 12 reports: 13 dotenv: deploy.env

合并结果为:

yaml
1variables: 2 POSTGRES_USER: username 3 POSTGRES_PASSWORD: testing_password 4 5test: 6 rules: 7 - if: $CI_PIPELINE_SOURCE == "merge_request_event" 8 when: manual 9 script: 10 - echo LOGIN=${POSTGRES_USER} > deploy.env 11 - rake spec 12 artifacts: 13 reports: 14 junit: rspec.xml 15 dotenv: deploy.env

在此示例中:

  • 变量只有在所有文件合并在一起之后才会求值。所包含文件中的作业 最终可能会使用在另一个文件中定义的变量值。合并之后, CI/CD 变量优先级决定每个变量的最终 值。
  • rules 是数组,因此无法合并。顶层文件优先。
  • artifacts 是哈希映射,因此可以深度合并。

覆盖所包含的配置数组#

您可以使用合并来扩展和覆盖所包含模板中的配置,但无法添加或修改数组中的单个条目。例如,要向扩展后的 production 作业的 script 数组添加额外的 notify_owner 命令:

autodevops-template.yml的内容:

yaml
production: stage: production script: - install_dependencies - deploy

.gitlab-ci.yml的内容:

yaml
1include: 'autodevops-template.yml' 2 3stages: 4 - production 5 6production: 7 script: 8 - install_dependencies 9 - deploy 10 - notify_owner

如果 install_dependencies 和 deploy 未在 .gitlab-ci.yml 文件中重复,则 production 作业的脚本中将只有 notify_owner。

使用嵌套 include#

您可以在配置文件中嵌套 include 部分,然后再将这些配置文件包含到另一个配置中。例如,对于嵌套三层的 include 关键字:

.gitlab-ci.yml的内容:

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

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

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

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

yaml
default: after_script: - echo "Job complete."

使用带有重复 include 条目的嵌套 include#

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

如果任何文件使用覆盖更改了所包含的配置,则 include 条目的顺序可能会影响最终配置。最后一次包含该配置时会覆盖之前包含该文件的所有情况。例如:

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

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

    yaml
    1include: 2 - template: defaults.gitlab-ci.yml 3 4default: # Override the included default 5 before_script: echo "Unit test default override" 6 7unit-test-job: 8 script: unit-test.sh
  • smoke-tests.gitlab-ci.yml 文件的内容:

    yaml
    1include: 2 - template: defaults.gitlab-ci.yml 3 4default: # Override the included default 5 before_script: echo "Smoke test default override" 6 7smoke-test-job: 8 script: smoke-test.sh

对于这三个文件,它们的包含顺序会改变最终配置。当:

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

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

    最终配置为:

    yaml
    1unit-test-job: 2 before_script: echo "Smoke test default override" 3 script: unit-test.sh 4 5smoke-test-job: 6 before_script: echo "Smoke test default override" 7 script: smoke-test.sh
  • 最后包含 unit-tests 时,.gitlab-ci.yml 文件的内容为:

    yaml
    include: - local: smoke-tests.gitlab-ci.yml - local: unit-tests.gitlab-ci.yml
  • 最终配置为:

    yaml
    1unit-test-job: 2 before_script: echo "Unit test default override" 3 script: unit-test.sh 4 5smoke-test-job: 6 before_script: echo "Unit test default override" 7 script: smoke-test.sh

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

在 include中使用变量#

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

例如:

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

您不能使用作业中定义的变量,也不能使用全局 variables 部分中定义的变量,该部分为所有作业定义默认变量。include 在作业之前求值,因此这些变量不能与 include 一起使用。

您不能在动态子流水线配置的 include 部分中使用 CI/CD 变量。议题 378717 提议修复此问题。

将 rules 与 include 一起使用#

您可以将 rules 与 include 一起使用,以有条件地包含其他配置文件。

您只能将 rules 与特定变量以及以下关键字一起使用:

include 与 rules:if#

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

yaml
1include: 2 - local: builds.yml 3 rules: 4 - if: $DONT_INCLUDE_BUILDS == "true" 5 when: never 6 - local: builds.yml 7 rules: 8 - if: $ALWAYS_INCLUDE_BUILDS == "true" 9 when: always 10 - local: builds.yml 11 rules: 12 - if: $INCLUDE_BUILDS == "true" 13 - local: deploys.yml 14 rules: 15 - if: $CI_COMMIT_BRANCH == "main" 16 17test: 18 stage: test 19 script: exit 0

include 与 rules:exists#

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

yaml
1include: 2 - local: builds.yml 3 rules: 4 - exists: 5 - exception-file.md 6 when: never 7 - local: builds.yml 8 rules: 9 - exists: 10 - important-file.md 11 when: always 12 - local: builds.yml 13 rules: 14 - exists: 15 - file.md 16 17test: 18 stage: test 19 script: exit 0

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

如果您在来自其他项目的 include 文件中将 include 与 rules:exists 一起使用,请仔细检查您的配置。极狐GitLab 会检查该文件在另一个项目中是否存在。例如:

yaml
1# Pipeline configuration in my-group/my-project 2include: 3 - project: my-group/other-project 4 ref: other_branch 5 file: other-file.yml 6 7test: 8 script: exit 0 9 10# other-file.yml in my-group/other-project on ref other_branch 11include: 12 - project: my-group/my-project 13 ref: main 14 file: my-file.yml 15 rules: 16 - exists: 17 - file.md

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

要更改搜索上下文,您可以将 rules:exists:paths 与 rules:exists:project 一起使用。例如:

yaml
1include: 2 - project: my-group/my-project 3 ref: main 4 file: my-file.yml 5 rules: 6 - exists: 7 paths: 8 - file.md 9 project: my-group/my-project 10 ref: main

include 与 rules:changes#

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

yaml
1include: 2 - local: builds1.yml 3 rules: 4 - changes: 5 - Dockerfile 6 - local: builds2.yml 7 rules: 8 - changes: 9 paths: 10 - Dockerfile 11 compare_to: 'refs/heads/branch1' 12 when: always 13 - local: builds3.yml 14 rules: 15 - if: $CI_PIPELINE_SOURCE == "merge_request_event" 16 changes: 17 paths: 18 - Dockerfile 19 20test: 21 stage: test 22 script: exit 0

在此示例中:

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

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

您可以将通配符路径(* 和 **)与 include:local 一起使用。

示例:

yaml
include: 'configs/*.yml'

当流水线运行时,极狐GitLab 会:

  • 将 configs 目录中的所有 .yml 文件添加到流水线配置中。

  • 不添加 configs 目录子文件夹中的 .yml 文件。要允许此操作, 请添加以下配置:

    yaml
    # 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'

故障排除#

Maximum of 150 nested includes are allowed! 错误#

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

  • 某些嵌套配置包含了过多额外的嵌套 include 配置。
  • 嵌套 include 中存在意外的循环。例如,include1.yml 包含 include2.yml,而后者又包含 include1.yml,从而形成递归循环。

为帮助降低发生此情况的风险,请使用流水线编辑器编辑流水线配置文件,它会验证是否达到该限制。您可以一次移除一个所包含的文件,以尝试缩小范围,找出导致循环或包含文件过多的配置文件。

极狐GitLab 私有化部署上的用户可以更改最大 include 数值。

错误:使用 include:local 时出现 Local file <file> does not exist!#

使用 include:local 时,即使文件存在于代码仓库中,您也可能收到 Local file <file> does not exist! 错误。

此错误是已知的系统级问题,而不是 CI/CD 配置问题。它已在分布式 Gitaly 或 Praefect 设置中间歇性出现。如果遇到此错误,请重试流水线。

更多信息,请参见议题 336789。

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 连接时发生。如果远程主机设置了速率限制以防止服务器因请求而过载,则可能引发此问题。

例如,JihuLab.com 的 GitLab Pages 服务器 有速率限制。反复尝试获取托管在 GitLab Pages 上的 CI/CD 配置文件可能会达到速率限制并导致该错误。您应避免将 CI/CD 配置文件托管在 GitLab Pages 站点上。

在可能的情况下,请使用 include:project 从极狐GitLab 实例中的其他项目获取配置文件,而无需发起外部 HTTP(S) 请求。