Jenkins声明式Pipeline语法

Jenkins声明式 Pipeline 语法

声明式流水线必须包含在一个 Pipeline 块中,比如以下是一个 Pipeline 块的格式:

1
2
3
pipeline {
/* insert Declarative Pipeline here */
}

在声明式流水线中有效的基本语句和表达式遵循与 Groovy 的语法同样的规则,但有以下例外:

  • 流水线顶层必须是一个 block,即 pipeline{};

  • 分隔符可以不需要分号,但是每条语句都必须在自己的行上;

  • 块只能由 SectionsDirectivesStepsassignment statements 组成;

  • 属性引用语句被当做是无参数的方法调用,比如 input 会被当做 input()。

1.Sections常用指令

声明式流水线中的 Sections 不是一个关键字或指令,而是包含一个或多个 Agent、Stages、post、Directives 和 Steps 的代码区域块。

1.1Agent语法

Agent 表示整个流水线或特定阶段中的步骤和命令执行的位置,该部分必须在 pipeline 块的顶层被定义,也可以在 stage 中再次定义,但是 stage 级别是可选的。

  • any:在任何可用的代理上执行流水线,配置语法:

    1
    2
    3
    pipeline {
    agent any
    }
  • none:表示该 Pipeline 脚本没有全局的 agent 配置。当顶层的 agent 配置为 none 时,每个 stage 部分都需要包含它自己的 agent。配置语法:

    1
    2
    3
    4
    5
    6
    7
    8
    pipeline {
    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
    8
    pipeline {
    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
    8
    agent {
    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
    7
    agent{
    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
    30
    agent {
    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
2
3
4
5
6
7
8
9
10
11
Jenkinsfile (Declarative Pipeline) // 可以不要此行
pipeline {
agent { docker 'maven:3-alpine' }
stages {
stage('Example Build') {
steps {
sh 'mvn -B clean verify'
}
}
}
}

示例 2:本示例在流水线顶层将 agent 定义为 none,那么此时 stage 部分就需要必须包含它自己的 agent 部分。在 stage(‘Example Build’)部分使用 maven:3-alpine 执行该阶段步骤,在 stage(‘Example Test’)部分使用 openjdk:8-jre 执行该阶段步骤。此时 Pipeline 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Jenkinsfile (Declarative Pipeline) // 可以不要此行
pipeline {
agent none
stages {
stage('Example Build') {
agent { docker 'maven:3-alpine' }
steps {
echo 'Hello, Maven' sh 'mvn --version'
}
}
stage('Example Test') {
agent { docker 'openjdk:8-jre' }
steps {
echo 'Hello, JDK' sh 'java -version'
}
}
}
}

示例 3:上述的示例也可以用基于 Kubernetes 的 agent 实现。比如定义具有三个容器的 Pod,分别为 jnlp (负责和Jenkins Master 通信)、build(负责执行构建命令)、kubectl(负责执行Kubernetes相关命令),在steps中可以通过containers字段,选择在某个容器执行命令:

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
pipeline { 
agent {
kubernetes {
cloud 'kubernetes-default'
slaveConnectTimeout 1200
yaml '''
apiVersion: v1
kind: Pod
spec:
containers:
- args: [\'$(JENKINS_SECRET)\', \'$(JENKINS_NAME)\']
image: 'registry.cn-beijing.aliyuncs.com/citools/jnlp:alpine'
name: jnlp
imagePullPolicy: IfNotPresent
- command:
-"cat"
image: "registry.cn-beijing.aliyuncs.com/citools/maven:3.5.3"
imagePullPolicy: "IfNotPresent"
name: "build"
tty: true
- command:
-"cat"
image: "registry.cn-beijing.aliyuncs.com/citools/kubectl:self-1.17"
imagePullPolicy: "IfNotPresent"
name: "kubectl"
tty: true
'''
}
}
stages {
stage('Building') {
steps {
container(name: 'build') {
sh """
mvm clean install
"""
}

}
}
stage('Deploy') {
steps {
container(name: 'kubectl') {
sh """
kubectl get node
"""
}

}
}
}
}

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Jenkinsfile (Declarative Pipeline) // 可以不写该行
pipeline {
agent any
stages {
stage('Example') {
steps {
echo 'Hello World'
}
}
}
post {
always {
echo 'I will always say Hello again!'
}
}
}

也可以将 post 写在 stage中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
pipeline {
agent any
stages {
stage('Test') {
steps {
sh 'EXECUTE_TEST_COMMAND'
}
post {
failure {
echo "Pipeline Testing failure..."
}
}
}
}
}

1.4Stages语法

Stages 包含一个或多个 stage 指令,同时可以在 stage 中的 steps 块中定义真正执行的指令。比如创建一个流水线,stages 包含一个名为 Example 的 stage,该 stage 执行 echo ‘Hello World’

命令输出 Hello World 字符串:

1
2
3
4
5
6
7
8
9
10
11
Jenkinsfile (Declarative Pipeline) 
pipeline {
agent any
stages {
stage('Example') {
steps {
echo 'Hello World ${env.BUILD_ID}' #这里需要注意,如果需要引用变量必须使用双引号""
}
}
}
}

1.5Steps语法

Steps 部分在给定的 stage 指令中执行的一个或多个步骤,比如在 steps 定义执行一条 shell 命令:

1
2
3
4
5
6
7
8
9
10
11
Jenkinsfile (Declarative Pipeline) 
pipeline {
agent any
stages {
stage('Example') {
steps {
echo 'Hello World'
}
}
}
}

或者是使用 sh 字段执行多条指令,多条指令用三个双引号引起来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Jenkinsfile (Declarative Pipeline) 
pipeline {
agent any
stages {
stage('Example') {
steps {
sh """
echo 'Hello World'
mvn clean install
"""
}
}
}
}

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Jenkinsfile (Declarative Pipeline) 
pipeline {
agent any
environment { // Pipeline 中定义,属于全局变量
CC = 'clang'
}
stages {
stage('Example') {
environment { // 定义在 stage 中,属于局部变量
AN_ACCESS_KEY = credentials('my-prefined-secret-text')
}
steps {
sh 'printenv'
}
}
}
}

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
pipeline {
agent any
options {
timeout(time: 1, unit: 'HOURS') //全局超时时间,整个流水线如果1小时内没结束会被强制终止
timestamps() //使用该指令需要安装Timestamper插件
}
stages {
stage('Example') {
steps {
echo 'Hello World'
}
}
}
}

Option 除了写在Pipeline 顶层,还可以写在 stage 中,但是写在 stage 中的option 仅支持 retry、 timeout、timestamps,或者是和 stage 相关的声明式选项,比如 skipDefaultCheckout。处于 stage级别的options 写法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
pipeline {
agent any
stages {
stage('Example') {
options {
timeout(time: 1, unit: 'HOURS')//特定阶段的超时时间设置,1小时内没完成强制终止
}
steps {
echo 'Hello World'
}
}
}
}

进阶用法:结合 retry

你可能希望在超时后自动重试,可以嵌套使用:

1
2
3
4
5
6
7
8
9
10
stage('Health Check') {
steps {
// 如果 3 分钟没成功,就重试,最多重试 3 次
retry(3) {
timeout(time: 3, unit: 'MINUTES') {
sh './check_service_status.sh'
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
timeout 指令通常包含两个主要字段:
1. time (数值)
含义:允许运行的最大时间量。
数据类型:整型(Integer)。
注意:必须配合 unit 使用,否则 Jenkins 默认单位是分钟(但在声明式脚本中建议显式指定)。
2. unit (单位)
含义:指定 time 字段的时间单位。
可选值:
NANOSECONDS (纳秒)
MICROSECONDS (微秒)
MILLISECONDS (毫秒)
SECONDS (秒)
MINUTES (分钟) —— 这是最常用的默认值
HOURS (小时)
DAYS (天)

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
pipeline {
agent any
parameters {
string(name: 'PERSON', defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?')

text(name: 'BIOGRAPHY', defaultValue: '', description: 'Enter some information about the person')

booleanParam(name: 'TOGGLE', defaultValue: true, description: 'Toggle this value')

choice(name: 'CHOICE', choices: ['One', 'Two', 'Three'], description: 'Pick something')

password(name: 'PASSWORD', defaultValue: 'SECRET', description: 'Enter a password')
}
stages {
stage('Example') {
steps {
echo "Hello ${params.PERSON}"
echo "Biography: ${params.BIOGRAPHY}"
echo "Toggle: ${params.TOGGLE}"
echo "Choice: ${params.CHOICE}"
echo "Password: ${params.PASSWORD}"
}
}
}
}

pipeline生产配置案例:

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
pipeline {
agent any

// 1. 定义参数化构建
parameters {
choice(
name: 'DEPLOY_ENV',
choices: ['development', 'staging', 'production'],
description: '请选择部署目标环境(生产环境需双重确认)'
)

string(
name: 'BRANCH_OR_TAG',
defaultValue: 'main',
description: '请输入要部署的 Git 分支、Tag 或 Commit ID'
)

booleanParam(
name: 'SKIP_SCAN',
defaultValue: false,
description: '是否跳过安全漏洞扫描?'
)

password(
name: 'DEPLOY_TOKEN',
defaultValue: '',
description: '请输入临时部署令牌(如适用)'
)
}

stages {
// 阶段一:参数检查与预览
stage('参数预览') {
steps {
echo "--- 部署任务启动 ---"
echo "目标环境: ${params.DEPLOY_ENV}"
echo "代码版本: ${params.BRANCH_OR_TAG}"
echo "是否跳过扫描: ${params.SKIP_SCAN}"
}
}

// 阶段二:安全扫描(公共逻辑)
stage('镜像安全扫描') {
when {
expression { return params.SKIP_SCAN == false }
}
steps {
echo "正在执行 Trivy 镜像安全扫描..."
// sh "trivy image my-app:${params.BRANCH_OR_TAG}"
}
}

// 阶段三:生产环境特有的二次确认
stage('生产环境二次确认') {
when {
environment name: 'DEPLOY_ENV', value: 'production'
}
steps {
input message: "当前选择为【生产环境】,确定要发布版本 ${params.BRANCH_OR_TAG} 吗?", ok: "确认发布"
}
}

// 阶段四:部署到开发环境(仅在选择 development 时运行)
stage('部署到开发环境') {
when {
environment name: 'DEPLOY_ENV', value: 'development'
}
steps {
echo "--- 开始部署至开发环境 ---"
// 使用开发环境的配置文件
sh "kubectl apply -f k8s/dev-deployment.yaml"
}
}

// 阶段五:部署到预发布环境(示例补充)
stage('部署到测试/预发布环境') {
when {
environment name: 'DEPLOY_ENV', value: 'staging'
}
steps {
echo "--- 开始部署至 Staging 环境 ---"
sh "kubectl apply -f k8s/staging-deployment.yaml"
}
}

// 阶段六:部署到生产环境(仅在选择 production 时运行)
stage('部署到生产环境') {
when {
environment name: 'DEPLOY_ENV', value: 'production'
}
steps {
echo "--- 开始部署至生产环境 ---"
// 生产环境通常需要特殊的权限配置文件或证书
sh "kubectl apply -f k8s/prod-deployment.yaml --kubeconfig=/root/.kube/prod-config"
}
}
}

post {
always {
echo "流水线运行结束。"
}
success {
echo "版本 ${params.BRANCH_OR_TAG} 已成功部署至 ${params.DEPLOY_ENV}"
}
failure {
echo "部署失败,请检查日志或网络连接。"
}
}
}

2.4Triggers自动触发流水线

在 Pipeline 中可以用 triggers 实现自动触发流水线执行任务,可以通过 WebhookCronpollSCMupstream 等方式触发流水线。

假如某个流水线构建的时间比较长,或者某个流水线需要定期在某个时间段执行构建,可以使用 cron 配置触发器,比如每5分钟执行一次:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#cron字段是基于时间触发构建
pipeline {
agent any
triggers {
cron('H/5 * * * *')
}
stages {
stage('Run Every 5 Minutes') {
steps {
echo 'This task runs every 5 minutes'
}
}
}
}

注意:H 的意思不是HOURS 的意思,而是 Hash 的缩写。主要为了解决多个流水线在同一时间同时运行带来的系统负载压力。H(哈希值)是Jenkins特有的语法,用于在多个任务之间分散负载。如果你希望任务在确切的五分钟间隔执行,可以使用*/5 * * * *,但这可能会导致所有任务在同一分钟开始执行,增加负载。

使用 cron 字段可以定期执行流水线,如果代码有变动想要重新触发流水线,可以使用 pollSCM字段:

1
2
3
4
5
6
7
8
9
10
11
12
13
#pollSCM是基于代码仓库是否发生变化来触发构建,如果代码有变化就会触发构建,后面的时间是多久对代码仓库进行检查
pipeline {
agent any triggers {
pollSCM('H/5 * * * *') #该参数的意思是每5分钟对代码仓库进行一次检查,如果代码有变更才会触发构建
}
stages {
stage('Example') {
steps {
echo 'Hello World'
}
}
}
}

Upstream 可以根据上游 job 的执行结果决定是否触发该流水线。比如当 job1 或 job2 执行成功时触发该流水线:

1
2
3
4
5
6
7
8
9
10
11
12
13
pipeline {
agent any
triggers {
upstream(upstreamProjects: 'job1,job2', threshold: hudson.model.Result.SUCCESS)
}
stages {
stage('Example') {
steps {
echo 'Hello World'
}
}
}
}
  • upstream:这是一个触发器类型,表示当前Pipeline将被上游项目(即upstreamProjects中列出的项目)的构建结果所触发。
  • upstreamProjects:这是一个参数,指定了哪些上游项目可以触发当前Pipeline的构建。在这个例子中,job1job2是上游项目。
  • 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
pipeline {
agent any
stages {
stage('Example') {
input {
message "还继续么?"
ok "继续"
submitter "alice,bob"
parameters {
string(name: 'PERSON', defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?')
}
}
steps {
echo "Hello, ${PERSON}, nice to meet you."
}
}
}
}

简单案例:主要关注 stage(‘Manual Approval for Production’) 部分的input定义和调用

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
pipeline {
agent any
stages {
stage('Build') {
steps {
// 构建步骤
sh 'mvn clean package'
}
}
stage('Deploy to Staging') {
steps {
// 部署到测试环境
sh 'mvn deploy -Pstaging'
}
}
stage('Manual Approval for Production') {
input {
message "是否确认部署到生产环境?"
ok "确认部署"
submitter "alice,bob,charlie"
parameters {
choice(name: 'DEPLOY_ENV', choices: ['us-east-1', 'us-west-2', 'eu-west-1'], description: '选择部署的区域')
booleanParam(name: 'NOTIFY_TEAM', defaultValue: true, description: '是否通知团队成员?')
}
}
steps {
script {
if (env.NOTIFY_TEAM == 'true') {
// 发送通知给团队成员
emailext (
subject: "即将部署到生产环境",
body: "即将在 ${env.DEPLOY_ENV} 区域部署到生产环境,请注意。",
to: "team@example.com"
)
}
// 部署到生产环境
sh "mvn deploy -Pproduction -Dregion=${env.DEPLOY_ENV}"
}
}
}
stage('Post-Deployment') {
steps {
// 部署后步骤,如运行健康检查或通知
sh 'mvn verify -Pproduction'
echo "部署到生产环境完成"
}
}
}
}

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
pipeline {
agent any
stages {
stage('Example Build') {
steps {
echo 'Hello World'
}
}
stage('Example Deploy') {
when {
branch 'production'
}
steps {
echo 'Deploying'
}
}
}
}

也可以同时配置多个条件,比如分支是 pro,而且 DEPLOY_TO 变量的值为 production时,才执行 Example Deploy:

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
pipeline {
agent any
environment { // Pipeline 中定义,属于全局变量
DEPLOY_TO = 'production'
}
parameters {
choice(name: 'branch', choices: ['dev', 'uat', 'pro'], description: '请选择要执行的分支')
}
stages {
stage('Example Build') {
steps {
echo 'Hello World'
}
}
stage('Example Deploy') {
when {
expression {
#多个条件都要满足才会执行下面的steps步骤
return params.branch == 'pro' && env.DEPLOY_TO == 'production'
}
}
steps {
echo 'Deploying'
}
}
}
}

也可以使用 anyOf 进行匹配其中一个条件即可,比如分支为 pro,DEPLOY_TO 为production 或staging 时执行 Deploy:

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
30
31
32
33
34
35
36
37
pipeline {
agent any
parameters {
// 1. 让分支变成可选
choice(name: 'BRANCH_NAME', choices: ['dev', 'uat', 'pro'], description: '请选择要执行的分支')

// 2. 让环境也变成可选,去掉之前固定的 environment 块
choice(name: 'DEPLOY_ENV', choices: ['production', 'staging'], description: '选择部署环境')
}

stages {
stage('Example Build') {
steps {
echo "构建中... 分支: ${params.BRANCH_NAME}, 环境: ${params.DEPLOY_ENV}"
}
}

stage('Example Deploy') {
when {
allOf {
// 只有当分支选择为 'pro' 时,必须满足
expression { params.BRANCH_NAME == 'pro' }

// 且环境是 production 或 staging 之一(其实参数里已经限制了,但这里可以做逻辑加固)
anyOf {
expression { params.DEPLOY_ENV == 'production' }
expression { params.DEPLOY_ENV == 'staging' }
}
}
}
steps {
// 使用 params.DEPLOY_ENV 获取用户选择的值
echo "正在部署至: ${params.DEPLOY_ENV}"
}
}
}
}

也可以使用 expression 进行正则匹配,比如当 BRANCH_NAME 为 dev 或着uat(满足其一),并且 DEPLOY_TO 为production 或 staging(满足其一) 时才会执行 Example Deploy:

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
30
31
32
33
34
pipeline {
agent any
parameters {
// 1. 让分支变成可选
choice(name: 'BRANCH_NAME', choices: ['dev', 'uat', 'pro'], description: '请选择要执行的分支')

// 2. 让环境也变成可选,去掉之前固定的 environment 块
choice(name: 'DEPLOY_ENV', choices: ['production', 'staging'], description: '选择部署环境')
}

stages {
stage('Example Build') {
steps {
echo "构建中... 分支: ${params.BRANCH_NAME}, 环境: ${params.DEPLOY_ENV}"
}
}

stage('Example Deploy') {
when {
expression { BRANCH_NAME ==~ /(dev|uat)/ }

// 且环境是 production 或 staging 之一(其实参数里已经限制了,但这里可以做逻辑加固)
anyOf {
expression { params.DEPLOY_ENV == 'production' }
expression { params.DEPLOY_ENV == 'staging' }
}
}
steps {
// 使用 params.DEPLOY_ENV 获取用户选择的值
echo "正在部署至: ${params.DEPLOY_ENV}"
}
}
}
}

默认情况下,如果定义了某个 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
pipeline {
agent none
stages {
stage('Example Build') {
steps {
echo 'Hello World'
}
}
stage('Example Deploy') {
agent {
label "some-label"
}
when {
beforeAgent true
branch 'production'
}
steps {
echo 'Deploying'
}
}
}
}

配置一个 beforeInput 示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
pipeline {
agent none
stages {
stage('Example Build') {
steps {
echo 'Hello World'
}
}
stage('Example Deploy') {
when {
beforeInput true
branch 'production'
}
input {
message "Deploy to production?"
id "simple-input"
}
steps {
echo 'Deploying'
}
}
}
}

配置一个 beforeOptions 示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
pipeline {
agent none
stages {
stage('Example Build') {
steps {
echo 'Hello World'
}
}
stage('Example Deploy') {
when {
beforeOptions true
branch 'testing'
}
options {
lock label: 'testing-deploy-envs',
quantity: 1,
variable:'deployEnv'
}
steps {
echo "Deploying to ${deployEnv}"
}
}
}
}

3.Parallel并发指令

Jenkins 声明式流水线(Declarative Pipeline) 中,parallel 用于让多个 Stage 或步骤同时执行,核心目的是 缩短流水线执行时间。并不是“某些固定任务才能并行”,而是 只要任务之间没有依赖关系,都可以并行执行

比如对分支 A、B、 C 进行并行处理:

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
pipeline {
agent any
stages {
stage('Non-Parallel Stage') {
steps {
echo 'This stage will be executed first.'
}
}
stage('Parallel Stage') {
when {
branch 'master'
}
failFast true //该参数意味着如果任何并行阶段失败,整个并行阶段将立即停止,不会等待其他并行阶段完成。
parallel {
stage('Branch A') {
agent {
label "for-branch-a"
}
steps {
echo "On Branch A"
}
}
stage('Branch B') {
agent {
label "for-branch-b"
}
steps {
echo "On Branch B"
}
}
stage('Branch C') {
agent {
label "for-branch-c"
}
stages {
stage('Nested 1') {
steps {
echo "In stage Nested 1 within Branch C"
}
}
stage('Nested 2') {
steps {
echo "In stage Nested 2 within Branch C"
}
}
}
}
}
}
}
}

设置failFast 为true 表示并行流水线中任意一个stage 出现错误,其它 stage 也会立即终止。也可以通过options 配置在全局:

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
pipeline {
agent any
options {
parallelsAlwaysFailFast() //建议配置该参数,当任意stage 出现错误,立即终止整个任务
}
stages {
stage('Non-Parallel Stage') {
steps {
echo 'This stage will be executed first.'
}
}
stage('Parallel Stage') {
when {
branch 'master'
}
parallel {
stage('Branch A') {
agent {
label "for-branch-a"
}
steps {
echo "On Branch A"
}
}
stage('Branch B') {
agent {
label "for-branch-b"
}
steps {
echo "On Branch B"
}
}
stage('Branch C') {
agent {
label "for-branch-c"
}
stages {
stage('Nested 1') {
steps {
echo "In stage Nested 1 within Branch C"
}
}
stage('Nested 2') {
steps {
echo "In stage Nested 2 within Branch C"
}
}
}
}
}
}
}
}

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
2
3
4
5
6
7
8
9
10
11
12
13
pipeline {
agent any

stages {
stage('Hello') {
steps {
echo "Running ${env.BUILD_ID} on ${env.JENKINS_URL}" //输出单个变量${env.BUILD_ID}
sh 'printenv' //打印所有内置变量
}
}
}
}

4.2 凭证的管理

4.2.1用户名密码

本示例用来演示 credentials 账号密码的使用,比如使用一个公用账户访问 Bitbucket、GitLab、 Harbor 等,此时可以使用 Jenkins 用户名密码类型的凭证进行管理。

比如添加一个用于访问 Harbor 的凭证:【Manage Jenkins】-【Credentials】-【global】-【Add credentials】


创建成功后如下图所示:

接下来可以使用访问获取凭证的值,HARBOR_ACCOUNT 为接收的变量名,可以自定义:

1
2
3
environment { 
HARBOR_ACCOUNT = credentials('HARBOR_ISER_PASSWORD')
}

上述的配置会自动生成 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
    19
    pipeline {
    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
2
3
4
5
6
7
8
9
10
11
12
13
pipeline {
agent any
environment {
MY_KUBECONFIG = credentials('STUDT_CLUSTER_CONF') //STUDT_CLUSTER_CONF是创建凭证时指定的ID
}
stages {
stage('Example stage 1') {
steps {
sh "cat $MY_KUBECONFIG"
}
}
}
}

更多其它类型的凭证可以参考:http://www.jenkins.io/doc/book/pipeline/jenkinsfile/#handling-credentials