3. Jenkins pipeline 语法
3.1 pipeline 组成
Jenkins pipeline 是基于Groovy
语言实现的一种DSL
(领域特定语言),用于描述整条流水线是如何进行的。流水线的主要内容包括源码拉取
、构建
、打包
、部署
、测试
、生成报告
等步骤。
从源码管理仓库到生成测试报告这些过程中,可以根据需要分成若干阶段,而每个阶段仅处理一件事情,而每个阶段也可以通过多个步骤来完成,因此我们可以基于这些阶段和步骤些进行抽象,形成工程化的pipeline,因此一个基本的pipeline示例如下所示:
pipeline{
agent any
stages{
stage("Sample stage"){
steps {
echo "Hi,Surpass.Welcome visit my blog:https://www.cnblogs.com/surpassme/"
}
}
}
}
以上示例详细解释如下所示:
- pipeline:代表整条流水线,包含
整条流水线的逻辑
- agent:指定流水线的
运行位置
流水线的中每个阶段都必须在某个地方(例如物理机、虚拟机或容器)运行,因此可能通过指定 agent部分来指定具体在哪里运行。
- stages:流水线中多个stage的容器。该部分
至少包含一个stage
- stage:表示阶段,代表流水线的阶段,每个阶段必须有名称
- steps:表示阶段中的一个或多个具体步骤的容器
1.steps
至少
包含一个步骤
2.在一个stage中仅有一个steps
以上每一个部分都是必需
的,否则Jenkins都会报错
3.2 pipeline 支持的命令
基本的pipeline结构是无法满足日常现实多变的需求。因此,Jenkins pipeline可以通过各种指令来扩展丰富自己。以下为Jenkins pipeline支持的命令。
3.2.1 environment
environment
主要用于设置环境变量
。可以定义在stage
和pipeline
部分。环境变量可以分为:Jenkins内置变量
和自定义环境变量
。
3.2.1.1 Jenkins 内置环境变量
在执行pipeline时,可以通过env
命令来获取Jenkins的全部内置环境变量,其主要使用方法如下所示:
pipeline {
agent any
stages{
stage("PrintEnviroment"){
steps{
// method A
echo "Running ${env.BUILD_ID} on ${env.JENKINS_URL}"
// method B
echo "Running $env.BUILD_ID on $env.JENKINS_URL"
// method C
echo "Running ${BUILD_ID} on ${JENKINS_URL}"
}
}
}
}
默认情况下,env中的所有环境变量都可以直接在pipeline中使用。因此上面三种方法都可以使用,但
不推荐第三种方法
,因为在出现变量名冲突时,排查问题非常难。
如果需要查看env所有可用的环境变量,可以通过以下方式进行访问。http://jenkins-master-address/pipeline-syntax/globals
。示例如下所示:
Jenkins 内置环境变量如下所示:
以下为日常经常使用到的内置环境变量简介。如下所示:
- BRANCH_NAME
多分支piple 项目支持。可根据不同的分支执行不同的语句。例如当分支为release时,部署到生产环境,分支为test时,部署至测试环境。
- BUILD_NUMBER
构建号,同一个项目中,持续累加的数字。
- BUILD_URL
当前构建的URL地址,点击该URL,可以快速跳转至构建页面
- WORKSPACE
构建的工作空间,为绝对路径
在调试pipeline时,也可以在pipeline 的开始阶段使用以下代码片断,打印所有env的环境变量,来进行排查问题。如下所示:
sh "printenv"
3.2.1.2 自定义环境变量
当内置环境变量无法满足要求时,我们也可以定义自己的环境变量。这个时候就需要使用environment
命令来自定义环境变量。示例如下所示:
pipeline {
agent any
environment{
NAME="Surpass"
AGE="28"
}
stages{
stage("PrintGolbalEnviroment"){
steps{
echo "Global Enviroment is name is ${env.NAME} age is ${env.AGE}"
}
}
stage("PrintLocalEnviroment"){
environment{
CITY="Shanghai"
FROM="Wuhan"
}
steps{
echo "Global Enviroment is name is ${env.NAME} age is ${env.AGE}"
echo "Local Enviroment is city is ${env.CITY} from is ${env.FROM}"
}
}
}
}
environment
可以在pipeline
中定义,属于全局环境变量
,代表整个pipeline均可以使用该环境变量。也可以在stage
中定义,属于局部环境变量
,仅限于该阶段内部有效,外部无法使用。
除了以上几中自定义环境变量,还可以通过script
来定义全局变量
,示例如下所示:
pipeline {
agent any
environment{
NAME="Surpass"
AGE="28"
}
stages{
stage("Set environment by script"){
steps{
script{
env.SURPASS_NAME="Surpass"
env.SURPASS_AGE=28
}
}
}
stage("PrintGolbalEnvironment"){
steps{
echo "Global Enviroment is name is ${env.NAME} age is ${env.AGE}"
}
}
stage("PrintLocalEnvironment"){
environment{
CITY="Shanghai"
FROM="Wuhan"
}
steps{
echo "Global Enviroment is name is ${env.NAME} age is ${env.AGE}"
echo "Local Enviroment is city is ${env.CITY} from is ${env.FROM}"
}
}
stage("PrintSetEnvironment"){
steps{
echo "print global env by script ${env.SURPASS_NAME}"
echo "print global env by script ${env.SURPASS_AGE}"
}
}
}
}
在自定义环境变量,需要注意的地方如下所示:
- 1.环境变量是不能跨pipeline进行访问的,即
不同的pipeline间不能共享环境变量
- 2.如果用户自定义的环境变量与env环境变量重名,则被重命名的环境将被
覆盖
3.2.1.3 自定义全局环境变量
env中的环境变量都是内置的,用户自定义的环境变量是与具体的pipeline相关的。如果需要定义全局并且跨pipeline
自定义环境变量,可以这样设置。
Manage Jenkins->Configure System-> Global properties,勾选 Environment variables,添加对应的环境变量即可。
以上自定义的全局环境变量,会被加入env环境变量列表中,后续使用时可以使用${env.SURPASS_NAME}
和${env.SURPASS_AGE}
来获取。
3.2.2 tools
可定义在pipeline或stage部分。在运行时,会自动下载
并安装指定的工具和加入PATH变量
中。但在agent none时,会失效
基于在线自动安装,受限于网络不可达、网络速度、网络策略等因素,一般还是建议,还是提前下载到本地,然后在Jenkins进行配置好之后,在pipeline中直接使用即可。
3.2.2.1 Go 语言环境搭建
其操作步骤如下所示:
1.下载golang SDK本地
2.在Jenkins 中安装go插件
3.在Jenkins中进行配置
Manage Jenkins->Configure System-> Global Tool Configuration->GO
- 4.编写pipeline 脚本
pipeline{
agent any
tools {
go "go-1.19"
}
stages{
stage("tools demo"){
steps{
sh "go version"
sh "go env"
}
}
}
}
运行结果如下所示:
3.2.2.2 Python 语言环境搭建
Python 环境很容易产生版本冲突和第三方库冲突等问题,因此Python通过会进行工程级别的环境隔离。在Jenkins中,我们可以使用插件Pyenv Pipeline Plugin
(https://plugins.jenkins.io/pyenv-pipeline/)来解决此类问题。其操作步骤如下所示:
- 1.在Jenkins中安装Python/pip/virtualenv
- 2.安装插件Pyenv Pipeline Plugin
- 3.编写pipeline 脚本
pipeline{
agent any
stages{
stage("python virtual env demo"){
steps{
withPythonEnv("/usr/local/bin/python3") {
// Uses the specific python3.5 executable located in /usr/bin
sh "python3 --version"
sh "python3 -c \"print('hello,Surpass')\""
}
}
}
}
}
运行结果如下所示:
3.2.2.3 利用作用域实现多版本编译
在实际项目中,同一份源码可能会存在多个版本的编译构建等。tools 除了支持pipeline域
也支持stage域
。示例如下所示:
pipeline{
agent any
stages{
stage("build with go 1.19"){
tools {
go "go-1.15"
}
steps{
echo "use go 1.15 build"
}
}
stage("build with go 1.19"){
tools {
go "go-1.19"
}
steps{
echo "use go 1.19 build"
}
}
}
}
3.2.3 input
input 命令可以实现pipeline中的交互操作
。利用input命令,我们可以一些简单的场景。
- 实现简易的审核流程
在部署环境前,由相应负责人员进行确认
- 排查定位问题
因为pipeline在遇到input命令时,会暂停执行。因此,我们可以利用这个特性,使运行某个阶段前,暂停执行pipeline
3.2.3.1 常用参数
input 命令的常用参数如下所示:
- message
该参数为必选参数
,input命令的消息提示框消息。
- id
该参数为可选参数
, input命令标识符,默认为stage的名称
- submitter
该参数为可选参数
,类型为字符串类型
,可以进行操作的用户ID或用户组名称,使用,
分隔,在,
左右不允许有空格
。可以用来做权限控制。
- submitterParameter
该参数为可选参数
,类型为字符串类型
,保存input命令的实际操作者的用户名的变量名
- ok
该参数为可选参数
,自定义确定按钮的文本
- parameters
该参数为可选参数
,提供参数列表供input命令使用。
3.2.3.2 简易用法
比如我们现在实现第一种简易的审核流程。示例脚本如下所示:
pipeline{
agent any
stages{
stage("input simple use"){
steps{
input message:"Confirm or Cancle ?"
}
}
}
}
当执行到input simple use
阶段时,pipeline会暂停,当鼠标移动到该阶段虚线视图上时,会出现一个浮层 ,以供选择。示意图如下所示:
3.2.3.3 复杂用法
示例脚本如下所示:
pipeline{
agent any
environment {
DEPLOY_ENV=""
}
stages{
stage("choose deploy nodes"){
steps{
script{
DEPLOY_ENV=input(
message: "准备部署到哪个节点?",
parameters:[choice(
name:'chooseNode',
choices:["node-1","node-2","node-3"],
description:"选择部署节点")
],
ok:"确定",
submitter:"admin,Surpass",
submitterParameter:"approvers"
)
}
}
}
stage("deply"){
steps{
echo "操作人员:${DEPLOY_ENV['approvers']}"
echo "部署节点:${DEPLOY_ENV['chooseNode']}"
}
}
}
}
因为input返回的值需要跨阶段,因此需要将input的返回值定义为全局变量。
input 命令返回值类型取决于返回的值个数
,详情如下所示:
- 仅返回一个值,返回值类型就是这个值的类型
- 返回多个值,则返回值类型为Map类型
运行结果如下所示:
3.2.4 options
用于配置pipeline本身
的选项,可以定义在pipeline
和stage
中。常用的配置项如下所示:
- buildDiscarder
用于配置保存最近历史构建记录的数量。示例如下所示:
options{
buildDiscarder(logRotator(numToKeepStr:'5'))
}
此选项只能在pipeline下的 options 中使用
- checkoutToSubdirectory
Jenkins 从版本控制库中拉取源码时,默认会存放到工作空间目录中,此选项可以指定检出到工作空间的子目录中,示例如下所示:
options{
checkoutToSubdirectory('subdir')
}
- disableConcurrentBuilds
同一个pipeline,Jenkins默认是可以同时执行的,而此选项则是禁止多个pipeline并行执行
,示例如下所示:
options {
disableConcurrentBuilds()
}
- retry
当发生失败时进行重试,可以指定整个pipeline的重试次数。示例如下所示:
options{
retry(3)
}
需要注意的是这里的重试次数是指总次数,即包含第一次失败。当使用retry选项时,options可以放在stage中
- timeout
若pipeline执行时间过长,超出了设置的超时时间之后,则Jenkins将中止pipeline。示例如下所示:
options{
timeout(time:1,unit:'SECONDS')
}
1.timeout时间单位有SECONDS、MINUTES、HOURS。
2.当使用timeout选项时,options可以放在stage块中
- timestamps
为控制台输出时间戳。示例如下所示:
options {
timestamps()
}
3.2.5 parallel
在pipeline中使用parallel
可以很方便的实现并行构建。
3.2.5.1 阶段并行
示例如下所示:
pipeline{
agent any
stages{
stage("Non Parallel stage"){
steps{
echo "This is non-parallel stage"
}
}
stage("Parallel stage"){
failFast true
parallel{
stage("Parallel A"){
steps{
echo "Parallel A"
}
}
stage("Parallel B"){
steps{
echo "Parallel B"
}
}
stage("Parallel C"){
steps{
echo "Parallel C"
}
}
}
}
}
}
在使用parallel
时,注意事项如下所示:
- parallel
块本身不允许
包含agent
和tools
- 默认情况下,pipeline要等parallel块下所有的阶段都运行完成,才能确定运行结果。若希望所有并行阶段中某个阶段失败后,就即将中止所有阶段,则需要在parallel同级位置加入
failFast true
failFast true 简单来讲就是表示,只要有一个并行阶段运行失败,则立即退出。
3.2.5.2 步骤并行
示例如下所示:
pipeline{
agent any
stages{
stage("Non-parallel steps"){
steps{
echo "Non-parallel steps"
}
}
stage("Parallel steps"){
steps{
parallel(
parallelA:{
echo "parallelA steps"
},
parallelB:{
echo "parallelB steps"
},
parallelC:{
echo "parallelC steps"
}
)
}
}
}
}
阶段并行和步骤并行的主要区别如下所示:
- 写法区别:在阶段并行时,使用的是
大括号
,而步骤并行时,使用的是括号
- 运行区别:阶段并行是运行在不同的executor,而步骤并行,则是运行在同一个executorr