GitLab CI/CD 组件示例

适用层级:Free、Premium、Ultimate。

提供方式:GitLab.com、GitLab Self-Managed、GitLab Dedicated。

测试组件

根据组件的功能,测试组件可能需要在仓库中添加其他文件。例如,一个针对特定编程语言执行代码检查、构建和测试的组件,需要实际的源代码示例。源代码示例、配置文件等都可以放在同一个仓库中。

例如,Code Quality CI/CD 组件提供了多个用于测试的代码示例。

示例:测试 Rust 语言的 CI/CD 组件

根据组件的功能,测试组件可能需要在仓库中添加其他文件。

为简便起见,下面的 Rust 编程语言“hello world”示例使用 cargo 工具链:

  1. 进入 CI/CD 组件的根目录。
  2. 使用 cargo init 命令初始化一个新的 Rust 项目。
       cargo init
    

    此命令会创建所有必需的项目文件,包括 src/main.rs 中的“hello world”示例。完成这一步,就可以在组件作业中通过 cargo build 构建 Rust 源代码。

       tree
       .
       ├── Cargo.toml
       ├── LICENSE.md
       ├── README.md
       ├── src
       │   └── main.rs
       └── templates
           └── build.yml
    
  3. 确保组件有一个构建 Rust 源代码的作业,例如将其放在 templates/build.yml 中:
       spec:
         inputs:
           stage:
             default: build
             description: 'Defines the build stage'
           rust_version:
             default: latest
             description: 'Specify the Rust version, use values from https://hub.docker.com/_/rust/tags Defaults to latest'
       ---
    
       "build-$[[ inputs.rust_version ]]":
         stage: $[[ inputs.stage ]]
         image: rust:$[[ inputs.rust_version ]]
         script:
           - cargo build --verbose
    

    在此示例中:

    • stage 和 rust_version 输入的值可以修改,不必使用默认值。CI/CD 作业名称以 build- 为前缀,并根据 rust_version 输入动态生成。命令 cargo build --verbose 会编译 Rust 源代码。
  4. 在项目的 .gitlab-ci.yml 配置文件中测试组件的 build 模板:
       include:
         # include the component located in the current project from the current SHA
         - component: $CI_SERVER_FQDN/$CI_PROJECT_PATH/build@$CI_COMMIT_SHA
           inputs:
             stage: build
    
       stages: [build, test, release]
    
  5. 如需运行测试及实现更多功能,请在 Rust 代码中添加其他函数和测试,并在 templates/test.yml 中添加执行 cargo test 的组件模板与作业。
       spec:
         inputs:
           stage:
             default: test
             description: 'Defines the test stage'
           rust_version:
             default: latest
             description: 'Specify the Rust version, use values from https://hub.docker.com/_/rust/tags Defaults to latest'
       ---
    
       "test-$[[ inputs.rust_version ]]":
         stage: $[[ inputs.stage ]]
         image: rust:$[[ inputs.rust_version ]]
         script:
           - cargo test --verbose
    
  6. 通过引入 test 组件模板,在流水线中测试新增作业:
       include:
         # include the component located in the current project from the current SHA
         - component: $CI_SERVER_FQDN/$CI_PROJECT_PATH/build@$CI_COMMIT_SHA
           inputs:
             stage: build
         - component: $CI_SERVER_FQDN/$CI_PROJECT_PATH/test@$CI_COMMIT_SHA
           inputs:
             stage: test
    
       stages: [build, test, release]
    

CI/CD 组件模式

本节提供在 CI/CD 组件中实现常见模式的实用示例。

使用布尔输入按条件配置作业

结合 boolean 类型的输入和 extends 功能,可以构建具有两个条件分支的作业。

例如,使用 boolean 输入配置复杂的缓存行为:

spec:
  inputs:
    enable_special_caching:
      description: 'If set to `true` configures a complex caching behavior'
      type: boolean
---

.my-component:enable_special_caching:false:
  extends: null

.my-component:enable_special_caching:true:
  cache:
    policy: pull-push
    key: $CI_COMMIT_SHA
    paths: [...]

my-job:
  extends: '.my-component:enable_special_caching:$[[ inputs.enable_special_caching ]]'
  script: ... # run some fancy tooling

此模式把 enable_special_caching 输入传给作业的 extends 关键字。根据 enable_special_caching 是 true 还是 false,从预定义的隐藏作业(.my-component:enable_special_caching:true 或 .my-component:enable_special_caching:false)中选择相应配置。

使用 options 按条件配置作业

可以使用多个选项构建作业,实现类似 if 和 elseif 条件分支的行为。将 extends 与 string 类型及多个 options 结合使用,即可处理任意数量的条件。

例如,通过三个不同的选项配置复杂的缓存行为:

spec:
  inputs:
    cache_mode:
      description: Defines the caching mode to use for this component
      type: string
      options:
        - default
        - aggressive
        - relaxed
---

.my-component:cache_mode:default:
  extends: null

.my-component:cache_mode:aggressive:
  cache:
    policy: push
    key: $CI_COMMIT_SHA
    paths: ['*/**']

.my-component:cache_mode:relaxed:
  cache:
    policy: pull-push
    key: $CI_COMMIT_BRANCH
    paths: ['bin/*']

my-job:
  extends: '.my-component:cache_mode:$[[ inputs.cache_mode ]]'
  script: ... # run some fancy tooling

在此示例中,cache_mode 输入提供 default、aggressive 和 relaxed 选项,每个选项对应一个不同的隐藏作业。通过 extends: '.my-component:cache_mode:$[[ inputs.cache_mode ]]' 扩展组件作业后,作业会根据所选选项动态继承正确的缓存配置。

使用组件上下文引用带版本的资源

  • 在 GitLab 18.6 中引入,当时为 Beta 功能,使用名为 ci_component_context_interpolation 的功能标志,默认启用。
  • 在 GitLab 18.7 中正式可用,移除了功能标志 ci_component_context_interpolation。

使用组件上下文的 CI/CD 表达式引用组件元数据,例如版本和提交 SHA。一种用途是随组件一起构建和发布带版本的资源(例如 Docker 镜像),并确保组件使用匹配的版本。

例如,你可以:

  • 在组件的发布流水线中构建 Docker 镜像,并使用与组件版本一致的标签。
  • 让组件引用同一个镜像版本。

组件项目的发布流水线(.gitlab-ci.yml):

build-image:
  stage: build
  image: docker:latest
  script:
    - docker build -t $CI_REGISTRY_IMAGE/my-tool:$CI_COMMIT_TAG .
    - docker push $CI_REGISTRY_IMAGE/my-tool:$CI_COMMIT_TAG

create-release:
  stage: release
  image: registry.gitlab.com/gitlab-org/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"

组件模板(templates/my-component/template.yml):

spec:
  component: [version, reference]
  inputs:
    stage:
      default: test
---

run-tool:
  stage: $[[ inputs.stage ]]
  image: $CI_REGISTRY_IMAGE/my-tool:$[[ component.version ]]
  script:
    - echo "Running tool version $[[ component.version ]]"
    - echo "Component was included using reference: $[[ component.reference ]]"
    - my-tool --version

在此示例中:

  • 如果通过 @1.0.0 引入组件,作业会使用镜像 my-tool:1.0.0。
  • 如果通过 @1.0 引入,它会解析为最新的 1.0.x 版本,例如 1.0.3,因此会使用 my-tool:1.0.3。
  • 如果通过 @~latest 引入,它会使用最新的已发布版本。
  • component.reference 字段显示你指定的确切引用,例如 1.0、~latest 或某个 SHA。可以将此引用用于日志记录或调试。

CI/CD 组件迁移示例

本节通过实用示例,展示如何把 CI/CD 模板与流水线配置迁移为可复用的 CI/CD 组件。

CI/CD 组件迁移示例:Go

软件开发生命周期的完整流水线可以由多个作业和阶段组成。面向编程语言的 CI/CD 模板可能会在一个模板文件中提供多个作业。作为练习,下面将迁移这个 Go CI/CD 模板。

default:
  image: golang:latest

stages:
  - test
  - build
  - deploy

format:
  stage: test
  script:
    - go fmt $(go list ./... | grep -v /vendor/)
    - go vet $(go list ./... | grep -v /vendor/)
    - go test -race $(go list ./... | grep -v /vendor/)

compile:
  stage: build
  script:
    - mkdir -p mybinaries
    - go build -o mybinaries ./...
  artifacts:
    paths:
      - mybinaries

CI/CD 模板迁移包含以下步骤:

  1. 分析 CI/CD 作业及依赖关系,并确定迁移操作:
    • image 配置是全局的,需要移入作业定义。
    • format 作业在同一个作业中运行多条 go 命令。应把 go test 命令移入独立作业,以提高流水线效率。
    • compile 作业运行 go build,应将其重命名为 build。
  2. 确定优化策略,提高流水线效率。
    • 作业属性 stage 应当可以配置,以适应不同的 CI/CD 流水线使用方。
    • image 键使用了硬编码的镜像标签 latest。添加以 latest 为默认值的golang_version 输入,使流水线更加灵活且易于复用。输入值必须与 Docker Hub 镜像的标签值匹配。
    • compile 作业将二进制文件构建到硬编码的目标目录 mybinaries。可以改用动态输入并保留默认值 mybinaries,以改进这一点。
  3. 为新组件创建模板目录结构,每个作业对应一个模板。
    • 模板名称应与 go 命令相对应,例如 format.yml、build.yml 和 test.yml。
    • 创建新项目,初始化 Git 仓库,添加并提交全部更改,设置远程 origin,然后推送。请把 URL 修改为你的 CI/CD 组件项目路径。
    • 按照编写组件的指南创建其他文件:README.md、LICENSE.md、.gitlab-ci.yml、.gitignore。以下 shell 命令用于初始化 Go 组件结构:
       git init
    
       mkdir templates
       touch templates/{format,build,test}.yml
    
       touch README.md LICENSE.md .gitlab-ci.yml .gitignore
    
       git add -A
       git commit -avm "Initial component structure"
    
       git remote add origin https://gitlab.example.com/components/golang.git
    
       git push
    
  4. 把 CI/CD 作业创建为模板,先从 build 作业开始。
    • 在 spec 部分定义以下输入:stage、golang_version 和 binary_directory。
    • 添加访问 inputs.golang_version 的动态作业名称定义。
    • 使用类似模式,通过访问 inputs.golang_version 动态指定 Go 镜像版本。
    • 将阶段设为 inputs.stage 的值。
    • 根据 inputs.binary_directory 创建二进制文件目录,并将其作为参数传给 go build。
    • 将制品路径定义为 inputs.binary_directory。
         spec:
           inputs:
             stage:
               default: 'build'
               description: 'Defines the build stage'
             golang_version:
               default: 'latest'
               description: 'Go image version tag'
             binary_directory:
               default: 'mybinaries'
               description: 'Output directory for created binary artifacts'
         ---
    
         "build-$[[ inputs.golang_version ]]":
           image: golang:$[[ inputs.golang_version ]]
           stage: $[[ inputs.stage ]]
           script:
             - mkdir -p $[[ inputs.binary_directory ]]
             - go build -o $[[ inputs.binary_directory ]] ./...
           artifacts:
             paths:
               - $[[ inputs.binary_directory ]]
    
    • format 作业模板遵循相同模式,但只需要 stage 和 golang_version 输入。
         spec:
           inputs:
             stage:
               default: 'format'
               description: 'Defines the format stage'
             golang_version:
               default: 'latest'
               description: 'Golang image version tag'
         ---
    
         "format-$[[ inputs.golang_version ]]":
           image: golang:$[[ inputs.golang_version ]]
           stage: $[[ inputs.stage ]]
           script:
             - go fmt $(go list ./... | grep -v /vendor/)
             - go vet $(go list ./... | grep -v /vendor/)
    
    • test 作业模板遵循相同模式,但只需要 stage 和 golang_version 输入。
         spec:
           inputs:
             stage:
               default: 'test'
               description: 'Defines the format stage'
             golang_version:
               default: 'latest'
               description: 'Golang image version tag'
         ---
    
         "test-$[[ inputs.golang_version ]]":
           image: golang:$[[ inputs.golang_version ]]
           stage: $[[ inputs.stage ]]
           script:
             - go test -race $(go list ./... | grep -v /vendor/)
    
  5. 要测试组件,请修改 .gitlab-ci.yml 配置文件,并添加测试。
    • 为 build 作业的 golang_version 输入指定一个不同的值。
    • 把 URL 修改为你的 CI/CD 组件路径。
         stages: [format, build, test]
    
         include:
           - component: $CI_SERVER_FQDN/$CI_PROJECT_PATH/format@$CI_COMMIT_SHA
           - component: $CI_SERVER_FQDN/$CI_PROJECT_PATH/build@$CI_COMMIT_SHA
           - component: $CI_SERVER_FQDN/$CI_PROJECT_PATH/build@$CI_COMMIT_SHA
             inputs:
               golang_version: "1.21"
           - component: $CI_SERVER_FQDN/$CI_PROJECT_PATH/test@$CI_COMMIT_SHA
             inputs:
               golang_version: latest
    
  6. 添加 Go 源代码以测试 CI/CD 组件。go 命令要求 Go 项目的根目录包含 go.mod 和 main.go。
    • 初始化 Go 模块。把 URL 修改为你的 CI/CD 组件路径。
         go mod init example.gitlab.com/components/golang
    
    • 创建包含 main 函数的 main.go 文件,例如打印 Hello, CI/CD component。可以使用代码注释,让 GitLab Duo Code Suggestions 生成 Go 代码。
         // Specify the package, import required packages
         // Create a main function
         // Inside the main function, print "Hello, CI/CD Component"
    
         package main
    
         import "fmt"
    
         func main() {
           fmt.Println("Hello, CI/CD Component")
         }
    
    • 目录树应如下所示:
         tree
         .
         ├── LICENSE.md
         ├── README.md
         ├── go.mod
         ├── main.go
         └── templates
             ├── build.yml
             ├── format.yml
             └── test.yml
    

按照将 CI/CD 模板转换为组件一节中的其余步骤完成迁移:

  1. 提交并推送更改,验证 CI/CD 流水线的结果。
  2. 按照编写组件的指南更新 README.md 和 LICENSE.md 文件。
  3. 发布组件并在 CI/CD 目录中验证它。
  4. 将 CI/CD 组件加入预发布或生产环境。

GitLab 维护的 Go 组件展示了从 Go CI/CD 模板成功迁移的示例,并结合输入参数和组件最佳实践进行了增强。可以查看 Git 历史了解更多信息。

原文:CI/CD component examples。作者:@dnsmichi;维护:GitLab Developer Relations。Copyright (c) 2011-present GitLab Inc.。本中文译文依据 GitLab 仓库 doc/ 文档的 CC BY-SA 4.0 许可翻译,译文沿用该许可;改动为中文翻译与离线排版,代码保留原文。维护信息。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容