主题
Jenkins Pipeline核心语法
一、Jenkins Pipeline基础语法
1.1 什么是Pipeline
Pipeline是Jenkins的一个核心特性,Pipeline提供了一组可扩展的工具, 用于将"简单到复杂"的交付流程以代码的形式实现和集成到Jenkins中。 Jenkins在运行Pipeline任务的时候会按照Jenkinsfile中定义的代码顺序执行。 Jenkinsfile类似于Dockerfile,具有一套特定的语法。
1.2 如何使用Pipeline
1.2.1安装Pipeline插件
在创建Pipeline类型的作业的时候,需要提前安装好pipeline插件,不然可能会出现找不到pipeline类型的作业。 进入插件管理, 搜索关键字"pipeline" 。安装后重启一下。 当Jenkins重启成功后,我们创建一个流水线类型的作业。
编写流水线代码
1.3 如何编写/运行Pipeline?
Jenkinsfile是一个文本文件,包含了Jenkins Pipeline的定义。它可以被提交到项目的源代码控制仓库中(Jenkinsfile
,比如我们后面要说到的共享库),也可以直接写在Jenkins的配置页面中。 基本示例:
groovy
pipeline {
agent any
stages {
stage('Build') {
steps {
echo 'Building..'
}
}
stage('Test') {
steps {
echo 'Testing..'
}
}
stage('Deploy') {
steps {
echo 'Deploying....'
}
}
}
}
- 构建完成✅
- 查看构建日志
- 流水线回放功能
💡Tips
借助回放可以修改上次构建所使用的Jenkinsfile代码, 进行更改后可以立即运行进行调试。
1.4 Pipeline 开发工具
选择任意pipeline类型的作业,点击“流水线语法”即可进入pipeline开发工具页面。
- 片段生成器 在这里可以找到每个插件以及Jenkins内置的方法的使用方法。有些方法来源于插件,则需要先安装相关的插件才能使用哦。
- 声明式语法生成器 还是选择任意pipeline类型的作业,点击“流水线语法”即可进入pipeline开发工具页面,选择左侧
Declarative Directive Generator
- 全局变量参考 提供已安装好的Jenkins插件和Jenkins内置的全局变量清单
1.5 Pipeline的基础语法介绍
1.5.1 Pipeline
Pipeline是声明式Pipeline的顶层组件:
groovy
pipeline {
// 所有的声明式Pipeline内容
}
1.5.2 agent构建节点
Jenkins采用分布式架构,分为server节点和agent节点。server节点也是可以运行构建任务的,一般使其主要来做任务的调度。agent节点专门用于任务的执行。 随着现在容器的盛行,agent节点可以分为静态节点和动态节点。 静态节点是固定的一台vm虚机或者容器。动态节点是随着任务的构建来自动创建agent节点。
- 参数:
- any: 运行在任一可用节点。
- none:当pipeline全局指定agent为none,则每个stage中定义的agent运行(stage必须指定)。
- label:在指定的标签的节点运行。(标签=分组)
- node:支持自定义流水线的工作目录。
groovy
## 运行在任一可用节点。
pipeline {
agent any
}
## 在指定的标签的节点运行
pipeline {
agent { label "label Name" }
}
## 自定义节点
pipeline {
agent {
node {
label "labelName",
customWorkspace "/opt/agent/workspace"
}
}
}
1.5.3 Stages构建阶段
- 关系:
stages
>stage
>steps
>script
- 定义:
- stages:包含多个stage阶段
- stage:包含多个steps步骤
- steps: 包含一组特定的脚本 (加上script后就可以实现在声明式脚本中嵌入脚本式语法)
groovy
pipeline {
agent { label "build" }
stages {
stage("build") {
steps {
echo "hello"
}
}
}
}
💡Tips
扩展:当pipeline全局指定agent为none,在阶段中定义agent
groovy
pipeline {
agent none
stages{
stage('Build'){
agent { label "build" }
steps {
echo "building......"
}
}
}
}
1.5.4 Stage
定义概念性的不同的构建阶段:
groovy
stage('Build') {
steps {
sh 'make'
}
}
1.5.5 Post构建后操作
定义Pipeline或stage完成后的操作:
- 状态:
- always: 不管什么状态总是执行
- success: 仅流水线成功后执行
- failure: 仅流水线失败后执行
- aborted: 仅流水线被取消后执行
- unstable:不稳定状态,单侧失败等等
groovy
pipeline {
.....
.....
post {
always{
script{
println("流水线结束后,经常做的事情")
}
}
success{
script{
println("流水线成功后,要做的事情")
}
}
failure{
script{
println("流水线失败后,要做的事情")
}
}
aborted{
script{
println("流水线取消后,要做的事情")
}
}
}
}
我们可以根据地铁线路图来理解pipeline :
pipeline
:整条地铁 1 号线的「运营体系」(从规划到运行的整体框架)。agent
:执行运输的「地铁列车」(承载任务运行的载体)。stages
:地铁 1 号线的「完整站点路线」(从起点到终点的所有站点顺序规划)。stage
:路线中的「单个站点」对应 Pipeline 中一个具体的任务步骤)。post
:列车完成「全程运行(所有站点)」后的「收尾操作」(例如:到达终点站后清客、检查车辆状态、为下一班次做准备等)。
1.6 声明式管道与脚本式管道
Jenkins Pipeline支持两种语法:声明式(Declarative)和脚本式(Scripted),是两种不同的语法风格,主要区别体现在结构化程度、语法约束和适用场景上。 以下通过具体代码示例和对比说明两者的差异。
1.6.1 声明式Pipeline
- 强制使用 stages 划分阶段,每个阶段的 steps 必须明确
- 更严格的语法结构
- 更容易读写
- 从Jenkins 2.5开始引入
groovy
pipeline {
agent any // 必须指定执行节点
stages {
stage('Hello') { // 必须用 stage 划分阶段
steps {
sh 'echo "声明式:Hello World"' // 步骤必须在 steps 块内
}
}
}
}
1.6.2 脚本式Pipeline
- 基于Groovy语言
- 提供更大的灵活性
- 无强制结构,用 node 替代 agent,步骤更自由
groovy
node { // 用 node 替代 agent(可选,但通常保留)
stage('Hi') { // stage 可选(但习惯保留)
sh 'echo "脚本式:Hi Jenkins"' // 步骤直接写,无需 steps 块
}
// 直接嵌入 Groovy 逻辑(声明式做不到)
def msg = '动态消息'
sh "echo ${msg}" // 直接拼接变量(声明式需用 env 或特定块)
}
1.6.3 声明式与脚本式核心差异
- 声明式像「填表格」(必须按 pipeline > agent > stages > steps 结构填写);
- 脚本式像「写代码」(用 Groovy 自由组合,node/stage/sh 随意嵌套)。
💡Tips
在声明式Pipeline中也可以执行脚本式Pipeline代码:
groovy
script {
def browsers = ['chrome', 'firefox']
for (int i = 0; i < browsers.size(); ++i) {
echo "Testing the ${browsers[i]} browser"
}
}
二、Pipeline高级语法介绍
2.1 Environment
定义环境变量: 通过键值对key:valued的格式定义流水线在运行时的环境变量, 分为流水线级别和阶段级别。
groovy
pipeline {
environment {
NAME = "srebro"
base_env = "prod"
}
}
groovy
pipeline {
.....
.....
stages{
stage('Build') {
environment{
VERSION="test"
}
steps{
Script {
echo "${VERSION}"
}
}
}
}
}
2.2 Options 运行时选项
Pipeline特定选项
groovy
options {
timeout(time: 1, unit: 'HOURS') //设定流水线的超时时间(可用于阶段级别)
disableConcurrentBuilds() //禁止并行构建
options { buildDiscarder(logRotator(numToKeepStr: '1')) } //设置构建保留策略,保留最近的记录
options { skipDefaultCheckout() } //跳过默认的代码检出
options { retry(3) } //设置重试次数(可用于阶段级别)
options { timestamps() } //设置时间戳输出(可用于阶段级别)
}
- 案例参考
groovy
pipeline{
options{
disableConcurrentBuilds()
skipDefaultCheckout()
timeout(time: 1, unit: 'HOURS')
}
stages{
stage('Build') {
options{
timeout(time: 3, unit: 'MINUTES')
retry(3)
timestamps()
}
steps{
script{
ehco "hello"
}
}
}
}
}
⚠️
如果存在下面的👇报错提示,需要安装插件Timestamper
groovy
WorkflowScript: 21: Invalid option type "timestamps". Valid option types: [authorizationMatrix, buildDiscarder, catchError, checkoutToSubdirectory, disableConcurrentBuilds, disableResume, durabilityHint, lock, overrideIndexTriggers, parallelsAlwaysFailFast, preserveStashes, quietPeriod, rateLimitBuilds, retry, script, skipDefaultCheckout, skipStagesAfterUnstable, timeout, waitUntil, warnError, withChecks, withContext, withCredentials, withEnv, wrap, ws] @ line 21, column 3.
timestamps()
^
2.3 Parameters流水线参数
- 定义: 流水线在运行时设置的参数,UI页面的参数。所有的参数都存储在params对象中。
- 将web ui页面中定义的参数,以pipeline的方式定义。
- 参数类型:
string
:字符串参数boolean
:布尔参数choice
:选择参数password
:密码参数text
:多行文本参数file
:文件参数credentials
:凭证参数run
:运行参数gitGit Parameter
: git参数
groovy
parameters {
string(name: 'VERSION', defaultValue: 'V1.0.0', description: '版本')
booleanParam(name: 'DEBUG_BUILD', defaultValue: true, description: '')
choice(name: 'BUILD_TYPE', choices: ['debug', 'release'], description: '')
password(name: 'PASSWORD', defaultValue: '123456', description: '密码')
text(name: 'DESCRIPTION', defaultValue: '描述', description: '')
file(name: 'FILE', description: '文件')
credentials(name: 'CREDENTIALS', description: '凭证')
gitParameter branch: '', branchFilter: '.*', defaultValue: 'main', description: '构建分支', name: 'GIT_BRANCH', quickFilterEnabled: false, selectedValue: 'NONE', sortMode: 'NONE', tagFilter: '*', type: 'GitParameterDefinition' //依赖于 Git Parameter 插件
run(name: 'RUN', description: '运行')
}
⚠️
配置了parameters流水线参数,需要先构建一次,渲染下流水线的参数化构建
2.4 Triggers
构建触发器:
groovy
triggers {
cron('H */4 * * 1-5') //cron 定时触发,每周一至周五,每 4 小时触发一次构建(具体分钟由 H 随机确定,避免任务扎堆)
pollSCM('H */4 * * 1-5') //轮询代码变更触发构建,含义与上面的 cron 触发器一致,每周一至周五,每 4 小时检查一次代码仓库是否有更新。
}
Demo 案例
groovy
pipeline {
agent any
triggers {
cron('H */7 * * 1-5') //cron 定时触发,每周一至周五,每 7 小时触发一次构建
}
stages {
stage('build') {
steps {
echo 'Hello World'
}
}
}
}
2.5 Tools
自动安装和放入PATH的工具,指的是在全局工具配置中配置的工具。
groovy
tools {
maven 'apache-maven-3.8.1'
jdk 'jdk11'
}
2.6 Input
人工输入:
- 可用于人工卡点确认
- 参数化构建
groovy
pipeline {
parameters {
choice choices: ['maven-3.6.3', 'maven-3.9.10'], description: 'maven版本', name: 'maven_version'
}
agent {
label "${maven_version}"
}
stages {
stage('拉取代码'){
steps{
script {
checkout scmGit(branches: [[name: '*/main']], extensions: [], userRemoteConfigs: [[credentialsId: 'a11aa99b-7bba-48fd-bd01-46b68732578a', url: 'http://code.srebro.cn/opforge/maven-demo.git']])
}
}
}
stage('打印maven版本') {
steps {
sh 'java -version'
sh 'mvn -v'
}
}
stage('构建(maven)') {
steps {
script {
sh "mvn clean package -Dmaven.test.skip=true"
}
}
}
stage('部署') {
input {
message "是否继续发布"
submitter "alice,bob"
ok "Yes, we should."
parameters {
choice choices: ['UAT', 'FAT', 'PROD'], description: '选择发布的环境:[UAT/FAT/PROD]', name: 'ENVTYPE'
}
}
steps {
echo "Deploy to ${ENVTYPE}, doing......."
}
}
}
}
2.7 When
条件执行:
- 根据输入的构建参数判断
- 根据条件判断(not/allOf/anyOf)
groovy
pipeline {
agent any
parameters {
string(name: 'ENVTYPE', defaultValue: 'UAT', description: '选择发布类型:[UAT/FAT/PROD]')
}
stages {
stage('Build') {
steps {
echo 'build......'
}
}
stage('Deploy') {
when {
environment name: 'ENVTYPE', value: 'UAT'
}
steps {
echo 'Deploying.......'
}
}
}
}
when 其他条件
groovy
### allOf 条件全部成立
when {
allOf {
environment name: 'NODE_AGENT', value: 'slave'
environment name: 'DEPLOY_ENV', value: 'prod'
}
}
### anyOf 条件其中一个成立
when {
anyOf {
environment name: 'NODE_AGENT', value: 'slave'
environment name: 'DEPLOY_ENV', value: 'dev'
}
}
2.8 Script
在声明式Pipeline中执行脚本式Pipeline代码:
groovy
script {
def browsers = ['chrome', 'firefox']
for (int i = 0; i < browsers.size(); ++i) {
echo "Testing the ${browsers[i]} browser"
}
}
2.9 parallel 阶段并行
场景: 自动化测试,多主机并行发布。
groovy
pipeline {
agent any
stages {
stage('Parallel Stage') {
failFast true
parallel {
stage('windows') {
agent {
label "master"
}
steps {
echo "windows"
}
}
stage('linux') {
agent {
label "build"
}
steps {
echo "linux"
}
}
}
}
}
}
⚠️
FAQ:如何解决并发构建中的同一节点,workspace问题?
groovy
env.nworkspace = "/home/application/${JOB_NAME}-${UUID.randomUUID().toString()}"
pipeline{
agent{
node{
label "build"
customWorkspace "${env.nworkspace}"
}
}
stages{
stage("build"){
steps{
echo "${env.nworkspace}"
}
}
}
}
三、全局变量参考
在流水线语法中,可以参考到全局环境变量的使用
3.1 内置全局变量
这些变量由 Jenkins 核心系统自动生成,无需额外配置,适用于所有类型的流水线(声明式/脚本式)。
变量名 | 类型 | 描述 |
---|---|---|
BUILD_NUMBER | 字符串 | 当前构建的唯一编号(从 1 开始递增,重启 Jenkins 后可能重置)。 |
BUILD_ID | 字符串 | 当前构建的唯一标识符(默认格式为 YYYYMMDD-HHMMSS,可通过系统配置修改)。 |
BUILD_DISPLAY_NAME | 字符串 | 构建的显示名称(默认格式为 #${BUILD_NUMBER},可通过系统配置自定义)。 |
JOB_NAME | 字符串 | 当前任务(Job)的名称(不含工作区路径)。 |
JOB_BASE_NAME | 字符串 | JOB_NAME 去除后缀后的基础名称(若任务是通过“复制”创建的,可能包含 -copyN)。 |
BUILD_TAG | 字符串 | 构建的标签(默认格式为 jenkins-${JOB_NAME}-${BUILD_NUMBER})。 |
BUILD_URL | 字符串 | 当前构建的完整 URL 地址(可用于访问 Jenkins 构建详情页)。 |
WORKSPACE | 字符串 | 当前任务的工作区路径(绝对路径,用于访问代码或临时文件)。 |
NODE_NAME | 字符串 | 当前执行构建的 Agent 节点名称(如 master 或自定义节点名)。 |
BUILD_STATUS | 字符串 | 当前构建的状态(仅在构建完成后有效)。 |
CAUSE | 字符串 | 触发当前构建的原因(如手动触发、定时触发、SCM 轮询触发等)。 |
USER_NAME | 字符串 | 触发构建的用户名称(若为定时触发则为 SYSTEM)。 |
3.2 currentBuild 变量(构建实例对象)
currentBuild 是 Jenkins 流水线中的内置变量,类型为 Run(表示当前构建的实例对象),用于获取构建的详细元数据(如构建号、结果、时间戳、参数等)。
属性名 | 类型 | 描述 |
---|---|---|
number | 整数(Integer) | 当前构建的编号(从 1 开始递增)。 |
result | 字符串(String) | 构建结果(仅构建完成后有效): - SUCCESS(成功) - FAILURE(失败) - UNSTABLE(不稳定) - 构建进行中时为 null。 |
currentResult | 字符串(String) | 构建结果(始终非空): - SUCCESS、UNSTABLE、FAILURE(即使构建未完成,默认返回 SUCCESS?需验证)。 |
displayName | 字符串(String) | 构建的显示名称(默认格式为 #${BUILD_NUMBER},可自定义)。 |
fullDisplayName | 字符串(String) | 完整显示名称(包含父任务路径),格式为 folder1 » folder2 » foo #123。 |
projectName | 字符串(String) | 当前构建所属项目的名称(不含路径)。 |
fullProjectName | 字符串(String) | 当前构建所属项目的完整名称(含父文件夹路径)。 |
description | 字符串(String) | 构建的附加描述(可通过脚本或插件设置)。 |
id | 字符串(String) | 构建的唯一 ID(默认与 BUILD_NUMBER 一致)。 |
externalizableId | 字符串(String) | 构建的全局唯一标识符(格式为 fullProjectName#number)。 |
timeInMillis | 长整型(Long) | 构建计划启动时间的毫秒时间戳(自 Unix 纪元起)。 |
startTimeInMillis | 长整型(Long) | 构建实际开始运行时间的毫秒时间戳。 |
duration | 长整型(Long) | 构建持续时间(毫秒,仅构建完成后有效)。 |
durationString | 字符串(String) | 构建持续时间的可读格式(如 5 min 0 sec)。 |
absoluteUrl | 字符串(String) | 构建详情页的完整 URL 地址。 |
keepLog | 布尔型(Boolean) | 标记是否保留构建日志(true 表示保留,否则可能被清理)。 |
changeSets | 列表(List) | 来自不同 SCM 检出的变更集列表,每个变更集包含提交记录(commitId、timestamp、msg、author、affectedFiles 等)。 注意:非 @NonCPS 方法中不可序列化访问。 |
upstreamBuilds | 列表(List) | 上游项目的构建列表(其产物作为当前构建的输入)。 |
buildVariables | 映射(Map) | 非 Pipeline 下游构建的构建变量映射;Pipeline 下游构建为结束时 env 中的全局变量(不包含构建参数)。 注意:子 Pipeline 可通过此属性向父 Pipeline 传递变量。 |
rawBuild | 对象(hudson.model.Run) | 底层 Jenkins 的 Run 对象(提供更多原生 API)。 注意:仅在信任库或管理员沙盒外脚本中访问,且不可序列化(需在 @NonCPS 方法中使用)。 |
demo 演示
groovy
println(env)
env.branchName = "develop"
env.commitID = "${UUID.randomUUID().toString()}"
env.commitID = "${env.commitID.split("-")[0]}"
currentBuild.displayName = "#${env.branchName}-${env.commitID}"
currentBuild.description = "Trigger by user jenkins \n branch: master"
pipeline {
agent { label "master"}
stages {
stage('打印全局变量') {
steps {
script {
// 打印内置变量
echo "BUILD_NUMBER: ${env.BUILD_NUMBER}"
echo "JOB_NAME: ${env.JOB_NAME}"
echo "WORKSPACE: ${env.WORKSPACE}"
// 打印 currentBuild 属性
echo "当前构建号: ${currentBuild.number}"
echo "构建结果: ${currentBuild.result}" // 仅在构建完成后有值
echo "构建开始时间(秒): ${currentBuild.startTimeInMillis / 1000}"
}
}
}
}
}
3.3 流水线中变量定义引用
变量的类型:两种类型的变量。
- Jenkins系统内置变量 (全局变量)
- Pipeline中自定义变量(全局/局部变量)
3.3.1 Jenkins系统内置变量引用
- 双引号字符串
变量会被解析(👍推荐)
示例:echo "当前构建编号:${BUILD_NUMBER}"
或 echo "工作区路径:$WORKSPACE"
。
- 单引号字符串
变量不会被解析(仅作为字面量)
示例:sh 'echo 单引号中的变量不会解析:$BUILD_NUMBER'
(输出字面量$BUILD_NUMBER
)。
- 脚本块(Script Block)
在script
标签或sh
/bat
步骤中,可直接使用变量。
TIP
内置变量的值由Jenkins运行时动态生成,无法手动修改。
3.3.2 Pipeline中自定义变量
Pipeline中自定义变量是用户根据需求手动定义的变量,用于存储临时数据或业务逻辑中的中间值。根据作用域可分为局部变量和全局变量。
3.3.2.1 局部变量
局部变量仅在特定作用域(如某个step、stage或script块)内有效,超出作用域后无法访问。
定义方式:
- 使用
def
关键字声明(适用于声明式流水线的steps
或脚本式流水线)。
groovy
pipeline {
agent any
stages {
stage('示例') {
steps {
def localVar = '我是局部变量' // 仅在当前step内有效
echo "局部变量值:$localVar" // 正常输出
}
post {
success {
echo "Post中访问局部变量:$localVar" // 报错:变量未定义
}
}
}
}
}
- 在script块中使用(脚本式语法,作用域同上)
groovy
script {
def scriptVar = '脚本块内的变量'
echo "Script块内:$scriptVar" // 有效
}
echo "Script块外:$scriptVar" // 报错
3.3.2.2 全局变量
全局变量在整个流水线中共享,可在多个stage或step中访问。常见定义方式有两种:
(1) 使用environment块(👍推荐)
groovy
pipeline {
agent any
environment {
GLOBAL_VAR = '全局环境变量' // 字符串类型
NUM_VAR = 123 // 数字类型(实际存储为字符串,需转换)
BOOL_VAR = true // 布尔类型(需注意脚本中的类型判断)
}
stages {
stage('Stage1') {
steps {
echo "Stage1访问全局变量:$GLOBAL_VAR" // 输出:全局环境变量
sh 'echo Shell中访问:${GLOBAL_VAR}' // Shell脚本中需用${}显式引用
}
}
stage('Stage2') {
steps {
echo "Stage2访问全局变量:${GLOBAL_VAR}" // 跨stage仍有效
}
}
}
}
WARNING
- environment块只能定义在pipeline顶层或stage内(若在stage内定义,仅该stage及其子步骤有效)。
- 变量值为字符串类型(即使赋值为数字或布尔值),在需要数值的场景(如条件判断)中需显式转换(如${NUM_VAR.toInteger()})。
(2) 使用env对象动态赋值
groovy
pipeline {
agent any
stages {
stage('动态设置全局变量') {
steps {
env.DYNAMIC_VAR = '动态赋值的全局变量' // 直接操作env对象
}
}
stage('跨stage访问') {
steps {
echo "访问动态变量:${env.DYNAMIC_VAR}" // 输出:动态赋值的全局变量
}
}
}
}
变量作用域总结
变量类型 | 定义方式 | 作用域范围 | 是否支持跨Stage访问 |
---|---|---|---|
局部变量 | def关键字 | 当前step或script块内 | 否 |
全局环境变量 | environment块或env对象 | 整个流水线(或stage内) | 是(顶层environment) |
总结 Jenkins流水线中的变量分为内置变量(系统预定义)和自定义变量(手动定义)。内置变量用于获取流水线元数据,自定义变量用于业务逻辑数据传递。使用时需注意作用域(局部/全局)和引用方式(双引号解析、Shell语法适配),避免因作用域或类型问题导致流程错误。