Jenkins声明式Pipeline语法

Jenkins声明式Pipeline语法
十八岁Jenkins声明式 Pipeline 语法
声明式流水线必须包含在一个 Pipeline 块中,比如以下是一个 Pipeline 块的格式:
1 | pipeline { |
在声明式流水线中有效的基本语句和表达式遵循与 Groovy 的语法同样的规则,但有以下例外:
流水线顶层必须是一个 block,即 pipeline{};
分隔符可以不需要分号,但是每条语句都必须在自己的行上;
块只能由 Sections、Directives、Steps 或 assignment statements 组成;
属性引用语句被当做是无参数的方法调用,比如 input 会被当做 input()。
1.Sections常用指令
声明式流水线中的 Sections 不是一个关键字或指令,而是包含一个或多个 Agent、Stages、post、Directives 和 Steps 的代码区域块。
1.1Agent语法
Agent 表示整个流水线或特定阶段中的步骤和命令执行的位置,该部分必须在 pipeline 块的顶层被定义,也可以在 stage 中再次定义,但是 stage 级别是可选的。
any:在任何可用的代理上执行流水线,配置语法:
1
2
3pipeline {
agent any
}none:表示该 Pipeline 脚本没有全局的 agent 配置。当顶层的 agent 配置为 none 时,每个 stage 部分都需要包含它自己的 agent。配置语法:
1
2
3
4
5
6
7
8pipeline {
agent none
stages {
stage('Stage For Build'){
agent any
}
}
}label:选择某个具体的节点执行 Pipeline 命令,例如:agent { label ‘my-defined-label’ }。在标签’my-defined-label’的代理节点上执行命令。这里定义的标签要和Jenkins控制台中添加的节点时设置的标签保持一致。
配置语法:
1
2
3
4
5
6
7
8pipeline {
agent none
stages {
stage('Stage For Build'){
agent { label 'my-slave-label' }
}
}
}如果agent没有指定的标签,任务会一致处于等待状态:
node:和 label 配置类似,只不过是可以添加一些额外的配置,比如 customWorkspace;
dockerfile:使用从源码中包含的 Dockerfile 所构建的容器执行流水线或 stage。此时对应的 agent 写法如下:
1
2
3
4
5
6
7
8agent {
dockerfile {
filename 'Dockerfile.build'
dir 'build'
label 'my-defined-label'
additionalBuildArgs '--build-arg version=1.0.2'
}
}docker:这是代理类型的声明。它指定了流水线将使用 Docker 节点来运行(在 Jenkins 管理界面(Manage Jenkins -> Nodes)中手动添加并成功连接的 Agent 节点。)。Jenkins 会自动在配置好的节点(Slave)上执行
docker run命令。这是比较推荐的方式,可以避免处理编译环境或者slave的版本问题。比如java编译,使用 maven 镜像启动slave进行打包,同时可以指定 args:1
2
3
4
5
6
7agent{
docker{ #指定流水线将使用 Docker 节点来运行。Jenkins 会自动在配置好的节点(Slave)上执行 docker run 命令。
image 'registry.cn-beijing.aliyuncs.com/k8s-liujunwei/maven:3.5.3'
label 'my-defined-label' #如果不指定标签,Jenkins会任意选择一个节点执行,如果节点没有docker任务就会报错。
args '-v /tmp:/tmp'
}
}kubernetes:Jenkins 也支持使用 Kubernetes 创建 Slave,也就是常说的动态 Slave(需要重点掌握)。配置示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30agent {
kubernetes {
label podlabel
yaml """
kind: Pod
metadata:
name: jenkins-agent
spec:
containers:
- name: kaniko
image: gcr.io/kaniko-project/executor:debug
imagePullPolicy: Always
command:
- /busybox/cat
tty: true
volumeMounts:
- name: aws-secret
mountPath: /root/.aws/
- name: docker-registry-config
mountPath: /kaniko/.docker
restartPolicy: Never
volumes:
- name: aws-secret
secret:
secretName: aws-secret
- name: docker-registry-config
configMap:
name: docker-registry-config
"""
}
1.2Agent配置实例
示例 1:假设有一个 Java 项目,需要用 mvn 命令进行编译,此时可以使用 maven 的镜像作为 agent。配置如下:
1 | Jenkinsfile (Declarative Pipeline) // 可以不要此行 |
示例 2:本示例在流水线顶层将 agent 定义为 none,那么此时 stage 部分就需要必须包含它自己的 agent 部分。在 stage(‘Example Build’)部分使用 maven:3-alpine 执行该阶段步骤,在 stage(‘Example Test’)部分使用 openjdk:8-jre 执行该阶段步骤。此时 Pipeline 如下:
1 | Jenkinsfile (Declarative Pipeline) // 可以不要此行 |
示例 3:上述的示例也可以用基于 Kubernetes 的 agent 实现。比如定义具有三个容器的 Pod,分别为 jnlp (负责和Jenkins Master 通信)、build(负责执行构建命令)、kubectl(负责执行Kubernetes相关命令),在steps中可以通过containers字段,选择在某个容器执行命令:
1 | pipeline { |
1.3Post语法
Post 一般用于流水线结束后的进一步处理,比如错误通知等。Post 可以针对流水线不同的结果做出不同的处理,就像开发程序的错误处理,比如 Python 语言的 try catch。Post 可以定义在 Pipeline 或 stage 中,目前支持以下条件:
- always:无论 Pipeline 或 stage 的完成状态如何,都允许运行该 post 中定义的指令;
- changed:只有当前 Pipeline 或stage 的完成状态与它之前的运行不同时,才允许在该post 部分运行该步骤;
- fixed:当本次 Pipeline 或 stage 成功,且上一次构建是失败或不稳定时,允许运行该post 中定义的指令;
- regression:当本次 Pipeline 或 stage 的状态为失败、不稳定或终止,且上一次构建的状态为成功时,允许运行该 post 中定义的指令;
- failure:只有当前 Pipeline 或 stage 的完成状态为失败(failure),才允许在 post 部分运行该步骤,通常这时在 Web 界面中显示为红色;
- success:当前状态为成功(success),执行 post 步骤,通常在 Web 界面中显示为蓝色或绿色;
- unstable:当前状态为不稳定(unstable),执行 post 步骤,通常由于测试失败或代码违规等造成,在 Web 界面中显示为黄色;
- aborted:当前状态为终止(aborted),执行该post步骤,通常由于流水线被手动终止触发,这时在 Web 界面中显示为灰色;
- unsuccessful:当前状态不是 success 时,执行该 post 步骤;
- cleanup:无论 pipeline 或 stage 的完成状态如何,都允许运行该 post 中定义的指令。和 always 的区别在于,cleanup 会在其它执行之后执行。
1.31Post配置示例
示例:一般情况下 post 部分放在流水线的底部,比如本实例,无论 stage 的完成状态如何,都会输出一条 I will always say Hello again!的信息
1 | Jenkinsfile (Declarative Pipeline) // 可以不写该行 |
也可以将 post 写在 stage中:
1 | pipeline { |
1.4Stages语法
Stages 包含一个或多个 stage 指令,同时可以在 stage 中的 steps 块中定义真正执行的指令。比如创建一个流水线,stages 包含一个名为 Example 的 stage,该 stage 执行 echo ‘Hello World’
命令输出 Hello World 字符串:
1 | Jenkinsfile (Declarative Pipeline) |
1.5Steps语法
Steps 部分在给定的 stage 指令中执行的一个或多个步骤,比如在 steps 定义执行一条 shell 命令:
1 | Jenkinsfile (Declarative Pipeline) |
或者是使用 sh 字段执行多条指令,多条指令用三个双引号引起来:
1 | Jenkinsfile (Declarative Pipeline) |
2.Directives常用指令
Directives 可用于一些执行stage 时的条件判断或预处理一些数据,和Sections 一致,Directives不是一个关键字或指令,而是包含了 environment、options、parameters、triggers、stage、tools、 input、when 等配置。
2.1Environment环境变量
Environment 主要用于在流水线中配置的一些环境变量,根据配置的位置决定环境变量的作用域。可以定义在 pipeline 中作为全局变量,也可以配置在 stage 中作为该 stage 的环境变量。
该指令支持一个特殊的方法 credentials(),该方法可用于在 Jenkins 环境中通过标识符访问预定义的凭证。对于类型为 Secret Text 的凭证,credentials()可以将该 Secret 中的文本内容赋值给环境变量。对于类型为标准的账号密码型的凭证,指定的环境变量为 username 和 password,并且也会定义两个额外的环境变量,分别为 MYVARNAME_USR 和 MYVARNAME_PSW。
假如需要定义一个变量名为CC的全局变量和一个名为AN_ACCESS_KEY的局部变量,并且用credentials读取一个Secret文本,可以通过以下方式定义:
1 | Jenkinsfile (Declarative Pipeline) |
2.2Options
Jenkins 流水线支持很多内置指令,比如 retry 可以对失败的步骤进行重复执行n 次,可以根据不同的指令实现不同的效果。比较常用的指令如下:
- buildDiscarder : 保 留 多 少 个 流 水 线 的 构 建 记 录 。 比 如 : options { buildDiscarder(logRotator(numToKeepStr: ‘1’)) };
- disableConcurrentBuilds:禁止流水线并行执行,防止并行流水线同时访问共享资源导致流水线失败。比如:options { disableConcurrentBuilds() };
- disableResume :如果控制器重启,禁止流水线自动恢复。比如: options { disableResume() };
- newContainerPerStage:agent 为 docker 或 dockerfile 时,每个阶段将在同一个节点的新容器中运行,而不是所有的阶段都在同一个容器中运行。比如: options { newContainerPerStage () };
- quietPeriod:流水线静默期,也就是触发流水线后等待一会在执行。比如:options { quietPeriod(30) };
- retry:流水线失败后重试次数。比如:options { retry(3) };
- timeout:设置流水线的超时时间,超过流水线时间,job 会自动终止。比如:options { timeout(time: 1, unit: ‘HOURS’) };
- timestamps:为控制台输出时间戳。比如:options { timestamps() }。
timeout字段配置案例如下:
只需要添加 options 字段即可:
1 | pipeline { |
Option 除了写在Pipeline 顶层,还可以写在 stage 中,但是写在 stage 中的option 仅支持 retry、 timeout、timestamps,或者是和 stage 相关的声明式选项,比如 skipDefaultCheckout。处于 stage级别的options 写法如下:
1 | pipeline { |
进阶用法:结合 retry
你可能希望在超时后自动重试,可以嵌套使用:
1 | stage('Health Check') { |
1 | timeout 指令通常包含两个主要字段: |
2.3Parameters参数化构建
Parameters 提供了一个用户在触发流水线时应该提供的参数列表,这些用户指定参数的值可以通过params 对象提供给流水线的 step(步骤)。
目前支持的参数类型如下:
string:字符串类型的参数,例如:parameters { string(name: ‘DEPLOY_ENV’, defaultValue:’staging’, description: ‘’) },表示定义一个名为 DEPLOY_ENV 的字符型变量,默认值为staging;
text:文本型参数,一般用于定义多行文本内容的变量。例如 parameters { text(name: ‘DEPLOY_TEXT’, defaultValue: ‘One\nTwo\nThree\n’, description: ‘’) },表示定义一个名为 DEPLOY_TEXT 的变量,默认值是’One\nTwo\nThree\n’;
booleanParam:布尔型参数,例如: parameters { booleanParam(name: ‘DEBUG_BUILD’, defaultValue: true, description: ‘’) };
choice:选择型参数,一般用于给定几个可选的值,然后选择其中一个进行赋值,例如: parameters { choice(name: ‘CHOICES’, choices: [‘one’, ‘two’, ‘three’], description: ‘’) },表示定义一个名为 CHOICES 的变量,可选的值为one、two、three;
password:密码型变量,一般用于定义敏感型变量,在 Jenkins 控制台会输出为*。例如:parameters { password(name: ‘PASSWORD’, defaultValue: ‘SECRET’, description: ‘A secret password’) },表示定义一个名为 PASSWORD 的变量,其默认值为 SECRET。
Parameters 用法如下:
1 | pipeline { |
pipeline生产配置案例:
1 | pipeline { |
2.4Triggers自动触发流水线
在 Pipeline 中可以用 triggers 实现自动触发流水线执行任务,可以通过 Webhook、Cron、 pollSCM 和 upstream 等方式触发流水线。
假如某个流水线构建的时间比较长,或者某个流水线需要定期在某个时间段执行构建,可以使用 cron 配置触发器,比如每5分钟执行一次:
1 | cron字段是基于时间触发构建 |
注意:H 的意思不是HOURS 的意思,而是 Hash 的缩写。主要为了解决多个流水线在同一时间同时运行带来的系统负载压力。H(哈希值)是Jenkins特有的语法,用于在多个任务之间分散负载。如果你希望任务在确切的五分钟间隔执行,可以使用*/5 * * * *,但这可能会导致所有任务在同一分钟开始执行,增加负载。
使用 cron 字段可以定期执行流水线,如果代码有变动想要重新触发流水线,可以使用 pollSCM字段:
1 | pollSCM是基于代码仓库是否发生变化来触发构建,如果代码有变化就会触发构建,后面的时间是多久对代码仓库进行检查 |
Upstream 可以根据上游 job 的执行结果决定是否触发该流水线。比如当 job1 或 job2 执行成功时触发该流水线:
1 | pipeline { |
- upstream:这是一个触发器类型,表示当前Pipeline将被上游项目(即
upstreamProjects中列出的项目)的构建结果所触发。 - upstreamProjects:这是一个参数,指定了哪些上游项目可以触发当前Pipeline的构建。在这个例子中,
job1和job2是上游项目。 - threshold:这是一个参数,定义了上游项目构建结果的阈值,只有当上游项目的构建结果达到或超过这个阈值时,当前Pipeline才会触发。在这个例子中,
hudson.model.Result.SUCCESS表示只有当上游项目的构建成功(即结果为SUCCESS)时,当前Pipeline才会触发。除了 SUCCESS 还有 UNSTABLE、FAILURE、NOT_BUILT、ABORTED等。
还有一种是Webhook的触发构建,该类型在后面会记录。
2.5Input交互式操作
Input 字段可以实现在流水线中进行交互式操作,比如选择要部署的环境、是否继续执行某个阶段等。
配置 Input 支持以下选项:
message:必选,需要用户进行 input 的提示信息,比如:“是否发布到生产环境?”;
id:可选,input 的标识符,默认为 stage 的名称;
ok:可选,确认按钮的显示信息,比如:“确定”、“允许”;
submitter:可选,允许提交 input 操作的用户或组的名称,如果为空,任何登录用户均可提交 input;
parameters:提供一个参数列表供 input 使用。
假如需要配置一个提示消息为“还继续么”、确认按钮为“继续”、提供一个 PERSON 的变量的参数,并且只能由登录用户为alice 和 bob 提交的 input 流水线:
1 | pipeline { |
简单案例:主要关注 stage(‘Manual Approval for Production’) 部分的input定义和调用
1 | pipeline { |
2.6When条件判断
When 指令允许流水线根据给定的条件决定是否应该执行该 stage,when 指令必须包含至少一个条件。如果 when 包含多个条件,所有的子条件必须都返回 True,stage 才能执行。
When 也可以结合not、allOf、anyOf 语法达到更灵活的条件匹配。
目前比较常用的内置条件如下:
- branch:当正在构建的分支与给定的分支匹配时,执行这个 stage,例如:when { branch ‘master’ }。注意,branch 只适用于多分支流水线;
- changelog : 匹配提交的 changeLog 决定是否构建, 例如: when { changelog ‘.*^\[DEPENDENCY\] .+$’ };
- environment:当指定的环境变量和给定的变量匹配时,执行这个 stage,例如:when { environment name: ‘DEPLOY_TO’, value: ‘production’ };
- equals:当期望值和实际值相同时,执行这个 stage,例如:when { equals expected: 2, actual: currentBuild.number };
- expression:当指定的 Groovy 表达式评估为 True,执行这个 stage,例如:when { expression { return params.DEBUG_BUILD } };
- tag:如果 TAG_NAME 的值和给定的条件匹配,执行这个 stage,例如:when { tag “release-*” };
- not:当嵌套条件出现错误时,执行这个 stage,必须包含一个条件,例如:when { not { branch ‘master’ } };
- allOf:当所有的嵌套条件都正确时,执行这个 stage,必须包含至少一个条件,例如:when { allOf { branch ‘master’; environment name: ‘DEPLOY_TO’, value: ‘production’ } };
- anyOf:当至少有一个嵌套条件为 True 时,执行这个 stage,例如:when { anyOf { branch ‘master’; branch ‘staging’ } }。
示例1:当分支为 production 时,执行 Example Deploy 步骤:
1 | pipeline { |
也可以同时配置多个条件,比如分支是 pro,而且 DEPLOY_TO 变量的值为 production时,才执行 Example Deploy:
1 | pipeline { |
也可以使用 anyOf 进行匹配其中一个条件即可,比如分支为 pro,DEPLOY_TO 为production 或staging 时执行 Deploy:
1 | pipeline { |
也可以使用 expression 进行正则匹配,比如当 BRANCH_NAME 为 dev 或着uat(满足其一),并且 DEPLOY_TO 为production 或 staging(满足其一) 时才会执行 Example Deploy:
1 | pipeline { |
默认情况下,如果定义了某个 stage 的 agent,在进入该 stage 的 agent 后,该 stage 的 when条件才会被评估,但是可以通过一些选项更改此选项。比如在进入 stage 的agent 前评估when,可以使用 beforeAgent,当 when 为 true 时才进行该 stage。
目前支持的前置条件如下:
beforeAgent:最常用的性能优化,如果 beforeAgent 为 true,则会先评估 when 条件。在 when 条件为 true时,才会进入该 stage;
beforeInput:如果 beforeInput 为 true,则会先评估 when 条件。在 when 条件为 true时,才会进入到 input 阶段;
beforeOptions:如果 beforeoptions 为 true,则会先评估 when 条件。在 when 条件为 true时,才会进入到 options 阶段;
简单来说,这些选项决定了 Jenkins 是“先占位(拿资源),再判断”,还是“先判断,再占位”。
在 Jenkins 默认逻辑下,一旦进入 stage,它会先去排队抢 Agent(比如一台 Docker 节点或服务器),抢到后再去判断 when。如果你没抢到 Agent,流水线就会卡在那里死等,即使最后 when 条件根本不满足。
注意:beforeOptions 优先级大于beforeInput 大于 beforeAgent
配置一个 beforeAgent 示例如下:
1 | pipeline { |
配置一个 beforeInput 示例如下:
1 | pipeline { |
配置一个 beforeOptions 示例如下:
1 | pipeline { |
3.Parallel并发指令
在 Jenkins 声明式流水线(Declarative Pipeline) 中,parallel 用于让多个 Stage 或步骤同时执行,核心目的是 缩短流水线执行时间。并不是“某些固定任务才能并行”,而是 只要任务之间没有依赖关系,都可以并行执行。
比如对分支 A、B、 C 进行并行处理:
1 | pipeline { |
设置failFast 为true 表示并行流水线中任意一个stage 出现错误,其它 stage 也会立即终止。也可以通过options 配置在全局:
1 | pipeline { |
4.Pipeline常用变量处理
4.1 内置环境变量
Jenkins 有许多内置变量可以直接在 Jenkinsfile 中使用,可以通过任务中的流水线语法获取 ,例如:http://192.168.0.87:8080/job/parallel-test/pipeline-syntax/globals#env 获取完整列表。目前比较常用的环境变量如下:
- BUILD_ID:构建 ID,对于 1.597 及以上版本和 BUILD_NUMBER 一致,而对于更早版本 的构建则是一个 YYYY-MM-DD_hh-mm-ss 格式的时间戳;这里的数字就是BUILD_ID,如下图:
- BUILD_NUMBER:当前构建的 ID,和 BUILD_ID 一致;
- BUILD_TAG:用来标识构建的版本号,格式为:**jenkins-${JOB_NAME}-${BUILD_NUMBER}**, 可以对产物进行命名,比如生产的 jar 包名字、镜像的 TAG 等;
- BUILD_URL:本次构建的完整 URL,比如:http://192.168.0.87:8080/job/parallel-test/4/;
- JOB_NAME:本次构建的项目名称;
- NODE_NAME:当前构建节点的名称;
- JENKINS_URL:Jenkins 完整的 URL,需要在Manage Jenkins—System中的Jenkins URL中设置,如果在你配置的时候发现已经有了,但是在环境变量中没有该变量,则重新保存下配置即可;
- WORKSPACE:执行构建的工作目录。
上述变量会保存在一个 Map 中,可以使用 env.BUILD_ID 或 env.JENKINS_URL 引用某个 内置变量:
1 | pipeline { |
4.2 凭证的管理
4.2.1用户名密码
本示例用来演示 credentials 账号密码的使用,比如使用一个公用账户访问 Bitbucket、GitLab、 Harbor 等,此时可以使用 Jenkins 用户名密码类型的凭证进行管理。
比如添加一个用于访问 Harbor 的凭证:【Manage Jenkins】-【Credentials】-【global】-【Add credentials】
创建成功后如下图所示:
接下来可以使用访问获取凭证的值,HARBOR_ACCOUNT 为接收的变量名,可以自定义:
1 | environment { |
上述的配置会自动生成 3 个环境变量:
HARBOR_ACCOUNT : 包 含 一 个 以 冒 号 分 隔 的 用 户 名 和 密 码 , 格 式 为 username:password
HARBOR_ACCOUNT_USR:仅包含用户名的附加变量;
HARBOR_ACCOUNT_PSW:仅包含密码的附加变量。
此时可以用如下方式获取变量:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19pipeline {
agent any
environment {
HARBOR_ACCOUNT = credentials('HARBOR_ISER_PASSWORD')
}
stages {
stage('echo harbor_credentials') {
steps {
echo """
HARBOR_ACCOUNT: $HARBOR_ACCOUNT
HARBOR_ACCOUNT_USR: $HARBOR_ACCOUNT_USR
HARBOR_ACCOUNT_PSW: $HARBOR_ACCOUNT_PSW
"""
}
}
}
}
4.2.2加密文件
需要加密保存的文件,也可以使用 credential,比如链接到 Kubernetes 集群的kubeconfig 文件等。
首先创建 Secret file 文本形式的凭证:
| 选项名称 | 含义解析 | 建议填写内容 |
|---|---|---|
| Kind (类型) | 凭据的种类。 | 如果你打算上传 kubeconfig 文件,保持 Secret file 即可。 |
| Scope (范围) | 凭据的可用范围。 | 默认为 Global(全局),这意味着 Jenkins 中的所有项目和节点都可以使用此凭据。通常保持默认即可。 |
| File (文件) | 核心部分,即凭据实体。 | 点击 **选择文件 (Choose File)**,上传你本地的 kubeconfig 文件(通常位于 ~/.kube/config)。这个文件包含了连接集群所需的 API 地址和证书。 |
| ID | Jenkins 内部调用此凭据的唯一标识符。 | 非常重要! 建议起一个有意义的名字,例如 STUDT_CLUSTER_CONF。在 Jenkins Pipeline 代码中,你会通过这个 ID 来引用它。 |
| Description | 对该凭据的补充说明。 | 方便后续维护。例如:“学习环境k8s集群访问凭据”。 |
接下来就可以在 Pipeline 中引用该文件:
1 | pipeline { |
更多其它类型的凭证可以参考:http://www.jenkins.io/doc/book/pipeline/jenkinsfile/#handling-credentials














