CI/CD 组件(实验功能)

  • 引入于 16.0 版本,作为实验功能,使用名为 ci_namespace_catalog_experimental 的功能标志。默认禁用。
  • 在极狐GitLab 16.2 中为 SaaS 和私有化部署启用。
  • 功能标志 ci_namespace_catalog_experimental 在 16.3 中被移除。
  • 在 16.6 中变为 Beta 版本。
  • 在 17.0 中 GA。

CI/CD 组件是可复用的单个流水线配置单元。使用组件来创建大型流水线的一部分,甚至可以组合完整的流水线配置。

可以为组件配置输入参数,以实现更动态的行为。

CI/CD 组件和其他使用 include 关键字的配置 类似,但具有以下优势:

  • 组件可以在 CI/CD 目录 中列出。
  • 组件可以发布并使用特定版本。
  • 多个组件可以在同一个项目中定义并一起版本化。

与其创建你自己的组件,您也可以在 CI/CD 目录中搜索已发布的组件,这些组件具有您需要的功能。

组件项目

  • 在 16.9 中,将每个项目的最大组件数量从 10 改成了 30。

组件项目是一个可以托管一个或多个组件的极狐GitLab 项目。项目中的所有组件可以一起被版本化,每个项目最多 30 个组件。

如果一个组件需要其他不同版本的组件,则该组件应移动到专用组件项目中。

创建组件项目

要创建组件项目,您必须:

  1. 创建一个具有 README.md 文件的新项目:
    • 确保描述清楚地介绍了组件。
    • 可选。项目创建后,你可以添加项目头像

    当展示组件项目的摘要时,CI/CD 目录中发布的组件会同时使用描述和头像。

  2. 为每一个组件新增一个 YAML 配置文件,须遵循必要的目录结构。 比如: For example:

    spec:
      inputs:
        stage:
          default: test
    ---
    component-job:
      script: echo job 1
      stage: $[[ inputs.stage ]]
    

你可以立马使用组件,但你可能想考虑将组件发布到CI/CD 目录中。

目录结构

仓库必需包含:

  • 一个 REAEME.md Markdown 文件,记录了仓库中所有组件的详细信息。
  • 包含所有组件配置的顶级目录 templates/。你可以在此目录下定义组件:
    • 每个组件都是单个的 YAML 文件,比如 templates/secret-detection.yml
    • 包含 template.yml 文件作为入口点的子目录,用于捆绑多个相关文件的组件。例如,templates/secret-detection/template.yml

NOTE: 可选地,每个组件都可以有自己的 README.md 文件,提供更详细的信息,并可以从顶级 README.md 文件中链接。这有助于提供对组件项目的更好概述以及如何使用它。

你还应该:

  • 配置项目的 .gitlab-ci.yml测试组件发布新版本
  • 为组件的使用添加了一个 LICENSE.md 文件,写明你选择的使用许可证。比如 MIT 或 Apache 2.0 开源许可证。

比如:

  • 如果项目包含单个组件,目录结构应类似于:

    ├── templates/
    │   └── my-component.yml
    ├── LICENSE.md
    ├── README.md
    └── .gitlab-ci.yml
    
  • 如果项目包含多个组件,则目录结构应类似于:

    ├── templates/
    │   ├── my-simple-component.yml
    │   └── my-complex-component/
    │       ├── template.yml
    │       ├── Dockerfile
    │       └── test.sh
    ├── LICENSE.md
    ├── README.md
    └── .gitlab-ci.yml
    

    在此示例中:

    • my-simple-component 组件的配置定义在单个文件中。
    • my-complex-component 组件的配置在目录中包含多个文件。

使用组件

要添加组件到项目的 CI/CD 配置中,使用 include: component 关键字。组件引用的格式为 <fully-qualified-domain-name>/<project-path>/<component-name>@<specific-version>,例如:

include:
  - component: $CI_SERVER_FQDN/my-org/security-components/secret-detection@1.0.0
    inputs:
      stage: build

在此示例中:

  • $CI_SERVER_FQDN 是一个与极狐GitLab 主机名相互匹配的 FQDN 的预定义的变量。你只能引用与你的项目位于同一极狐GitLab 实例中的组件。
  • my-org/security-components 是包含组件的项目的完整路径。
  • secret-detection 是组件名称,要么定义在单个文件 templates/secret-detection.yml 中,要么定义在包含 template.yml 文件的目录 templates/secret-detection/ 中。
  • 1.0.0 是组件的版本

流水线配置和组件配置不会独立处理。当流水线启动时,任何包含的组件配置合并到流水线的配置中。如果您的流水线和组件都包含具有相同名称的配置,则它们可能会以意想不到的方式交互。确保您的流水线和组件不共享具有相同名称的任何配置,除非您打算覆盖组件的配置。

比如,两个名称相同的作业会合并成一个作业。同样,组件使用与流水线中的作业具有相同名称的 extends 进行配置,可能会扩展错误的配置。确保您的流水线和组件不共享具有相同名称的任何配置,除非您打算覆盖组件的配置。

要在私有化部署实例中使用 JihuLab.com 组件,请镜像组件项目

caution 如果组件需要用户的令牌、密码或其他敏感数据,请确保审计组件的源代码,以确保数据仅用于执行您期望和授权的操作。您还应该使用具有最小权限、访问或范围的令牌和秘密来完成操作。

组件版本

按照优先级从高到低的顺序,组件版本可能是:

  • 提交 SHA,比如 e3262fdd0914fa823210cdb79a8c421e2cef79d8
  • 标签,比如:1.0.0。如果标签和提交 SHA 以相同名称存在,则标签优先于提交 SHA。发布到 CI/CD 目录的组件应该使用语义版本
  • 分支名,比如 main。如果分支和标签以相同名称存在,则标签优先于分支。
  • ~latest,它始终指向发布到 CI/CD 目录中的最新语义版本。仅在你绝对想哟使用最新版本的时候才使用 ~latest,因为它可能包含破坏性变更。~latest 不包括预发布版本,比如 1.0.1-rc,它们不被认为是生产就绪的。

你可以使用组件支持的任意版本,但是推荐使用发布到 CI/CD 目录中的版本。以提交 SHA 或分支名为版本引用的组件可能没有发布到 CI/CD 目录中,但是可以被用于测试。

语义版本范围

  • 引入于极狐GitLab 16.11。

引用一个 CI/CD 目录组件时,你可以使用一个特殊的格式来指定一个范围内的最新语义版本

要指定最新版本:

  • 一个次要版本,在引用中要同时使用主要和次要版本号,但是不需要补丁版本号。比如,使用 1.1 来使用以 1.1 为始的最新版本,包括 1.1.01.1.9,但是不包括 1.2.0
  • 一个主要版本,在引用中使用主要版本即可。比如,使用 1 来使用以 1 为始的最新版本,诸如 1.0.01.9.9 但是不包括 2.0.0
  • 所有版本,使用 ~latest 来使用最新的版本。

比如,一个组件以这个确切的顺序发布:

  1. 1.0.0
  2. 1.1.0
  3. 2.0.0
  4. 1.1.1
  5. 1.2.0
  6. 2.1.0
  7. 2.0.1

在这个例子中,引用组件为:

  • 1 将使用 1.2.0 版本。
  • 1.1 将使用 1.1.1 版本。
  • ~latest 将使用 2.1.0 版本。

但引用版本范围时,预发布版本从不会被获取。要想拉取一个预发布版本,需要指定完整版本,比如 1.0.1-rc

编写组件

此部分描述了一些创建高质量组件项目的最佳实践。

管理依赖

当一个组件可以使用其他组件时,需要仔细确保它们的依赖性。要管理依赖,你可以:

  • 保持依赖性最小化。通常情况下,少量的重复比依赖性更好。
  • 尽可能依赖本地依赖。比如,使用 include:local 是确保在多个文件中使用相同 Git SHA 的好方法。
  • 当依赖于其他项目的组件时,将它们的版本固定到目录中的发布版本,而不是使用移动目标版本,比如 ~latest 或 Git 引用。使用发布或 Git SHA 可以确保始终获取相同的修订版本,并且组件的使用者获得一致的行为。
  • 定期更新依赖项,通过将它们固定到更新的发布版本来更新依赖项。然后发布新版本的组件,带有更新的依赖项。

撰写一个清晰的 README.md

每一个组件都应该有清晰和完备的文昂。要撰写一个优良的 README.md 文件:

  • 文档应该以项目中组件提供的功能的摘要开始。
  • 如果项目包含多个组件,使用目录可以帮助用户快速跳转到特定组件的详细信息。
  • 为项目中的每个组件添加一个 ## Components 部分,其中包含 ### Component A 等子部分。
  • 在每个组件部分:
    • 添加一个组件是做什么的描述。
    • 添加至少一个 YAML 示例,展示如何使用它。
    • 如果组件使用输入,添加一个表格,则显示所有输入的名称、描述、类型和默认值。
    • 如果组件使用任何变量或密钥,这些也应该被记录下来。
  • 如果接受贡献,建议添加一个 ## Contribute 部分。

如果组件需要更多指南,在组件目录中添加一个 Markdown 文件,并在主 README.md 文件中添加链接。比如:

README.md    # with links to the specific docs.md
templates/
├── component-1/
│   ├── template.yml
│   └── docs.md
└── component-2/
    ├── template.yml
    └── docs.md

测试组件

强烈推荐奖 CI/CD 组件测试作为研发工作流的一部分,因为这能够确保一致性行为。

通过在 root 目录下创建一个 .gitlab-ci.yml 文件来测试 CI/CD 流水线中的变更。确保测试了组件的行为和可能的副作用。如果需要,你还可以使用极狐GitLab API

比如:

include:
  # include the component located in the current project from the current SHA
  - component: $CI_SERVER_FQDN/$CI_PROJECT_PATH/my-component@$CI_COMMIT_SHA
    inputs:
      stage: build

stages: [build, test, release]

# Check if `component job of my-component` is added.
# This example job could also test that the included component works as expected.
# You can inspect data generated by the component, use GitLab API endpoints, or third-party tools.
ensure-job-added:
  stage: test
  image: badouralix/curl-jq
  # Replace "component job of my-component" with the job name in your component.
  script:
    - |
      route="${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/pipelines/${CI_PIPELINE_ID}/jobs"
      count=`curl --silent "$route" | jq 'map(select(.name | contains("component job of my-component"))) | length'`
      if [ "$count" != "1" ]; then
        exit 1; else
        echo "Component Job present"
      fi

# If the pipeline is for a new tag with a semantic version, and all previous jobs succeed,
# create the release.
create-release:
  stage: release
  image: registry.gitlab.com/gitlab-org/release-cli:latest
  script: echo "Creating release $CI_COMMIT_TAG"
  rules:
    - if: $CI_COMMIT_TAG
  release:
    tag_name: $CI_COMMIT_TAG
    description: "Release $CI_COMMIT_TAG of components repository $CI_PROJECT_PATH"

在提交和推送变更后,流水线会测试组件,然后会创建一个版本(如果早期作业成功的话)。

note 如果项目时私有的,则认证是必须的。

用示例文件测试组件

在有些情况下,组件需要和一些源文件交互。比如,一个构建 Go 源码的组件可能需要一些 Go 的样例来测试。或者,一个构建 Docker 镜像的组件可能需要一些样例 Dockerfile 来测试。

你可以直接在组件项目中包含这些样例文件,以便在测试期间使用。

你可以学习更多有关测试组件的示例

避免硬编码实例或项目特定值

当在组件中使用其他组件时,使用 $CI_SERVER_FQDN 而不是实例的完全限定域名(比如 jihulab.com)。

当在组件中访问极狐GitLab API 时,使用 $CI_API_V4_URL 而不是实例的完整 URL 和路径(比如 https://jihulab.com/api/v4)。

这些预定义变量确保组件在其他实例上也能工作,比如在 JihuLab.com 上使用一个私有化部署实例的组件

不要总是假定 API 资源是公开的

确保组件和其测试流水线在私有化部署实例中依旧可用。在 JihuLab.com 上,某些公共项目的 API 资源可以通过未认证的请求访问,而在自托管的情况下,组件项目可以被镜像为私有或内部项目。

在私有化部署实例中,重要的是可以通过输入或变量选择性地提供访问令牌以进行身份验证。

避免使用全局关键字

避免在组件中使用全局关键字。在组件中使用这些关键字会影响流水线中的所有作业,包括直接定义在主 .gitlab-ci.yml 中的作业,或者在其他包含的组件中定义的作业。

关键字的替代方案为:

  • 直接在每个作业中添加配置,即使它会导致组件配置中的某些重复。
  • 在组件中使用 extends 关键字,但使用唯一名称,以减少组件合并到配置中时命名冲突的风险,。

比如,避免使用 default 全局关键字:

# Not recommended
default:
  image: ruby:3.0

rspec-1:
  script: bundle exec rspec dir1/

rspec-2:
  script: bundle exec rspec dir2/

相反地,你可以:

  • 为每个作业显式添加配置:

    rspec-1:
      image: ruby:3.0
      script: bundle exec rspec dir1/
    
    rspec-2:
      image: ruby:3.0
      script: bundle exec rspec dir2/
    
  • 使用 extends 来复用配置:

    .rspec-image:
      image: ruby:3.0
    
    rspec-1:
      extends:
        - .rspec-image
      script: bundle exec rspec dir1/
    
    rspec-2:
      extends:
        - .rspec-image
      script: bundle exec rspec dir2/
    

使用输入替换硬编码的值

避免在 CI/CD 组件中使用硬编码的值。硬编码的值可能会迫使组件用户需要查看组件的内部细节,并调整他们的流水线以与组件一起工作。

常见的一个具有问题的硬编码值的关键字是 stage。如果一个组件作业的阶段是硬编码的,那么所有使用组件的流水线必须要么定义相同的阶段,要么覆盖配置。

更好的方法是为动态配置使用 input 关键字。组件用户可以指定他们需要的确切值。

比如,使用 input 关键字来创建一个组件,其中 stage 配置可以由用户定义:

  • 在组件配置中:

    spec:
      inputs:
        stage:
          default: test
    ---
    unit-test:
      stage: $[[ inputs.stage ]]
      script: echo unit tests
    
    integration-test:
      stage: $[[ inputs.stage ]]
      script: echo integration tests
    
  • 在使用组件的项目中:

    stages: [verify, release]
    
    include:
      - component: $CI_SERVER_FQDN/myorg/ruby/test@1.0.0
        inputs:
          stage: verify
    

使用输入定义作业命名

stage 关键字的值类似,您应该避免在 CI/CD 组件中硬编码作业名称。当您的组件用户能够自定义作业名称时,他们可以防止与他们流水线中现有的名称发生冲突。用户还可以通过使用不同的名称多次包含组件,使用不同的输入选项。

使用 inputs 允许组件用户定义特定的作业名称,或者作业名称的前缀。例如:

spec:
  inputs:
    job-prefix:
      description: "Define a prefix for the job name"
    job-name:
      description: "Alternatively, define the job's name"
    job-stage:
      default: test
---

"$[[ inputs.job-prefix ]]-scan-website":
  stage: $[[ inputs.job-stage ]]
  script:
    - scan-website-1

"$[[ inputs.job-name ]]":
  stage: $[[ inputs.job-stage ]]
  script:
    - scan-website-2

使用 input 替换自定义 CI/CD 变量

当在组件中使用 CI/CD 变量时,需要评估是否可以用 inputs 关键字取而代之。inputs 是一个很好的解决方案,避免要求用户定义自定义变量来配置组件。

输入显式定义在组件的 spec 部分,并且比变量有更好的验证。例如,如果未向组件传递必需的输入,则极狐GitLab 返回流水线错误。相比之下,如果未定义变量,则其值为空,并且没有错误。

比如,使用 inputs 而不是变量来配置扫描器的输出格式:

  • 在组件配置中:

    spec:
      inputs:
        scanner-output:
          default: json
    ---
    my-scanner:
      script: my-scan --output $[[ inputs.scanner-output ]]
    
  • 在使用组件的项目中:

    include:
      - component: $CI_SERVER_FQDN/path/to/project/my-scanner@1.0.0
        inputs:
          scanner-output: yaml
    

在其他情况下,CI/CD 变量可能仍然更受欢迎。例如:

CI/CD 目录

  • 以试验功能引入于极狐GitLab 16.1。
  • 在极狐GitLab 16.7 中变为 Beta。
  • 在极狐GitLab 17.0 中变为 GA。

CI/CD 目录 是一个包含已发布 CI/CD 组件的项目列表,您可以使用这些组件来扩展您的 CI/CD 工作流。

任何人都可以创建一个组件项目并将其添加到 CI/CD 目录中,或将其贡献至既有项目以提高组件的可用性。

查看 CI/CD 目录

要访问 CI/CD 目录并查看可供您使用的已发布的组件:

  1. 在左侧导航栏,选择 搜索或前往
  2. 选择 浏览
  3. 选择 CI/CD 目录

如果您已经在项目的流水线编辑器 中,您可以直接选择 CI/CD 目录

CI/CD 目录中组件的可见性遵循其源项目的可见性设置。组件的源项目设置为:

  • 私有的可见性仅限于那些对源组件项目至少具有访客角色的用户。
  • 内部的可见性仅限于那些登录到极狐GitLab 实例的用户。
  • 公共的可见性对所有有权访问极狐GitLab 实例的人都可见。

发布一个组件项目

要在 CI/CD 目录中发布一个组件项目,您必需:

  1. 将项目设置为目录项目。
  2. 发布新版本。

将组件项目设置为目录项目

要想在 CI/CD 目录中让已发布的组件变得可视,您必须将项目设置为目录项目。

先决条件:

  • 您必须是项目的拥有者角色。

要想将项目设置为目录项目:

  1. 在左侧导航栏,选择 搜索或前往 并找到你的项目。
  2. 选择 设置 > 通用
  3. 展开 可视化、项目功能、权限
  4. 打开 CI/CD 目录项目 开关。

在你发布新版本后,项目在目录中才可被发现。

为了自动启用此设置,你可以使用 mutationcatalogresourcescreate GraphQL 端点。

发布新版本

CI/CD 组件无需在 CI/CD 目录列表中也可使用。然而,将其发布到目录中更易于其他用户发现并使用。

先决条件:

要向目录发布组件新版本:

  1. 在项目的 .gitlab-ci.yml 文件中添加一个作业,当创建标签时,使用 release 关键字来创建新的发布。在运行发布作业之前,您应该配置标签流水线来测试组件

    create-release:
      stage: release
      image: registry.gitlab.com/gitlab-org/release-cli:latest
      script: echo "Creating release $CI_COMMIT_TAG"
      rules:
        - if: $CI_COMMIT_TAG
      release:
        tag_name: $CI_COMMIT_TAG
        description: "Release $CI_COMMIT_TAG of components in $CI_PROJECT_PATH"
    
  2. 为发布创建一个新标签,这会触发包含负责创建发布作业的标签流水线。标签必须使用语义版本

发布作业成功后,就会创建出版本切新版本被发布到了 CI/CD 目录中。

语义版本

  • 引入于极狐GitLab 16.10。

当打完标签并发布组件的新版本到目录时,您必须使用语义版本。语义版本是用于表述变更是主要、次要、补丁还是其他类型的变更的标准。

比如,1.0.02.3.41.0.0-alpha 都是有效的语义版本。

取消发布组件项目

要从目录中移除组件项目,在项目设置中关闭 CI/CD 目录资源 开关即可。

caution 此操作会销毁组件项目的元数据及其已经发布到目录中的版本。项目及其仓库仍然存在,但不再在目录中可见。

要想在目录中再次发布组件项目,您需要发布一个新版本

将 CI/CD 模板转换为组件

任何你通过语法 include: 使用的 CI/CD 模板都可以被转换为 CI/CD 组件:

  1. 决定您是否想要将组件与现有组件项目中的其他组件分组,或者创建一个新的组件项目
  2. 在组件项目中根据目录结构创建一个 YAML 文件。
  3. 将原始模板 YAML 文件的内容复制到新的组件 YAML 文件中。
  4. 重构新组件的配置,以:
  5. 利用组件存储库中的 .gitlab-ci.yml测试组件的更改
  6. 打标签并发布组件

您可以通过将 Go CI/CD 模板迁移到 CI/CD 组件的实际示例来了解更多。

在私有化部署实例中使用 JihuLab.com 组件

新安装的极狐GitLab 示例中,在 CI/CD 目录中是没有任何发布的组件的。要想丰富实例中的目录,您可以:

要想将 JihuLab.com 中的组件镜像到私有化实例中:

  1. 确保对 jihulab.com网络出站请求是允许的。
  2. 创建一个群组来托管组件项目(推荐的组:components)。
  3. 在新的群组中,创建组件项目的镜像
  4. 为组件项目镜像编写项目描述,因为镜像仓库不会复制描述。
  5. 将自托管组件项目设置为目录资源
  6. 在自托管组件项目中通过运行流水线来发布一个新版本

CI/CD 组件安全最佳实践

对组件用户

因为任何人都可以发布组件到目录中,所以在使用它们之前,您应该仔细审查组件。使用极狐GitLab CI/CD 组件是您自己的风险,极狐GitLab 不能保证第三方组件的安全性。

当使用第三方 CI/CD 组件时,请考虑以下安全最佳实践:

  • 审计和审核组件源代码:仔细检查代码,确保其不包含恶意内容。
  • 最小化对凭据和令牌的访问
    • 审核组件的源代码,以确保任何凭据或令牌仅用于执行您预期和授权的操作。
    • 使用最小范围的访问令牌。
    • 避免使用长期有效的访问令牌或凭据。
    • 审核 CI/CD 组件使用的凭据和令牌的使用情况。
  • 使用固定版本:将 CI/CD 组件固定到特定的提交 SHA(首选)或发布版本标签,以确保使用的组件的完整性。
  • 安全地存储密钥:不要在 CI/CD 配置文件中存储密钥。如果可以使用外部密钥管理解决方案,请避免在项目设置中存储密钥和凭据。
  • 使用临时、隔离的 runner 环境:尽可能在临时、隔离的环境中运行组件作业。请注意自托管 runner 的安全风险
  • 安全地处理缓存和制品:除非绝对必要,否则不要将其他作业的缓存或制品传递给 CI/CD 组件作业。
  • 限制 CI_JOB_TOKEN 访问:限制CI/CD 作业令牌 (CI_JOB_TOKEN) 项目访问和权限
  • 审查 CI/CD 组件变更:在变更使用更新的提交 SHA 或发布标签之前,仔细审查 CI/CD 组件配置的所有更改。
  • 审计自定义容器镜像:仔细审查 CI/CD 组件使用的任何自定义容器镜像,以确保它们不包含恶意内容。

对组件维护者

要维护 CI/CD 组件的安全性和可靠性,确保您交付给用户的流水线配置的完整性,请遵循以下最佳实践:

  • 使用双因素认证(2FA):确保所有 CI/CD 组件项目维护者和所有者已启用双因素身份验证(2FA),或者强制在组中为所有用户启用 2FA
  • 用户受保护分支
    • 为组件项目的发布使用受保护分支
    • 保护默认分支,并使用通配符规则保护所有发布分支。
    • 要求每个人提交合并请求以更改受保护的分支。将 允许推送和合并 选项设置为 以保护受保护的分支。
    • 阻止强制推送受保护的分支。
  • 对所有提交进行签名对组件项目的所有提交进行签名
  • 避免使用 latest:避免在 README.md 中包含使用 @latest 的示例。
  • 限制对其他作业缓存和制品的依赖:仅在绝对必要时在 CI/CD 组件中使用其他作业的缓存和制品。
  • 定期更新 CI/CD 组件依赖项:定期检查并应用对 CI/CD 组件依赖项的更新。
  • 仔细审查更改
    • 仔细审查所有对 CI/CD 组件流水线配置的更改,然后再将其合并到默认分支或发布分支中。
    • 对所有面向用户的 CI/CD 组件目录项目更改使用合并请求审批

故障排查

content not found 消息

当使用 ~latest 版本限定符引用由目录项目托管的组件时,可能会收到类似于以下内容的错误消息:

This GitLab CI configuration is invalid: Component 'gitlab.com/my-namespace/my-project/my-component@~latest' - content not found

~latest 的行为在极狐GitLab 16.10 中进行了更新。它现在引用目录资源的最新语义版本。要解决此问题,请创建新版本

错误: Build component error: Spec must be a valid json schema

如果一个组件有无效的格式,您可能无法创建版本并接收到诸如 Build component error: Spec must be a valid json schema 的错误。

此错误可能是由于 spec:inputs 部分为空引起的。如果您的配置没有使用任何输入,您可以将 spec 部分留空。例如:

spec:
---

my-component:
  script: echo