Jenkinsfile 的使用
Jenkins Pipeline 支持两种语法,即声明式和脚本式,这两种语法都支持构建持续交付流水线。并且都可以用来在 Web UI 或 Jenkinsfile 中定义流水线,不过通常将 Jenkinsfile 放置于代码仓库中(当然也可以放在单独的代码仓库中进行管理)。
创建一个 Jenkinsfile 并将其放置于代码仓库中,有以下几个好处:
- 方便对流水线上的代码进行复查/迭代;
- 对管道进行审计跟踪;
- 流水线真正的源代码能够被项目的多个成员查看和编辑;
环境变量
静态变量
Jenkins 有许多内置变量可以直接在 Jenkinsfile 中使用,可以通过 JENKINS_URL/pipeline-syntax/globals#env
获取完整列表。
目前比较常用的环境变量如下:
- BUILD_ID: 当前构建的ID,与 Jenkins 版本1.597+中的 BUILD_NUMBER 完全相同;
- BUILD_NUMBER: 当前构建的ID,和BUILD_ID一致;
- BUILD_TAG: 用来标识构建的版本号,格式为:
jenkins-${JOB_NAME}-${BUILD_NUMBER}
,可以对产物进行命名,比如生产的 jar 包名字、镜像的 TAG 等; - BUILD_URL: 本次构建的完整 URL,比如:
http://buildserver/jenkins/job/MyJobName/17/
; - JOB_NAME: 本次构建的项目名称;
- NODE_NAME: 当前构建节点的名称;
- JENKINS_URL: Jenkins完整的URL,需要在
SystemConfiguration
设置; - WORKSPACE: 执行构建的工作目录。
上述变量会保存在一个 Map 中,可以使用
env.BUILD_ID
或env.JENKINS_URL
等方式引用某个内置变量,如下:1
2
3
4
5
6
7
8
9
10pipeline {
agent any
stages {
stage('Example') {
steps {
echo "Running ${env.BUILD_ID} on ${env.JENKINS_URL}"
}
}
}
}对应的脚本式流水线如下
1
2
3node {
echo "Running ${env.BUILD_ID} on ${env.JENKINS_URL}"
}除了上述默认的环境变量,也可以手动配置一些环境变量,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16pipeline {
agent any
environment {
CC = 'clang'
}
stages {
stage('Example') {
environment {
DEBUG_FLAGS = '-g'
}
steps {
sh 'printenv'
}
}
}
}上述配置了两个环境变量,一个 CC 值为 clang,另一个是 DEBUG_FLAGS 值为
-g
。但是两者定义的位置不一样,CC 位于顶层,适用于整个流水线,而 DEBUG_FLAGS 位于 stage 中,只 适用于当前 stage
动态变量
动态变量是根据某个指令的结果进行动态赋值,变量的值根据指令的执行结果而不同。
如下所示
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
31pipeline {
agent any
environment {
// 使用 returnStdout
CC = """
${sh(
returnStdout: true,
script: 'echo "clang"'
)
}
"""
// 使用 returnStatus
EXIT_STATUS = """
${sh(
returnStatus: true,
script: 'exit 1'
)
}
"""
}
stages {
stage('Example') {
environment {
DEBUG_FLAGS = '-g'
}
steps {
sh 'printenv'
}
}
}
}- returnStdout: 将命令的执行结果赋值给变量,比如上述的命令返回的是 clang,此时 CC 的值为 “clang”。注意后面多了一个空格,可以用
.trim()
将其删除; - returnStatus: 将命令的执行状态赋值给变量,比如上述命令的执行状态为 1,此时 EXIT_STATUS 的值为 1。
- returnStdout: 将命令的执行结果赋值给变量,比如上述的命令返回的是 clang,此时 CC 的值为 “clang”。注意后面多了一个空格,可以用
凭证管理
Jenkins 的声明式流水线语法有一个 credentials()
函数,它支持 secret text(加密文本)、username 和 password(用户名和密码)以及 secret file(加密文件)等。接下来看一下一些常用的凭证处理方法。
加密文本
示例1: 本示例演示将两个 Secret 文本凭证分配给单独的环境变量来访问 Amazon Web 服务,需要提前创建这两个文件的 credentials,Jenkinsfile 文件的内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21pipeline {
agent {
// Define agent details here
}
environment {
AWS_ACCESS_KEY_ID = credentials('jenkins-aws-secret-key-id')
AWS_SECRET_ACCESS_KEY = credentials('jenkins-aws-secret-access-key')
}
stages {
stage('Example stage 1') {
steps {
echo 'Example Stage 1...'
}
}
stage('Example stage 2') {
steps {
echo 'Example Stage 2...'
}
}
}
}说明:
上述示例定义了两个全局变量AWS_ACCESS_KEY_ID
和AWS_SECRET_ACCESS_KEY
, 这两个变量引用的是 credentials 的两个加密文本,并且这两个变量均可以在 stages 通过$AWS_SECRET_ACCESS_KEY
和$AWS_ACCESS_KEY_ID
直接引用,。注意: 如果在 steps 中使用
echo "$AWS_ACCESS_KEY_ID"
,此时返回的是 ****,加密内容不 会被显示出来。
用户名密码
示例1: 本示例用来演示 credentials 账号密码的使用,比如使用一个公用账户访问 Bitbucket、GitLab、Harbor 等。假设已经配置完成了用户名密码形式的 credentials,凭证 ID 为 docker-register-credentials。可以使用以下方式设置凭证环境变量 DOCKER_REGISTRY_CREDS,名称可以自定义
1
2
3
4
5
6pipeline {
agent any
environment {
DOCKER_REGISTRY_CREDS = credentials('docker-register-credentials')
}
}上述的配置会自动生成 3 个环境变量:
- DOCKER_REGISTRY_CREDS: 包含一个以冒号分隔的用户名和密码,格式为 username:password;
- DOCKER_REGISTRY_CREDS_USR: 仅包含用户名的附加变量;
- DOCKER_REGISTRY_CREDS_PSW: 仅包含密码的附加变量。
此时,调用用户名密码的 Jenkinsfile 如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15pipeline {
agent any
environment {
DOCKER_REGISTRY_CREDS = credentials('docker-register-credentials')
}
stages {
stage('Example stage 1') {
steps {
echo "Map: $DOCKER_REGISTRY_CREDS"
echo "username: $DOCKER_REGISTRY_CREDS_USR"
echo "password: $DOCKER_REGISTRY_CREDS_PSW"
}
}
}
}
加密文件
需要加密保存的文件,也可以使用 credential,比如链接到 Kubernetes 集群的kubeconfig文 件等。
示例1: 假设已经配置好了一个 kubeconfig 文件,此时可以在 Pipeline 中引用该文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21pipeline {
agent any
environment {
DOCKER_REGISTRY_CREDS = credentials('docker-register-credentials')
MY_KUBERNETES = credentials('prod-kubernetes')
}
stages {
stage('Example stage 1') {
steps {
echo "Map: $DOCKER_REGISTRY_CREDS"
echo "username: $DOCKER_REGISTRY_CREDS_USR"
echo "password: $DOCKER_REGISTRY_CREDS_PSW"
}
}
stage('Test Kubeconfig') {
steps {
sh("kubectl --kubeconfig $MY_KUBERNETES get pods")
}
}
}
}
更多其它类型的凭证可以参考: handling-credentials
参数处理
声明式流水线支持很多开箱即用的参数,可以让流水线接收不同的参数以达到不同的构建 效果,在 Directives 小节讲解的参数均可用在流水线中。
在 Jenkinsfile 中指定的 parameters 会在 Jenkins Web UI 自动生成对应的参数列表,此时可以在 Jenkins 页面点击 Build With Parameters
来指定参数的值,这些参数可以通过 params 变量被成员访问。
假设在 Jenkinsfile 中配置了名为 Greeting 的字符串参数,可以通过
${params.Greeting}
访问 该参数,比如:1
2
3
4
5
6
7
8
9
10
11
12
13pipeline {
agent any
parameters {
string(name: 'Greeting', defaultValue: 'Hello', description: 'How should I greet the world?')
}
stages {
stage('Example') {
steps {
echo "${params.Greeting} World!"
}
}
}
}对应的脚本式流水线如下:
1
2
3
4properties([parameters([string(defaultValue: 'Hello', description: 'How should I greet the world?', name: 'Greeting')])])
node {
echo "${params.Greeting} World!"
}
使用多个代理
流水线允许在 Jenkins 环境中使用多个代理,这有助于更高级的用例,例如跨多个平台执行构建、测试等。
比如,在 Linux 和 Windows 系统的不同 agent 上进行测试:
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
41pipeline {
agent none
stages {
stage('Build') {
agent any
steps {
checkout scm
sh 'make'
stash includes: '**/target/*.jar', name: 'app'
}
}
stage('Test on Linux') {
agent {
label 'linux'
}
steps {
unstash 'app'
sh 'make check'
}
post {
always {
junit '**/target/*.xml'
}
}
}
stage('Test on Windows') {
agent {
label 'windows'
}
steps {
unstash 'app'
bat 'make check'
}
post {
always {
junit '**/target/*.xml'
}
}
}
}
}