CI/CD 组件实例
测试组件
取决于组件的功能性,测试组件可能需要在仓库中添加额外的文件。比如,一个用于特定编程语言的代码检查、构建和测试的组件需要实际的源代码示例。您可以在同一个仓库中拥有源代码示例、配置文件等。
示例 1:测试一个 Rust 语言的 CI/CD 组件
取决于组件的功能性,测试组件可能需要在仓库中添加额外的文件。
以下是 Rust 编程语言的“hello world”示例,使用 cargo
工具链以简化操作:
- 前往 CI/CD 组件根目录。
-
使用
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
-
确保组件有一个构建 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 源代码。 -
在项目的
.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]
-
要运行更多测试,将更多功能和测试添加到 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
-
通过在流水线中引用
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
来实现任何数量的条件。
比如,要配置具有 3 个不同选项的复杂缓存行为:
spec:
inputs:
cache_mode:
description: Defines the caching mode to use for this component
type: string
options:
- default
- aggressive
- relaxed
---
.my-component:enable_special_caching:false:
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 ]]'
来扩展组件作业,作业会动态地继承基于所选选项的正确缓存配置。
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
build
CI/CD 作业。CI/CD 模板迁移涉及如下步骤:
- 分析 CI/CD 作业和依赖并定义迁移操作:
-
image
配置是全局的,需要移动到作业定义中。 -
format
作业在一个作业中运行多个go
命令。go test
命令应该移动到一个单独的作业中,以提高流水线效率。 -
compile
作业运行go build
并且应该重命名为build
。
-
- 定义优化策略以实现更好的流水线效率。
-
stage
作业属性应该可配置,以允许不同的 CI/CD 管道使用者。 -
image
键使用硬编码的latest
标签镜像。image
键使用硬编码的镜像标签latest
。添加golang_version
作为输入,并将latest
作为默认值,以实现更灵活和可重用的流水线。该输入必须与 Docker Hub 镜像标签值匹配。 -
compile
作业将二进制文件构建到硬编码的目标目录mybinaries
中,可以使用动态 输入 和默认值mybinaries
进行增强。
-
- 为新组件创建模板 目录结构,每个作业一个模板。
- 模板的名称应该遵循
go
命令,例如format.yml
、build.yml
和test.yml
。 - 创建一个新项目,初始化一个 Git 仓库,添加/提交所有更改,设置远程 origin 并推送。修改 CI/CD 组件项目的路径 URL。
- 创建额外的文件,如 编写组件 所述:
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
- 模板的名称应该遵循
- 创建 CI/CD 作业作为模版。从
build
作业开始。- 在
spec
部分定义以下输入:stage
、golang_version
和binary_directory
。 - 添加动态作业名称定义,访问
inputs.golang_version
。 - 使用类似的模式为动态 Go 镜像版本,访问
inputs.golang_version
。 - 将阶段分配给
inputs.stage
值。 - 从
inputs.binary_directory
创建二进制目录,并将其作为参数添加到go build
。 -
将 artifacts 路径定义为
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/)
- 在
- 为了测试组件,修改
.gitlab-ci.yml
配置文件,并添加 tests。- 为
build
作业指定不同的golang_version
输入。 -
修改 CI/CD 组件路径的 URL。
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
- 为
-
添加 Go 源码来测试 CI/CD 组件。
go
命令需要一个 Go 项目,其中包含根目录中的go.mod
和main.go
。-
初始化 Go 模块。修改 URL 以匹配您的 CI/CD 组件路径。
go mod init example.gitlab.com/components/golang
-
创建
main.go
文件,包含一个main
函数,打印Hello, CI/CD component
。// 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 模板转换为组件部分中剩余的步骤,以完成迁移: