9636 字约 32 分钟
CNB 流水线通过 .cnb.yml 配置文件来定义自动化构建流程。
基本结构
CNB 流水线采用层级结构,从外到内依次是:
| 层级 | 说明 | 示例 |
|---|---|---|
| 触发分支 | 指定哪些分支的代码会触发流水线 | main、dev |
| 触发事件 | 指定什么操作会触发流水线 | push、pull_request |
| Pipeline(流水线) | 一次完整的构建流程,包含多个阶段 | 构建流程 |
| Stage(阶段) | 流水线中的一个步骤,可包含一个或多个任务 | 安装依赖 |
| Job(任务) | 最小的执行单元,执行具体的命令或插件 | 执行命令 |
执行流程示意
触发分支 (main)
└─ 触发事件 (push)
├─ Pipeline (流水线)
│ └─ Stage(阶段)
│ └─ Job(任务)
└─ Pipeline (流水线)
└─ Stage(阶段)
└─ Job(任务)完整示例
以下是一个包含所有层级的完整示例:
main: # 触发分支:在 main 分支上触发
push: # 触发事件:代码推送时触发
- name: pipeline-1 # 流水线名称
stages:
- name: stage-1 # 阶段名称
jobs:
- name: job-1 # 任务名称
script: echo "in pipeline-1"
- name: pipeline-2 # 流水线名称
stages:
- name: stage-1 # 阶段名称
jobs:
- name: job-1 # 任务名称
script: echo "in pipeline-2"也支持通过对象的形式声明多个流水线:
main: # 触发分支
push: # 触发事件
pipeline-1: # 流水线标识
stages:
- name: stage-1
jobs:
- name: job-1
script: echo "Hello World"
pipeline-2: # 流水线标识
stages:
- name: stage-1
jobs:
- name: job-1
script: echo "Hello World"触发分支
作用:指定哪些分支的代码会触发流水线。
类型:字符串
支持模式
| 模式类型 | 说明 | 示例 |
|---|---|---|
| 精确匹配 | 精确匹配分支名 | main、dev、release |
| 通配符匹配 | 使用 glob 语法匹配 | feature/*、hotfix/* |
| 兜底匹配 | 匹配所有未明确指定的分支 | $ |
分支匹配示例
# 只在 main 分支触发
main:
push:
- stages:
- echo "main branch"
# 匹配所有 feature 开头的分支
feature/*:
push:
- stages:
- echo "feature branch"
# 兜底:匹配其他所有分支
$:
push:
- stages:
- echo "other branches"更多详情
参考 触发机制#触发分支
触发事件
作用:指定什么操作会触发流水线执行。
常用事件
| 事件名 | 触发时机 |
|---|---|
| push | 代码推送到分支时触发 |
| pull_request | 创建或更新 Pull Request 时触发 |
| tag_push | 推送标签时触发 |
| branch.delete | 删除分支时触发 |
触发事件示例
main:
# 代码推送时执行测试
push:
- stages:
- npm test
# PR 时执行代码检查
pull_request:
- stages:
- npm run lint更多详情
参考 触发机制#触发事件
Pipeline
Pipeline 表示一个流水线,包含一个或多个阶段 Stage,每个 Stage 依次执行。
配置项概览
Pipeline 支持以下配置项:
| 配置项 | 类型 | 说明 |
|---|---|---|
| name | String | 流水线名称 |
| runner | Object | 构建节点配置(tags、cpus) |
| docker | Object | Docker 环境配置(image、build、devcontainer、volumes) |
| git | Object | Git 仓库配置(enable、submodules、lfs) |
| services | Array | 构建服务(docker、vscode) |
| env | Object | 环境变量 |
| imports | Array<String> | 从文件导入环境变量 |
| label | Object | 流水线标签 |
| stages | Array | 阶段任务列表 |
| failStages | Array | 失败时执行的任务 |
| endStages | Array | 结束时执行的任务 |
| ifNewBranch | Boolean | 仅新分支时执行 |
| ifModify | Array<String> | 文件变更时执行 |
| breakIfModify | Boolean | 源分支更新时终止 |
| retry | Number | 失败重试次数 |
| allowFailure | Boolean | 允许失败 |
| lock | Object | 流水线锁配置 |
| sandbox | Boolean | 沙箱模式 |
配置项详细说明
name
- 类型:
String
指定流水线名,默认为 pipeline。当有多条并行流水线时,默认流水线名为 pipeline、pipeline-1、pipeline-2 依此类推,可定义 name 指定流水线名来区分不同流水线。
runner
- 类型:
Object
指定构建节点相关参数。
子参数:
| 参数 | 类型 | 说明 |
|---|---|---|
| tags | String | Array<String> | 指定使用具备哪些标签的构建节点 |
| cpus | Number | 指定构建需使用的 cpu 核数 |
runner.tags
- 类型:
String|Array<String> - 默认值:
cnb:arch:default
指定使用具备哪些标签的构建节点。详见构建节点。
示例:
main:
push:
- runner:
tags: cnb:arch:amd64
stages:
- name: uname
script: uname -arunner.cpus
- 类型:
Number
指定构建需使用的最大 cpu 核数(memory = cpu 核数 × 2 G),其中 cpu 和 memory 不超过 runner 机器实际大小。
未配置,则最大可用 cpu 核数由分配到的 runner 机器配置来指定。
示例:
# cpus = 1,memory = 2G
main:
push:
- runner:
cpus: 1
stages:
- name: echo
script: echo "hello world"docker
- 类型:
Object
指定 docker 相关的参数。详情见构建环境
子参数:
| 参数 | 说明 |
|---|---|
| image | 当前 Pipeline 的环境镜像,在当前 Pipeline 下的所有任务都将在这个镜像环境中执行 |
| build | 指定一个 Dockerfile,构建一个临时镜像,作为 image 的值使用 |
| devcontainer | 指定 devcontainer.json 文件所在路径,将使用 devcontainer.json 文件内容作为流水线容器镜像 |
| volumes | 声明数据卷,用于缓存场景 |
优先级
当同时指定 image、build、devcontainer 时,优先级为 build > devcontainer > image。
docker.image
- 类型:
Object|String
指定当前 Pipeline 的环境镜像,在当前 Pipeline 下的所有任务都将在这个镜像环境中执行。
该属性及其下的属性支持引用环境变量,参考变量替换。
属性:
| 属性 | 类型 | 说明 |
|---|---|---|
| image.name | String | 镜像名,如 node:20 |
| image.dockerUser | String | 指定 Docker 用户名,用于拉取指定的镜像 |
| image.dockerPassword | String | 指定 Docker 用户密码,用于拉取指定的镜像 |
如果指定 image 为字符串,则等同于指定了 image.name。
如果使用 云原生构建 的 Docker 制品库的镜像且未设置 image.dockerPassword,该参数会设为环境变量 CNB_TOKEN 的值。
示例一:使用 DockerHub 公开镜像
main:
push:
- docker:
# 取 Docker 官方镜像仓库中的 node:20 镜像作为构建容器
image: node:20
stages:
- name: show version
script: node -v示例二:使用 CNB 公开或私有镜像
main:
push:
- docker:
# 取非公开镜像作为构建容器,需传入 docker 用户名和密码
image:
name: docker.cnb.cool/images/pipeline-env:1.0
# 使用 CNB 镜像,构建时默认注入 CNB_TOKEN 为 dockerPassword
stages:
- name: echo
script: echo "hello world"示例三:使用其他私有镜像
在密钥仓库文件中声明拉取其他私有镜像所需的 Docker 用户名、密码。
DOCKER_USER: <user>
DOCKER_PASSWORD: <password>main:
push:
# 导入上文创建的密钥仓库文件为环境变量
- imports: https://cnb.cool/<your-repo-slug>/-/blob/main/xxx/docker.yml
docker:
image:
name: other-private-images/pipeline-env:1.0
# 引用密钥仓库文件 docker.yml 声明的环境变量
dockerUser: $DOCKER_USER
dockerPassword: $DOCKER_PASSWORD
stages:
- name: echo
script: echo "hello world"docker.build
- 类型:
Object|String
指定一个 Dockerfile,构建一个临时镜像,作为 image 的值使用。
该属性及其下的属性支持引用环境变量,参考变量替换。
使用 build 声明构建环境的完整示例可参考 docker-build-with-by。
参数说明:
| 参数 | 类型 | 说明 |
|---|---|---|
| build.dockerfile | String | Dockerfile 路径,支持引用环境变量 |
| build.target | String | 对应 docker build 中的 --target 参数,可以选择性地构建 Dockerfile 中的特定阶段 |
| build.by | Array<String> | String | 声明缓存构建过程中依赖的文件列表 |
| build.versionBy | Array<String> | String | 用于版本控制,支持直接传入文件夹路径 |
| build.buildArgs | Object | 在 build 时插入额外的构建参数 |
| build.ignoreBuildArgsInVersion | Boolean | 版本计算是否忽略 buildArgs |
| build.sync | String | 是否等待 docker push 成功后才继续,默认为 false |
注意
未出现在 by 列表中的文件,除了 Dockerfile,其他在构建镜像过程中,都当不存在处理。
如果指定 build 为字符串,则等同于指定了 build.dockerfile。
Dockerfile 用法:
main:
push:
- docker:
# `build` 为字符串,则等同于指定了 `build.dockerfile`
build: ./image/Dockerfile
stages:
- stage1
- stage2main:
push:
- docker:
# 指定了 `build` 的类型为 `Object`,可对构建镜像过程进行更多控制
build:
dockerfile: ./image/Dockerfile
# 只构建 builder,而不是整个 Dockerfile
target: builder
stages:
- stage1
- stage2Dockerfile versionBy 用法:
示例:将 pnpm 缓存到环境镜像中,加速后续 pnpm i 过程
FROM node:22
RUN npm config set registry https://mirrors.cloud.tencent.com/npm/ \
&& npm i -g pnpm
WORKDIR /data/cache
COPY package.json package-lock.json ./
RUN pnpm imain:
push:
# 通过 Dockerfile 指定构建环境
- docker:
build:
dockerfile: ./Dockerfile
by:
- package.json
- package-lock.json
versionBy:
- package-lock.json
stages:
- name: cp node_modules
# 从容器中将 node_modules 复制到流水线工作目录
script: cp -r /data/cache/node_modules ./
- name: check node_modules
script: |
if [ -d "node_modules" ]; then
cd node_modules
ls
else
echo "node_modules directory does not exist."
fidocker.devcontainer
- 类型:
String
指定 devcontainer.json 文件所在路径,将使用 devcontainer.json 文件内容作为流水线容器镜像。
仅支持相对于当前仓库的路径,如:.devcontainer/devcontainer.json
具体 devcontainer.json 规范可查看:devcontainer.json
有限支持
由于 CNB 平台特性,目前仅提供有限的支持。当前支持的属性:
- image
- build.dockerfile
- build.context
- build.args
- build.target
docker.volumes
- 类型:
Array<String>|String
声明数据卷,多个数据卷可用通过数组或者用 , 号做分隔符传入,可引用环境变量。
注意
此缓存仅在当前构建节点中有效,不支持跨节点缓存。详见流水线缓存
支持的格式:
<group>:<path>:<type><path>:<type><path>
参数含义:
| 参数 | 说明 |
|---|---|
| group | 可选,数据卷分组,不同组间相互隔离 |
| path | 必填,数据卷挂载绝对路径,支持绝对路径(/ 开头)或相对路径(./ 开头),相对于工作区 |
| type | 可选,数据卷类型,缺省值为 copy-on-write |
数据卷类型:
| 类型 | 简写 | 说明 | 适用场景 |
|---|---|---|---|
| read-write | rw | 读写,并发写冲突需自行处理 | 串行构建场景 |
| read-only | ro | 只读,写操作抛出异常 | 只读访问 |
| copy-on-write | cow | 读写,变更在流水线成功后被合并 | 并发构建场景(默认) |
| copy-on-write-read-only | - | 只读,变更在流水线结束后丢弃 | PR 场景 |
| data | - | 创建临时数据卷,流水线结束时自动清理 | 共享数据 |
copy-on-write
用于缓存场景,支持并发。
copy-on-write 技术允许系统在需要修改数据之前共享相同的数据副本,从而实现高效的缓存复制。在并发环境中,这种方法避免了缓存的读写冲突,因为只有在实际需要修改数据时,才会创建数据的私有副本。这样,只有写操作会导致数据复制,而读操作可以安全地并行进行,无需担心数据一致性问题。这种机制显著提高了性能,尤其是在读多写少的缓存场景中。
data
用于共享数据,将容器中的指定目录,共享给其他容器中使用。
通过创建数据卷,然后 mount 到各容器中。与直接将构建节点上目录 mount 到容器中方式不同的是:当指定的目录在容器中已经存在,会先把容器中内容自动复制到数据卷,而不是将数据卷内容直接覆盖容器中目录。
volumes 示例
示例 1:挂载构建节点上目录到容器中,实现本地缓存效果
main:
push:
- docker:
image: node:20
# 声明数据卷
volumes:
- /data/config:read-only
- /data/mydata:read-write
# 使用缓存,同时更新
- /root/.npm
# 使用 main 缓存,同时更新
- main:/root/.gradle:copy-on-write
stages:
- stage1
- stage2
pull_request:
- docker:
image: node:20
# 声明数据卷
volumes:
- /data/config:read-only
- /data/mydata:read-write
# 使用 copy-on-write 缓存
- /root/.npm
- node_modules
# pr 使用 main 缓存,但不更新
- main:/root/.gradle:copy-on-write-read-only
stages:
- stage1
- stage2示例 2:将打包在容器中的文件,共享到其他容器中使用
main:
push:
- docker:
image: go-app-cli # 假设有个 go 应用在镜像的 /go-app/cli 路径下
# 声明数据卷
volumes:
# 此路径在 go-app-cli 镜像存在,所以执行环境镜像时,会将此路径内容复制到临时数据卷中,可共享给其他任务容器里使用
- /go-app
stages:
- name: show /go-app-cli in job container
image: alpine
script: ls /go-appgit
- 类型:
Object
提供 Git 仓库相关配置。
git.enable
- 类型:
Boolean - 默认值:
true(branch.delete事件为false)
指定是否拉取代码。
git.submodules
- 类型:
Object|Boolean - 默认值:
- enable:
true - remote:
false
- enable:
指定是否要拉取子项目(submodules)。
当值为 Boolean 类型时,相当于指定 git.submodules.enable 为 git.submodules 的值,git.submodules.remote 为默认值 false。
git.submodules.enable
- 类型:
Boolean - 默认值:
true
是否指定是否要拉取子项目 submodules。
git.submodules.remote
- 类型:
Boolean - 默认值:
false
执行 git submodule update 时是否添加 --remote 参数,用于每次拉取 submodule 最新的代码。
基本用法:
main:
push:
- git:
enable: true
submodules: true
stages:
- name: echo
script: echo "hello world"
- git:
enable: true
submodules:
enable: true
remote: true
stages:
- name: echo
script: echo "hello world"git.lfs
- 类型:
Object|Boolean - 默认值:
true
指定是否要拉取 LFS 文件。
支持 Object 形式指定具体参数,字段缺省时,默认值为:
{
"enable": true
}基本用法:
main:
push:
- git:
enable: true
lfs: true
stages:
- name: echo
script: echo "hello world"
- git:
enable: true
lfs:
enable: true
stages:
- name: echo
script: echo "hello world"git.lfs.enable
是否指定是否要拉取 LFS 文件。
services
- 类型:
Array<String>|Array<Object>
用于声明构建时需要的服务,格式:name:[version],version 是可选的。
目前支持的服务:
- docker
- vscode
service:docker
用于开启 dind 服务。
当构建过程中需要使用 docker build、docker login 等操作时声明,会自动在环境注入 docker daemon 和 docker cli。
示例:
main:
push:
- services:
- docker
docker:
image: alpine
stages:
- name: docker info
script:
- docker info
- docker ps该服务会自动 docker login 到 CNB Docker 制品库的镜像源(docker.cnb.cool),在后续任务中可直接 docker push 到当前仓库 Docker 制品库。
示例:
main:
push:
- services:
- docker
stages:
- name: build and push
script: |
# 根目录存在 Dockerfile 文件
docker build -t ${CNB_DOCKER_REGISTRY}/${CNB_REPO_SLUG_LOWERCASE}:latest .
docker push ${CNB_DOCKER_REGISTRY}/${CNB_REPO_SLUG_LOWERCASE}:latest若需要使用 buildx 构建多种架构/平台的镜像,可以开启 rootlessBuildkitd 特性:
main:
push:
- docker:
image: golang:1.24
services:
- name: docker
options:
rootlessBuildkitd:
enabled: true
env:
IMAGE_TAG: ${CNB_DOCKER_REGISTRY}/${CNB_REPO_SLUG_LOWERCASE}:latest
stages:
- name: go build
script: ./build.sh
- name: docker login
script: docker login -u ${CNB_TOKEN_USER_NAME} -p "${CNB_TOKEN}" ${CNB_DOCKER_REGISTRY}
- name: docker build and push
script: docker buildx build -t ${IMAGE_TAG} --platform linux/amd64,linux/amd64/v2,linux/amd64/v3,linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/mips64le,linux/mips64,linux/loong64,linux/arm/v7,linux/arm/v6 --push .service:vscode
需要云原生开发时声明。
示例:
$:
vscode:
- services:
- vscode
- docker
docker:
image: alpine
stages:
- name: uname
script: uname -a如需开启仅预览模式,请参考文档。
如需指定开发环境离线保活时间(超过指定时长,则回收开发环境),可使用 keepAliveTimeout 参数:
$:
vscode:
- docker:
build: .ide/Dockerfile
services:
- docker
- name: vscode
options:
# 保活时间,单位毫秒,不设置默认 10 分钟没有心跳(检测不到开发环境内的 http/ssh 连接)就关闭开发环境
keepAliveTimeout: 10m
# 开发环境启动后会执行的任务
stages:
- name: ls
script: ls -alkeepAliveTimeout 参数说明:
| 属性 | 值 |
|---|---|
| 类型 | Number | String(单位默认为毫秒) |
| 默认值 | 600000(ms, 10分钟) |
| 说明 | 开发环境的离线保活时间 |
支持的时间单位:
| 单位 | 说明 |
|---|---|
| ms | 毫秒(默认) |
| s | 秒 |
| m | 分钟 |
| h | 小时 |
env
- 类型:
Object
声明一个对象作为环境变量:属性名为环境变量名,属性值为环境变量值。
在任务执行中使用,对当前 Pipeline 内的非插件任务均有效。
示例:
main:
push:
- services:
- docker
env:
some_key: some_value
stages:
- name: some job
script: echo "$some_value"imports
- 类型:
Array<String>|String
指定 CNB 仓库文件路径(文件相对路径或页面地址),作为环境变量来源,作用同 env。
文件内容会被解析为对象,属性名为环境变量名,属性值为环境变量值。
在任务执行中使用,对当前 Pipeline 内的非插件任务均有效。
本地相对路径如 ./env.yml 会被拼接成文件页面地址进行加载。即:本地存在但远端不存在的文件不会被引用。
安全性
云原生构建 现支持密钥仓库,安全性更高,支持文件引用审计。一般使用一个密钥仓库来存放诸如 npm、docker 等账号密码。
同名 key 优先级
- 当配置 imports 为数组时,如遇到参数重复的情况,后面的配置会覆盖前面的
- 如果和
env参数中重复,那么env中的参数会覆盖掉imports文件中的
变量替换
imports 文件路径可读取环境变量。若是数组,下面的文件路径可读取上面文件中的变量。
FILE: "https://cnb.cool/<your-repo-slug>/-/blob/main/xxx/env2.yml"TEST_TOKEN: some tokenmain:
push:
- imports:
- ./env1.yml
# FILE 为 env1.yml 中声明的环境变量
- $FILE
stages:
- name: echo
# TEST_TOKEN 为 env2.yml 中声明的环境变量
script: echo $TEST_TOKEN引用鉴权
被引用文件可声明可被访问范围,参考 配置文件引用鉴权。
示例:
匹配一个项目下面的所有仓库:
key: value
allow_slugs:
- team_name/project_name/**允许被所有仓库引用:
key: value
allow_slugs:
- "**"文件解析规则
支持解析多种文件格式并将其转换为环境变量。
YAML 文件
按 YAML 格式解析为对象,支持的文件格式为:.yaml、.yml。
DOCKER_USER: "username"
DOCKER_TOKEN: "token"
DOCKER_REGISTRY: "https://xxx/xxx"JSON 文件
按 JSON 格式解析为对象,支持的文件格式为:.json。
{
"DOCKER_USER": "username",
"DOCKER_TOKEN": "token",
"DOCKER_REGISTRY": "https://xxx/xxx"
}证书文件
证书文件以文件名(. 被替换为 _)作为属性名,文件内容作为属性值解析为对象。
支持的文件格式包括:.crt、.cer、.key、.pem、.pub、.pk、.ppk。
-----BEGIN CERTIFICATE-----
MIIE...
-----END CERTIFICATE-----main:
push:
- imports: https://cnb.cool/<your-repo-slug>/-/blob/main/server.crt
stages:
- echo "$server_crt" > server.crt
- cat server.crt其他文本文件
除以上文件格式外,其他文本文件按 key=value 的格式解析为对象。
DB_HOST=localhost
DB_PORT=5432深层属性
大部分场景配置文件是简单的单层属性,比如:
// env.json
{
"token": "private token",
"password": "private password"
}为了应对复杂的配置文件和场景,深层属性(第一层不能为数组),会平铺成单层对象,规则是:
- 属性名保留,属性值会转成字符串
- 属性值若为对象(包括数组),则会递归平铺,属性路径以
_连接
{
"key1": [
"value1",
"value2"
],
"key2": {
"subkey1": [
"value3",
"value4"
],
"subkey2": "value5"
},
"key3": [
"value6",
{
"subsubkey1": "value7"
}
],
"key4": "value8"
}会平铺成:
{
// 原属性值转成字符串
"key1": "value1,value2",
// 属性值若为对象,则额外进行递归平铺操作增加属性
"key1_0": "value1",
"key1_1": "value2",
"key2": "[object Object]",
"key2_subkey1": "value3,value4",
"key2_subkey1_0": "value3",
"key2_subkey1_1": "value4",
"key2_subkey2": "value5",
"key3": "value6,[object Object]",
"key3_0": "value6",
"key3_1": "[object Object]",
"key3_1_subsubkey1": "value7",
"key4": "value8"
}main:
push:
- imports:
- ./env.json
stages:
- name: echo
script: echo $key3_1_subsubkey1label
- 类型:
Object
为流水线指定标签。每个标签的值可以是一个字符串,也可以是一个字符串数组。该标签可用于后续流水线记录筛选等功能。
这里举一种工作流的例子:main 分支合并即发布预发布环境,打 tag 后发布正式环境。
main:
push:
- label:
# Master 分支的常规流水线
type:
- MASTER
- PREVIEW
stages:
- name: install
script: npm install
- name: CCK-lint
script: npm run lint
- name: BVT-build
script: npm run build
- name: UT-test
script: npm run test
- name: pre release
script: ./pre-release.sh
$:
tag_push:
- label:
# 产品发布分支的常规流水线
type: RELEASE
stages:
- name: install
script: npm install
- name: build
script: npm run build
- name: DELIVERY-release
script: ./release.shstages
- 类型:
Array<Stage|Job>
定义一组阶段任务,每个阶段串行运行。
failStages
- 类型:
Array<Stage|Job>
定义一组失败阶段任务。当正常流程失败,会依次执行此阶段任务。
endStages
- 类型:
Array<Stage|Job>
定义流水线结束阶段执行的一组任务。当流水线 stages/failStages 执行完,流水线结束前,会依次执行此阶段任务。
当流水线 prepare 阶段成功,无论 stages 是否成功,endStages 都将执行。且 endStages 是否成功不影响流水线状态(即 endStages 失败,流水线状态也可能是成功)。
ifNewBranch
- 类型:
Boolean - 默认值:
false
为 true 表示当前分支属于新分支(即 CNB_IS_NEW_BRANCH 为 true)时,才执行此 Pipeline。
条件组合
当同时存在 ifNewBranch / ifModify 时,其中有一个条件满足,此 Pipeline 就会执行。
ifModify
- 类型:
Array<String>|String
指定只有相应文件变动时,才执行此 Pipeline。是一个 glob 表达式字符串或字符串数组。
支持事件
- 非新建分支的
push事件,会对比before和after,统计变更文件 commit.add事件,会统计新增 commit 中变更的文件- 非新建分支的
push、commit.add事件流水线中通过cnb:apply触发的事件,变更文件统计规则同上 PR触发的事件,统计PR中的变更文件PR触发的事件通过cnb:apply触发的事件,统计PR中的变更文件
限制
因为文件变更可能非常多,变更文件的统计限制为最多 300 个。 上述情况外,不适合统计文件变更,会忽略 ifModify 检查。
示例
示例 1:当修改文件列表中包含 a.js 或者 b.js,会执行此 Pipeline。
ifModify:
- a.js
- b.js示例 2:当修改文件列表中包含有 js 后缀的文件时,会执行此 Pipeline。
ifModify:
- "**/*.js"
- "*.js"示例 3:反向匹配,排除目录 legacy 和排除所有 Markdown 文件,有其他文件变更时触发。
ifModify:
- "**"
- "!(legacy/**)"
- "!(**/*.md)"
- "!*.md"示例 4:反向匹配,src 目录并且除目录 src/legacy 以外有变更时触发。
ifModify:
- "src/**"
- "!(src/legacy/**)"breakIfModify
- 类型:
Boolean - 默认值:
false
Job 执行前,如果源分支已更新,则终止构建。
retry
- 类型:
Number - 默认值:
0
失败重试次数,0 表示不重试。
重试间隔为 1s, 2s, 4s, 8s...
allowFailure
- 类型:
Boolean - 默认值:
false
是否允许当前流水线失败。
当此参数设置为 true 时,流水线的失败的状态不会上报到 CNB 上。
lock
- 类型:
Object|Boolean
给 pipeline 设置锁,pipeline 执行完后自动释放锁,锁不能跨仓库使用。
表现:流水线 A 获取到锁后,流水线 B 再申请锁,可以终止 A 或等待 A 执行完释放锁后,获取到锁再继续执行任务。
参数说明:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| key | String | 分支名-流水线名 | 自定义锁名 |
| expires | Number | 3600(1小时) | 锁过期时间(秒) |
| timeout | Number | 3600(1小时) | 超时时间(秒) |
| cancel-in-progress | Boolean | false | 是否终止占用锁或等待锁的流水线 |
| wait | Boolean | false | 锁被占用是否等待 |
| cancel-in-wait | Boolean | false | 是否终止正在等待锁的流水线 |
若 lock 为 true,则所有参数为默认值。
示例 1:lock 是 Boolean 格式
main:
push:
- lock: true
stages:
- name: stage1
script: echo "stage1"示例 2:lock 是 Object 格式
main:
push:
- lock:
key: key
expires: 600 # 10分钟
wait: true
timeout: 60 # 最多等待 1分钟
stages:
- name: stage1
script: echo "stage1"示例 3:停止 pull_request 下上一条正在进行的流水线
main:
pull_request:
- lock:
key: pr
cancel-in-progress: true
stages:
- name: echo hello
script: echo "stage1"sandbox
- 类型:
Boolean
是否开启沙箱模式。
设为 true 时,流水线以下环境变量无效:
Stage
- 类型:
Job|Object<name: Job>
Stage 表示流水线中的一个阶段,可包含一个或多个 Job。详见 Job 介绍。
配置项概览
Stage 支持以下配置项:
| 配置项 | 类型 | 说明 |
|---|---|---|
| name | String | 阶段名称 |
| ifNewBranch | Boolean | 仅新分支时执行 |
| ifModify | Array<String> | 文件变更时执行 |
| if | String | 条件执行脚本 |
| env | Object | 环境变量 |
| imports | Array<String> | 从文件导入环境变量 |
| retry | Number | 失败重试次数 |
| lock | Object | 阶段锁配置 |
| image | Object | 环境镜像 |
| jobs | Array | 任务列表 |
结构说明
单个 Job
当 Stage 只有一个 Job 时,可省略 Stage 层级,直接声明 Job。
stages:
- name: stage1
jobs:
- name: job A
script: echo hello可以简化为:
- stages:
- name: job A
script: echo hello当 Job 为字符串时,可视作脚本任务,name 和 script 都取该字符串,可继续简化为:
- stages:
- echo hello串行 Job
当 jobs 为数组时,这组 Job 会按顺序串行执行。
# 串行执行
stages:
- name: install
jobs:
- name: job1
script: echo "job1"
- name: job2
script: echo "job2"并行 Job
当 jobs 为对象时,这组 Job 会并行执行。
# 并行执行
stages:
- name: install
jobs:
job1:
script: echo "job1"
job2:
script: echo "job2"多个 Job 可灵活组织串行和并行。先串行后并行的示例:
main:
push:
- stages:
- name: serial first
script: echo "serial"
- name: parallel
jobs:
parallel job 1:
script: echo "1"
parallel job 2:
script: echo "2"
- name: serial next
script: echo "serial next"配置项说明
name
- 类型:
String
阶段名称。
ifNewBranch
- 类型:
Boolean - 默认值:
false
为 true 表示当前分支属于新分支(即 CNB_IS_NEW_BRANCH 为 true)时,才执行此 Stage。
条件组合
当同时存在 ifNewBranch / ifModify / if 时,其中有一个条件满足,此 Stage 就会执行。
ifModify
- 类型:
Array<String>|String
指定只有相应文件变动时,才执行此 Stage。使用 glob 匹配表达式。
if
- 类型:
Array<String>|String
指定一个 shell 脚本,当脚本退出码为 0 时,执行此 Stage。
示例 1:判断变量值
main:
push:
- env:
IS_NEW: true
stages:
- name: is new
if: |
[ "$IS_NEW" = "true" ]
script: echo is new
- name: is not new
if: |
[ "$IS_NEW" != "true" ]
script: echo not new示例 2:判断任务输出
main:
push:
- stages:
- name: make info
script: echo 'haha'
exports:
info: RESULT
- name: run if RESULT is haha
if: |
[ "$RESULT" = "haha" ]
script: echo $RESULTenv
- 类型:
Object
声明环境变量,仅对当前 Stage 生效。
Stage env 优先级比 Pipeline env 高。
imports
- 类型:
Array<String>|String
从文件导入环境变量,仅对当前 Stage 生效。用法同 Pipeline imports。
retry
- 类型:
Number - 默认值:
0
失败重试次数,0 表示不重试。
重试间隔为 1s, 2s, 4s, 8s...
lock
- 类型:
Boolean|Object
给 Stage 设置锁,Stage 执行完后自动释放锁。
表现:任务 A 获取到锁后,任务 B 需等待锁释放后才能继续执行。
参数说明:
| 参数 | 类型 | 说明 |
|---|---|---|
| lock.key | String | 自定义锁名,默认为 分支名-流水线名-stage下标 |
| lock.expires | Number | 锁过期时间(秒),默认 3600 |
| lock.wait | Boolean | 锁被占用时是否等待,默认 false |
| lock.timeout | Number | 等待锁的超时时间(秒),默认 3600 |
若 lock 为 true,则所有参数为默认值。
示例 1:lock 是 Boolean 格式
main:
push:
- stages:
- name: stage1
lock: true
jobs:
- name: job1
script: echo "job1"示例 2:lock 是 Object 格式
main:
push:
- stages:
- name: stage1
lock:
key: key
expires: 600 # 10分钟
wait: true
timeout: 60 # 最多等待 1分钟
jobs:
- name: job1
script: echo "job1"Stage.image
- 类型:
Object|String
指定当前 Stage 的环境镜像,在当前 Stage 下的所有任务默认都在这个镜像环境中执行。
该属性支持引用环境变量,参考变量替换。
属性:
| 属性 | 类型 | 说明 |
|---|---|---|
| image.name | String | 镜像名,如 node:20 |
| image.dockerUser | String | 指定 Docker 用户名,用于拉取指定的镜像 |
| image.dockerPassword | String | 指定 Docker 用户密码,用于拉取指定的镜像 |
如果指定 image 为字符串,则等同于指定了 image.name。
如果使用 云原生构建 的 Docker 制品库的镜像且未设置 image.dockerPassword,该参数会设为环境变量 CNB_TOKEN 的值。
jobs
- 类型:
Array<Job>|Object<name,Job>
定义一组任务。数组形式为串行执行,对象形式为并行执行。
Job
Job(任务)是最小的执行单元,主要分为脚本任务、插件任务和内置任务三种类型。前两者都支持指定 image 参数定义运行环境,这容易让新人混淆。参考脚本任务 vs 插件任务了解两者的区别。
配置项概览
Job 支持以下配置项:
| 配置项 | 类型 | 说明 |
|---|---|---|
| name | String | 任务名称 |
| ifModify | Array<String> | 文件变更时执行 |
| ifNewBranch | Boolean | 仅新分支时执行 |
| if | String | 条件执行脚本 |
| breakIfModify | Boolean | 源分支更新时终止 |
| skipIfModify | Boolean | 源分支更新时跳过 |
| env | Object | 环境变量 |
| imports | Array<String> | 从文件导入环境变量 |
| exports | Object | 导出环境变量 |
| timeout | Number | 超时时间 |
| allowFailure | Boolean | 允许失败 |
| lock | Object | 任务锁配置 |
| retry | Number | 失败重试次数 |
| type | String | 内置任务类型 |
| options | Object | 内置任务参数 |
| optionsFrom | Array<String> | 从文件加载参数 |
| script | String | Shell 脚本 |
| commands | String | Shell 脚本(兼容 Drone CI) |
| image | Object | 运行环境镜像 |
| settings | Object | 插件参数 |
| settingsFrom | Array<String> | 从文件加载插件参数 |
| args | Array<String> | 插件参数 |
任务类型
脚本任务
执行 Shell 脚本命令。
参数说明:
| 参数 | 类型 | 说明 |
|---|---|---|
| script | Array<String> | String | 要执行的 Shell 脚本,数组会用 && 连接 |
| image | String | 可选,指定脚本运行环境 |
示例:
- name: install
image: node:20
script: npm install简化写法:脚本任务可简化为字符串,此时 script 和 name 都取该字符串:
- echo hello等同于:
- name: echo hello
script: echo hello插件任务
插件即 Docker 镜像,也可称为镜像任务。
特点:
- 执行环境灵活
- 易于分享和复用
- 可跨 CI 平台使用
工作原理:通过向 ENTRYPOINT 传递环境变量来配置插件行为。
注意
通过 imports、env 设置的自定义环境变量不会传递给插件,但可在 settings、args 中使用变量替换。CNB 系统环境变量会传递给插件。
参数说明:
| 参数 | 类型 | 说明 |
|---|---|---|
| name | String | 任务名称 |
| image | Object | String | 插件镜像,详见 job.image |
| settings | Object | 插件参数,按插件文档填写,支持 $VAR 或 ${VAR} 引用环境变量 |
| settingsFrom | Array<String> | String | 指定本地或 Git 仓库文件路径,加载为插件任务参数 |
示例
with imports:
- name: npm publish
image: plugins/npm
imports: https://cnb.cool/<your-repo-slug>/-/blob/main/xxx/npm.json
settings:
username: $NPM_USER
password: $NPM_PASS
email: $NPM_EMAIL
registry: https://mirrors.xxx.com/npm/
folder: ./{
"username": "xxx",
"password": "xxx",
"email": "xxx@emai.com",
"allow_slugs": ["cnb/**/**"],
"allow_images": ["plugins/npm"]
}with settingsFrom:
- name: npm publish
image: plugins/npm
settingsFrom: https://cnb.cool/<your-repo-slug>/-/blob/main/xxx/npm-settings.json
settings:
registry: https://mirrors.xxx.com/npm/
folder: ./{
"username": "xxx",
"password": "xxx",
"email": "xxx@emai.com",
"allow_slugs": ["cnb/cnb"],
"allow_images": ["plugins/npm"]
}内置任务
使用 CNB 提供的内置功能。
参数说明:
| 参数 | 类型 | 说明 |
|---|---|---|
| type | String | 指定要执行的 内置任务 类型 |
| options | Object | 内置任务的参数 |
| optionsFrom | Array<String> | String | 从文件加载参数 |
options 中的字段优先级高于 optionsFrom。
引用配置文件权限控制参考 配置文件引用鉴权。
示例:
name: install
type: INTERNAL_JOB_NAME
optionsFrom: ./options.json
options:
key1: value1
key2: value2// ./options.json
{
"key1": "value1",
"key2": "value2"
}配置项说明
name
- 类型:
String
任务名称。
ifModify
- 类型:
Array<String>|String
指定只有相应文件变动时,才执行此任务。用法同 Stage ifModify。
ifNewBranch
- 类型:
Boolean - 默认值:
false
为 true 表示当前分支属于新分支(即 CNB_IS_NEW_BRANCH 为 true)时,才执行此任务。用法同 Stage ifNewBranch。
if
- 类型:
Array<String>|String
指定一个 shell 脚本,当脚本退出码为 0 时,执行此任务。用法同 Stage if。
breakIfModify
- 类型:
Boolean - 默认值:
false
Job 执行前,如果源分支已更新,则终止当前任务。
skipIfModify
- 类型:
Boolean - 默认值:
false
Job 执行前,如果源分支已更新,则跳过当前任务。
env
- 类型:
Object
声明环境变量,仅对当前 Job 生效。
Job env 优先级最高。
imports
- 类型:
Array<String>|String
从文件导入环境变量,仅对当前 Job 生效。用法同 Stage imports。
exports
- 类型:
Object
将任务执行结果导出为环境变量,供后续任务使用。生命周期为当前 Pipeline。
详情请见 环境变量
timeout
- 类型:
Number|String
设置单个任务的超时时间和无输出超时时间,默认单个任务的超时时间为 1 小时,最大不能超过 12 小时,无输出超时时间为 10 分钟。
对脚本任务和插件任务有效。
支持的时间单位:
| 单位 | 说明 |
|---|---|
| ms | 毫秒(默认) |
| s | 秒 |
| m | 分钟 |
| h | 小时 |
示例:
name: timeout job
script: sleep 1d
timeout: 100s # 任务将在100秒后超时退出详见 超时策略
allowFailure
- 类型:
Boolean|String - 默认值:
false
是否允许当前任务失败。
当此参数设置为 true 时,任务失败不会影响后续流程的执行和最终结果。
值为 String 类型时可读取环境变量。
lock
- 类型:
Object|Boolean
给 Job 设置锁,Job 执行完后自动释放锁。
表现:任务 A 获取到锁后,任务 B 需等待锁释放后才能继续执行。
参数说明:
| 参数 | 类型 | 说明 |
|---|---|---|
| lock.key | String | 自定义锁名,默认为 分支名-流水线名-stage下标-job名 |
| lock.expires | Number | 锁过期时间(秒),默认 3600 |
| lock.wait | Boolean | 锁被占用时是否等待,默认 false |
| lock.timeout | Number | 等待锁的超时时间(秒),默认 3600 |
若 lock 为 true,则所有参数为默认值。
示例 1:简化写法
name: 锁
lock: true
script: echo 'job 锁'示例 2:详细配置
name: 锁
lock:
key: key
expires: 10
wait: true
script: echo 'job 锁'retry
- 类型:
Number - 默认值:
0
失败重试次数,0 表示不重试。
重试间隔为 1s, 2s, 4s, 8s...
type
- 类型:
String
指定要执行的 内置任务 类型。
options
- 类型:
Object
内置任务的参数配置。
optionsFrom
- 类型:
Array<String>|String
从文件加载内置任务参数。与 imports 参数类似,配置为数组时,后面的配置会覆盖前面的。
options 中的字段优先级高于 optionsFrom。
script
- 类型:
Array<String>|String
要执行的 Shell 脚本。为数组时会自动使用 && 拼接。脚本的退出码作为任务的退出码。
注意
流水线默认使用 sh 作为命令行解释器,不同的 image 可能使用不同的解释器。
commands
- 类型:
Array<String>|String
作用同 script 参数,优先级比 script 高。主要为了兼容 Drone CI 语法。
Job.image
- 类型:
Object|String
指定任务的运行环境镜像。可用于脚本任务或插件任务。
该属性支持引用环境变量,参考变量替换。
属性:
| 属性 | 类型 | 说明 |
|---|---|---|
| image.name | String | 镜像名,如 node:20 |
| image.dockerUser | String | 指定 Docker 用户名,用于拉取指定的镜像 |
| image.dockerPassword | String | 指定 Docker 用户密码,用于拉取指定的镜像 |
如果指定 image 为字符串,则等同于指定了 image.name。
如果使用 云原生构建 的 Docker 制品库的镜像且未设置 image.dockerPassword,该参数会设为环境变量 CNB_TOKEN 的值。
settings
- 类型:
Object
插件任务的参数配置。按照插件文档填写,支持通过 $VAR 或 ${VAR} 引用环境变量。
settingsFrom
- 类型:
Array<String>|String
从文件加载插件任务参数。与 imports 参数类似。
优先级:
- 配置为数组时,后面的配置会覆盖前面的
settings中的字段优先级高于settingsFrom
引用配置文件权限控制参考 配置文件引用鉴权。
args
- 类型:
Array<String>
执行插件镜像时传递的参数,内容会追加到 ENTRYPOINT 中,仅支持数组。
示例:
- name: npm publish
image: plugins/npm
args:
- ls等同于执行:
docker run plugins/npm ls任务退出码说明
任务执行完成后会返回一个退出码,不同的退出码有不同的含义:
| 退出码 | 说明 |
|---|---|
| 0 | 任务成功,继续执行后续任务 |
| 78 | 任务成功,但中断当前流水线的执行(可在脚本中主动执行 exit 78 来中断流水线) |
| 其他数字 | 任务失败,同时中断当前流水线的执行 |
配置复用
include
使用 include 关键字,可以在当前配置文件中导入当前仓库或其他仓库中的 YAML 文件。这有助于对大型配置进行拆分,提高可维护性和复用性。
使用示例
template.yml(被引用的文件):
main:
push:
pipeline_2:
env:
ENV_KEY1: xxx
ENV_KEY3: inner
services:
- docker
stages:
- name: echo
script: echo 222.cnb.yml(主配置文件):
include:
- https://cnb.cool/<your-repo-slug>/-/blob/main/xxx/template.yml
main:
push:
pipeline_1:
stages:
- name: echo
script: echo 111
pipeline_2:
env:
ENV_KEY2: xxx # 新增环境变量
ENV_KEY3: outer # 覆盖 template.yml 中的 ENV_KEY3
stages:
- name: echo
script: echo 333 # 新增步骤合并后的等效配置:
main:
push:
pipeline_1: # key不存在,合并时新增
stages:
- name: echo
script: echo 111
pipeline_2: # key已存在,合并内容
env: # 对象合并:同名键覆盖,新键添加
ENV_KEY1: xxx # 来自 template.yml
ENV_KEY2: xxx # 来自 .cnb.yml (新增)
ENV_KEY3: outer # 来自 .cnb.yml (覆盖)
services: # 数组合并:追加元素
- docker # 来自 template.yml
stages: # 数组合并:追加元素
- name: echo # 来自 template.yml
script: echo 222
- name: echo # 来自 .cnb.yml
script: echo 333语法说明
include 支持三种引入方式:
include:
# 1. 直接传入配置文件路径 (字符串)
- "https://cnb.cool/<your-repo-slug>/-/blob/main/xxx/template.yml"
- "template.yml" # 相对路径(相对于仓库根目录)
# 2. 传入对象,提供更多控制
# path: 配置文件路径
# ignoreError: 未找到文件时是否报错。true-忽略错误;false-报错(默认)
- path: "template1.yml"
ignoreError: true
# 3. 直接传入内联的 YAML 配置对象
- config:
main:
push:
- stages:
- name: echo
script: echo "hello world"合并规则
不同文件间的配置按以下规则合并:
| 场景 | 合并结果 |
|---|---|
| 数组 + 数组 | 合并所有元素(追加) |
| 对象 + 对象 | 合并键,同名键的值会被覆盖 |
| 数组 + 对象 或 对象 + 数组 | 最终结果仅为数组(对象被忽略) |
合并顺序:
- 本地
.cnb.yml配置覆盖include引入的配置 include数组中后面的配置覆盖前面的配置
权限说明
出于安全考虑,与敏感信息保护原则一致,include 无法引用存储在密钥仓库中的文件,因为合并后的完整配置会展示在构建详情页中。
注意事项
- 支持嵌套 include,但最多不能超过 50 个配置文件
- include 的本地文件路径相对于项目根目录
- 不支持引用 git submodule 中的文件
- 不支持跨文件使用 YAML 锚点 (
&,*)