Pipeline
# Pipeline介绍
Pipeline
表示一个构建流程,由一个或者多个 Stage
组成,多个 Stage
依次执行,见 Stage 介绍。
一个 Pipeline
的基本配置如下:
name: 流水线名字
docker:
image: node
build: dev/Dockerfile
volumes:
- /root/.npm:copy-on-write
# 仅私有化部署场景支持 endpoints,SaaS 场景不支持
endpoints:
- 80
git:
enable: true
submodules: true
services:
- docker
env:
TEST_KEY: TEST_VALUE
imports:
- https://xxx/envs.yml
- ./env.txt
label:
type: MASTER
class: MAIN
stages:
- stage1
- stage2
- stage3
failStages:
- stage1whenFail
- stage2whenFail
ifModify:
- a.txt
- src/**/*
retry: 3
allowFailure: false
# name
- type:
String
指定流水线名,默认为 pipeline
。当有多条并行流水线时,默认流水线名为 pipeline
、pipeline-1
、pipeline-2
依此类推,可定义 name
指定流水线名来区分不同流水线
# runner
- type:
Object
指定与指定构建机相关的参数。
tags
: 可选,指定使用具备哪些标签的构建机cpus
: 可选,指定构建需使用的最大 cpu 核数(memory = cpu 核数 * 2 G),其中 cpu 和 memory 不超过 runner 机器实际大小
# tags
- type:
String
|Array<String>
- default:
coding:arch:amd64
指定使用具备哪些标签的构建机。
SaaS 场景下可用的官方构建机标签如下:
coding:arch:amd64
代表 amd64 架构构建机coding:arch:arm64:v8
代表 arm64/v8 架构构建机
示例:
master:
push:
- runner:
tags: coding:arch:arm64:v8
stages:
- name: uname
script: uname -a
# cpus
- type:
Number
指定构建需使用的最大 cpu 核数(memory = cpu 核数 * 2 G),其中 cpu 和 memory 不超过 runner 机器实际大小
未配置,则最大可用不超过 runner 机器实际 cpu 核数
示例:
# cpus = 1,memory = 2G
master:
push:
- runner:
cpus: 1
stages:
- name: echo
script: echo "hello world"
# docker
- type:
Object
指定 docker
相关的参数。详情见build-env
image
: 当前Pipeline
的环境镜像,在当前Pipeline
下的所有任务都将在这个镜像环境中执行。build
: 指定一个Dockerfile
,构建一个临时镜像,做为image
的值使用。volumes
: 声明数据卷,用于缓存场景。
# image
- type:
Object
|String
指定当前 Pipeline
的环境镜像,在当前 Pipeline
下的所有任务都将在这个镜像环境中执行,支持引用环境变量。
image.name
: 镜像名。如node:14
。image.dockerUser
:- type:
String
指定docker用户名,用于拉取指定的镜像。若指定image为非公开镜像则必须指定,否则会出现没有权限读取镜像的情况。
- type:
image.dockerPassword
:- type:
String
指定docker用户密码,用于拉取指定的镜像。若指定image为非公开镜像则必须指定,否则会出现没有权限读取镜像的情况。
- type:
如果指定image
为字符串,则等同于指定了image.name
。
示例:
master:
push:
- docker:
# 取 docker 官方镜像仓库中的 node:14 镜像作为构建容器
image: node:14
stages:
- name: show version
script: node -v
master:
push:
- imports: https://demo-team.coding.net/p/demo-project/d/demo-private-reop/git/tree/master/envs/docker.yml
docker:
# 取自定义构建镜像,作为构建容器
image:
name: team-docker.pkg.coding.net/project/images/pipeline-env:1.0
dockerUser: $DOCKER_USER
dockerPassword: $DOCKER_PASSWORD
stages:
- name: echo
script: echo "hello world"
docker.yml
DOCKER_USER: user
DOCKER_PASSWORD: password
# build
- type:
Object
|String
指定一个 Dockerfile
,构建一个临时镜像,做为 image
的值使用,支持引用环境变量。
build.dockerfile
:- type:
String
Dockerfile
路径。- type:
build.target
:- type:
String
对应docker build中--target参数,docker build会执行到指定的stage时停止。
- type:
build.by
:- type:
Array<String>
|String
用来声明缓存构建过程中依赖的文件列表。注意:未出现在
by
列表中的文件,除了dockerfile,其他在构建缓存过程中,都当不存在处理。String
类型时,多个文件可用英文逗号分隔。- type:
build.versionBy
:- type:
Array<String>
|String
用来进行版本控制,所指向的文件内容发生变化,我们就会认为是一个新的版本, 具体的计算逻辑见这个表达式:md5(dockerfile + versionBy + buildArgs)。
String
类型时,多个文件可用英文逗号分隔。- type:
build.buildArgs
:- type:
Object
在 build 时插入额外的构建参数 (--build-arg $key=$value), value 值为 null 时只加入 key (--build-arg $key)。
- type:
build.ignoreBuildArgsInVersion
:- type:
Boolean
版本计算是否忽略buildArgs。详见版本控制。
- type:
build.dockerImageName
:- type:
String
指定缓存镜像的镜像名(不含tag)。如:
team-docker.pkg.coding.net/projct/docker-cache
。不指定时,则只把镜像缓存在当前构建机- type:
build.dockerUser
:- type:
String
指定docker用户名,用于推送和拉取缓存镜像。指定dockerImageName时必须指定,否则会出现没有权限的情况
- type:
build.dockerPassword
:- type:
String
指定docker用户密码,用与推送和拉取缓存镜像。指定dockerImageName时必须指定,否则会出现没有权限的情况
- type:
build.sync
:- type:
String
是否等待
docker push
成功后才继续。默认为false
。- type:
如果指定build
为字符串,则等同于指定了build.dockerfile
。
Dockerfile 用法:
master:
push:
- docker:
# 通过 Dockerfile 指定构建环境
build: ./image/Dockerfile
stages:
- stage1
- stage2
- stage3
master:
push:
- docker:
# 通过 Dockerfile 指定构建环境
build:
dockerfile: ./image/Dockerfile
dockerImageName: team-docker.pkg.coding.net/project/images/pipeline-env
dockerUser: $DOCKER_USER
dockerPassword: $DOCKER_PASSWORD
stages:
- stage1
- stage2
- stage3
master:
push:
- docker:
# 通过 Dockerfile 指定构建环境
build:
dockerfile: ./image/Dockerfile
target: builder #对应docker build中--target参数
stages:
- stage1
- stage2
- stage3
Dockerfile versionBy 用法:
示例:将 pnpm 缓存到环境镜像中,加速后续pnpm i过程
master:
push:
# 通过 Dockerfile 指定构建环境
- docker:
build:
dockerfile: ./Dockerfile
versionBy:
- package-lock.json
stages:
- name: pnpm i
script: pnpm i
- stage1
- stage2
- stage3
FROM node:16
RUN npm config set registry https://mirrors.tencent.com/npm/ &&\
npm i -g pnpm &&\
pnpm config set store-dir /lib/pnpm
WORKDIR /data/orange-ci/workspace
COPY package.json package-lock.json ./
RUN pnpm i
[pnpm i] Progress: resolved 445, reused 444, downloaded 0, added 100
[pnpm i] Progress: resolved 445, reused 444, downloaded 0, added 141
[pnpm i] Progress: resolved 445, reused 444, downloaded 0, added 272
[pnpm i] Progress: resolved 445, reused 444, downloaded 0, added 444, done
[pnpm i]
[pnpm i] dependencies:
[pnpm i] + mocha 8.4.0 (10.0.0 is available)
[pnpm i]
[pnpm i] devDependencies:
[pnpm i] + babel-eslint 9.0.0 (10.1.0 is available)
[pnpm i] + eslint 5.16.0 (8.23.0 is available)
[pnpm i] + jest 27.5.1 (29.0.2 is available)
[pnpm i]
[pnpm i]
[pnpm i] Job finished, duration: 6.8s
# volumes
- type:
Array<String>
|String
声明数据卷,可作为缓存用于后续流水线,多个数据卷可用通过数组或者用,
号做分割符传入
用途:
- 将文件存储在构建机上,可在后续构建中复用。(
type
不为data
时)- 原理:将构建机上目录 mount 到各容器中,该目录在流水线退出后会保留。可作为缓存用于后续流水线。该目录在构建机上会按不同的 Git 仓库相互隔离。
- 将容器中的指定目录,共享给其他容器中使用。(仅
type
为data
时)- 原理:通过创建数据卷,然后 mount 到各容器中。与直接将构建机上目录 mount 到容器中方式不同的是:当指定的目录在容器中已经存在,会先把容器中内容自动复制到数据卷,而不是将数据卷内容直接覆盖容器中目录。
支持引用环境变量,支持的格式:
<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
: 只读,变更(新增、删除、修改)在构建结束后丢弃data
: 创建一个临时数据卷,该数据卷在流水线结束时会自动清理
# volumes 示例
示例1 : 挂载构建节点上目录到容器中,实现本地缓存效果
master:
push:
- docker:
image: node:14
# 声明数据卷
volumes:
- /data/config:read-only
- /data/mydata:read-write
# 使用缓存,同时更新
- /root/.npm
# 使用 master 缓存,同时更新
- master:/root/.gradle:copy-on-write
stages:
- stage1
- stage2
- stage3
merge_request:
- docker:
image: node:14
# 声明数据卷
volumes:
- /data/config:read-only
- /data/mydata:read-write
# 使用 copy-on-write 缓存
- /root/.npm
- node_modules
# mr 使用 master 缓存,但不更新
- master:/root/.gradle:copy-on-write-read-only
stages:
- stage1
- stage2
- stage3
示例2:将打包在容器中文件,共享到其他容器中使用
# .coding-ci.yml
master:
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-app
# endpoints
- type:
Array<Number>
仅私有化部署场景支持 endpoints,SaaS 场景不支持
声明目标端口列表,自动转换为 endpoints
(ip:port) ,可供外部直接访问。
转换后的 endpoints
可通过环境变量引用。
环境变量格式为:$CODING_PIPELINE_ENDPOINT_{port}
目标端口需绑定在 0.0.0.0
网卡上,目前仅支持 tcp 协议。
# endpoints 示例
# .coding-ci.yml
master:
push:
- name: example-for-endpoints
docker:
image: nginx:latest
endpoints:
- 80
stages:
- name: echo endpoints
script: echo "$CODING_PIPELINE_ENDPOINT_80"
# git
- type:
Object
提供 Git 仓库相关配置。
# git.enable
- type:
Boolean
- default:
true
默认值为 true
。指定是否拉取代码。
mergeable
、 branch.delete
事件,默认值为 false
。其他事件,默认值为 true
# git.submodules
- type:
Object
|Boolean
- default:
true
指定是否要拉取子项目(submodules)。
支持 Object
形式指定具体参数,字段缺省时,默认值为:
{
"enable":true,
"remote":false
}
基本用法:
master:
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.submodules.enable
是否指定是否要拉取子项目 submodules
。
# git.submodules.remote
执行 git submodule update
时是否添加 --remote
参数,用于每次拉取 submodule
最新的代码
# services
- type:
Array<String>
用于声明构建时需要的服务,格式:name:[version]
, version
是可选的。
目前支持的服务有:
docker: 开启
dind
服务,当构建过程中需要使用docker build
,docker login
等操作时声明。会自动在环境注入docker cli
命令行工具示例:
master: push: - services: - docker docker: image: alpine stages: - name: docker info script: - docker info - docker ps
vscode: 需要远程开发时声明。用法参见vscode:go
# env
- type:
Object
指定环境变量。可以定义一组环境变量,在任务执行中使用。对当前 Pipeline
内的所有任务均有效。
# imports
- type:
Array<String>
|String
指定某个本仓库或另外 Coding Git 仓库文件路径,可以读取此文件作为环境变量来源。
一般使用一个私有仓库来存放诸如 npm
或者 docker
等账号密码。
支持的文件格式列表:
yaml
:所有根路径下的属性名都会导出为环境变量,解析文件后缀为yml
。json
: 所有根路径下的属性名都会导出为环境变量,解析文件后缀为json
。plain
: 每行格式为key=value
,除了以上涉及的后缀都以此方式解析。(不推荐)
同名 key 优先级:
- 当配置 imports 为数组时,如遇到参数重复的情况,后面的配置会覆盖前面的。
- 如果和
env
参数中重复,那么env
中的参数会覆盖掉imports
文件中的。
变量赋值:
imports
文件路径可读取环境变量。若是数组,下面的文件路径可读取上面文件中的变量
master:
push:
- imports:
- ./env1.json
- $FILE
- https://xxx/xxs.yml
stages:
- name: echo
script: echo $TEST_ENV
访问控制:
- 默认会检查流水线发起人是否具备目标仓库的访问权限
- 可在引用的目标文件中声明
allow_slugs
字段,控制可访问范围
allow_slugs:
如果引用的目标文件中含有 allow_slugs
,那么只会检查当前仓库路径(team/project/repo)是否在 allow_slugs
指定的白名单中,而不会检查流程发起人是否有权限。
allow_slugs
为 glob
模式字符串数组,表示允许特定的项目使用。
如 team_name/project_name/*
,匹配一个项目下面的所有仓库:
key: value
allow_slugs:
- team_name/project_name/*
允许被所有仓库引用
key: value
allow_slugs:
- "**"
# label
- type:
Object
为流水线指定标签。每个标签的值可以是一个字符串,也可以是一个字符串数组。该标签可用于后续流水线记录筛选等功能。
这里举一种工作流的例子:master 分支合并即发布预发布环境,打 tag 后发布正式环境。
master:
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.sh
# stages
- type:
Array<Job>
定义一组阶段任务,每个阶段串行运行。
# failStages
- type:
Array<Job>
定义一组失败阶段任务。当正常流程失败,会依次执行此阶段任务。
# ifNewBranch
- type:
Boolean
- default:
false
为 true
表示当前分支属于新分支(即 CODING_IS_NEW_BRANCH
为 true
)时,才执行此 Pipeline
。
当同时存在
ifNewBranch
/ifModify
时,其中有一个条件满足,此Pipeline
就会执行。
# ifModify
- type:
Array<String>
|String
指定一个 glob
文件匹配规则或者文件名列表,只有命中规则时,才执行此 Pipeline
。
示例1:
当修改文件列表中包含 a.js
或者 b.js
,会执行此 Pipeline
。
ifModify:
- a.js
- b.js
示例2:
当修改文件列表中包含有 js
后缀的文件时,会执行此 Pipeline
。
其中 **/*.js
表示匹配所有子目录中的 js
后缀文件,*.js
表示所有根目录中的 js
后缀文件。
ifModify:
- "**/*.js"
- "*.js"
示例3:
反向匹配,除目录 legacy 以外有变更时触发
ifModify:
- "**"
- "!(legacy/**)"
案例四:
反向匹配,src 目录并且除目录 src/legacy 以外有变更时触发
ifModify:
- 'src/**'
- '!(src/legacy/**)'
# breakIfModify
- type:
Boolean
- default:
false
Job
执行前,如果源分支已更新,则终止构建。
# retry
- type:
Number
- default:
0
失败重试次数, 0
表示不重试。
# allowFailure
- type:
Boolean
- default:
false
是否允许当前流水线 失败。
当此参数设置为 true
时,流水线的失败的状态不会上报到 Coding 上。
# lock
- type:
Object
|Boolean
给 pipeline
设置锁,pipeline
执行完后自动释放锁,锁不能跨仓库使用。
表现: 流水线 A 获取到锁后,流水线 B 再申请锁,可以终止A或等待A执行完释放锁后,获取到锁再继续执行任务。
key:
- type:
String
自定义锁名,默认为
分支名-流水线名
,既锁范围默认为当前pipeline
- type:
expires:
- type:
Number
- default:
3600
(一小时)
锁过期时间,过期后自动释放锁,单位“秒”。
- type:
timeout:
- type:
Number
- default:
3600
(一小时)
超时时间,用于等待锁的场景下,单位“秒”。
- type:
cancel-in-progress:
- type:
Boolean
- default:
false
是否终止占用锁或等待锁的流水线,让当前流水线获取锁并执行
- type:
wait:
- type:
Boolean
- default:
false
锁被占用是否等待,为 false 则直接报错,不能与
cancel-in-progress
同时使用- type:
例1: lock 是 Boolean 格式
master:
push:
- lock: true
stages:
- name: stage1
script: echo "stage1"
例2: lock 是 Object 格式
master:
push:
- lock:
key: key
expires: 600 # 10分钟
wait: true
timeout: 60 # 最多等待 1分钟
stages:
- name: stage1
script: echo "stage1"
例3: 停止 merge_request 下上一条正在进行的流水线
master:
merge_request:
- lock:
key: mr
cancel-in-progress: true
stages:
- name: echo hello
script: echo "stage1"
Stage →