Pipeline 基础
Pipeline 是 Jenkins 2.0 的核心特性,它将整个构建流程以代码形式定义,实现了"流水线即代码"的理念。通过 Pipeline,你可以将代码检出、构建、测试、部署等一系列操作编排成一条自动化的流水线。
什么是 Pipeline?
Pipeline(流水线)是一套插件,支持在 Jenkins 中实现持续交付流水线。持续交付流水线是将软件从版本控制到最终交付给用户的自动化流程,包含构建、测试、部署等多个阶段。
Pipeline 的核心优势
代码化:Pipeline 使用 Groovy DSL 语法定义,可以像普通代码一样进行版本控制、代码审查和迭代修改。当 Pipeline 定义在代码仓库中的 Jenkinsfile 文件里时,项目成员可以清楚地看到构建流程是如何工作的。
持久性:Pipeline 能够在 Jenkins 控制器重启后恢复执行。即使在长时间运行的任务过程中 Jenkins 发生重启,Pipeline 也能从断点继续执行,不会丢失进度。
可暂停:Pipeline 支持在执行过程中暂停,等待人工输入或审批后再继续。这对于需要人工确认才能部署到生产环境的场景非常有用。
可扩展:通过共享库(Shared Libraries)机制,可以将常用的构建逻辑封装成可复用的模块,供多个项目使用。插件开发者也可以扩展 Pipeline 的 DSL,添加自定义步骤。
声明式与脚本式 Pipeline
Jenkins Pipeline 支持两种语法风格:声明式(Declarative)和脚本式(Scripted)。
// 声明式 Pipeline(推荐)
// 结构清晰,语法简洁,适合大多数场景
pipeline {
agent any
stages {
stage('Build') {
steps {
echo 'Building...'
}
}
stage('Test') {
steps {
echo 'Testing...'
}
}
}
}
// 脚本式 Pipeline
// 更灵活,适合复杂逻辑处理
node {
stage('Build') {
echo 'Building...'
}
stage('Test') {
echo 'Testing...'
}
}
两种语法的选择建议:大多数情况下推荐使用声明式 Pipeline,因为它结构清晰、易于理解和维护。只有在需要处理非常复杂的逻辑时,才考虑使用脚本式 Pipeline。
Pipeline 基本结构
声明式 Pipeline 的基本结构包含几个核心部分:
pipeline {
// 指定运行环境
agent any
// 定义环境变量
environment {
APP_NAME = 'my-app'
}
// 构建选项配置
options {
timeout(time: 1, unit: 'HOURS')
}
// 定义构建阶段
stages {
stage('Build') {
steps {
echo 'Building...'
}
}
}
// 后置处理
post {
always {
echo 'Cleanup...'
}
}
}
pipeline 块
pipeline 块是声明式 Pipeline 的顶层容器,所有 Pipeline 内容都必须包含在这个块内。这是声明式 Pipeline 特有的语法,脚本式 Pipeline 不需要这个块。
agent 指令
agent 指定 Pipeline 在哪里执行。它告诉 Jenkins 分配一个执行器和工作空间来运行 Pipeline。
// 在任意可用节点执行
agent any
// 不在任何节点执行(用于阶段级别指定)
agent none
// 指定标签的节点
agent { label 'linux && docker' }
// Docker 容器内执行
agent {
docker {
image 'maven:3.9-eclipse-temurin-21'
args '-v $HOME/.m2:/root/.m2'
}
}
// Kubernetes Pod 内执行
agent {
kubernetes {
yaml '''
apiVersion: v1
kind: Pod
spec:
containers:
- name: maven
image: maven:3.9-eclipse-temurin-21
command: ['cat']
tty: true
'''
}
}
阶段级别的 agent:可以为不同阶段指定不同的执行环境:
pipeline {
agent none
stages {
stage('Build') {
agent {
docker { image 'maven:3.9-eclipse-temurin-21' }
}
steps {
sh 'mvn clean package'
}
}
stage('Test') {
agent {
docker { image 'node:20' }
}
steps {
sh 'npm test'
}
}
}
}
stages 和 stage
stages 块包含一个或多个 stage 块,每个 stage 代表一个逻辑阶段。阶段名称会在 Jenkins 界面中显示,方便查看构建进度。
stages {
stage('Checkout') {
steps {
git 'https://github.com/example/repo.git'
}
}
stage('Build') {
steps {
sh 'mvn clean package'
}
}
stage('Test') {
steps {
sh 'mvn test'
}
}
stage('Deploy') {
steps {
sh './deploy.sh'
}
}
}
steps
steps 块定义阶段内要执行的具体操作。Jenkins 提供了丰富的内置步骤,也可以通过插件添加更多步骤。
steps {
// 输出信息
echo 'Hello, Jenkins!'
// 执行 Shell 命令(Linux/macOS)
sh 'ls -la'
sh '''
echo "多行命令"
pwd
whoami
'''
// 执行 Windows 批处理命令
bat 'dir'
// 执行 PowerShell 命令
powershell 'Get-Date'
// 暂停执行
sleep(time: 30, unit: 'SECONDS')
// 等待用户输入
input message: 'Continue?'
// 超时控制
timeout(time: 10, unit: 'MINUTES') {
sh 'long-running-task.sh'
}
// 重试机制
retry(3) {
sh 'flaky-test.sh'
}
}
环境变量
环境变量用于存储构建过程中需要使用的配置信息,可以在 Pipeline 的多个地方访问。
定义环境变量
pipeline {
agent any
environment {
// 静态值
APP_NAME = 'my-application'
VERSION = '1.0.0'
// 使用凭证
DB_PASSWORD = credentials('db-password')
// 动态值(通过命令获取)
BUILD_DATE = sh(
script: 'date +%Y%m%d',
returnStdout: true
).trim()
// 引用其他变量
FULL_NAME = "${APP_NAME}-${VERSION}"
}
stages {
stage('Build') {
// 阶段级别的环境变量
environment {
STAGE_VAR = 'stage-value'
}
steps {
echo "Building ${env.APP_NAME}"
echo "Full name: ${env.FULL_NAME}"
echo "Build date: ${env.BUILD_DATE}"
}
}
}
}
内置环境变量
Jenkins 提供了许多内置环境变量,可以在 Pipeline 中直接使用:
| 变量名 | 说明 | 示例值 |
|---|---|---|
BUILD_NUMBER | 当前构建编号 | 42 |
BUILD_ID | 构建 ID(与 BUILD_NUMBER 相同) | 42 |
BUILD_URL | 构建的完整 URL | http://jenkins/job/myjob/42/ |
JOB_NAME | 任务名称 | my-project |
JOB_URL | 任务的 URL | http://jenkins/job/my-project/ |
WORKSPACE | 工作空间路径 | /var/jenkins/workspace/my-project |
NODE_NAME | 当前节点名称 | agent-01 |
JENKINS_URL | Jenkins 服务器 URL | http://jenkins/ |
GIT_COMMIT | Git 提交哈希 | a1b2c3d4 |
GIT_BRANCH | Git 分支名 | main |
steps {
echo "Build #${env.BUILD_NUMBER}"
echo "Job: ${env.JOB_NAME}"
echo "Workspace: ${env.WORKSPACE}"
// 在 Shell 中使用
sh 'echo "Build: ${BUILD_NUMBER}"'
}
参数化构建
参数化构建允许在触发构建时传入参数,使 Pipeline 更加灵活。
参数类型
pipeline {
agent any
parameters {
// 字符串参数
string(
name: 'BRANCH',
defaultValue: 'main',
description: '要构建的分支'
)
// 选项参数(下拉选择)
choice(
name: 'ENVIRONMENT',
choices: ['development', 'staging', 'production'],
description: '部署环境'
)
// 布尔参数(复选框)
booleanParam(
name: 'SKIP_TESTS',
defaultValue: false,
description: '是否跳过测试'
)
// 文本参数(多行文本)
text(
name: 'DESCRIPTION',
defaultValue: '',
description: '构建描述'
)
// 密码参数(隐藏输入)
password(
name: 'SECRET_KEY',
description: '密钥'
)
// 文件参数
file(
name: 'CONFIG_FILE',
description: '配置文件'
)
}
stages {
stage('Build') {
steps {
echo "Branch: ${params.BRANCH}"
echo "Environment: ${params.ENVIRONMENT}"
echo "Skip tests: ${params.SKIP_TESTS}"
}
}
}
}
使用参数
stages {
stage('Checkout') {
steps {
git branch: params.BRANCH,
url: 'https://github.com/example/repo.git'
}
}
stage('Test') {
// 条件执行:当参数为 false 时才运行测试
when {
expression { !params.SKIP_TESTS }
}
steps {
sh 'mvn test'
}
}
stage('Deploy') {
steps {
script {
// 生产环境需要确认
if (params.ENVIRONMENT == 'production') {
input message: '确认部署到生产环境?'
}
sh "./deploy.sh ${params.ENVIRONMENT}"
}
}
}
}
条件执行
when 指令用于控制阶段是否执行,可以根据分支、环境变量、表达式等条件判断。
when 条件类型
stages {
// 根据分支判断
stage('Deploy to Production') {
when {
branch 'main'
}
steps {
sh './deploy-prod.sh'
}
}
// 根据环境变量判断
stage('Deploy to Dev') {
when {
environment name: 'DEPLOY_ENV', value: 'development'
}
steps {
sh './deploy-dev.sh'
}
}
// 根据表达式判断
stage('Release') {
when {
expression { params.RELEASE == true }
}
steps {
sh './release.sh'
}
}
// 根据 Git 标签判断
stage('Tag Release') {
when {
tag 'v*'
}
steps {
sh './tag-release.sh'
}
}
// 根据变更文件判断
stage('Frontend Tests') {
when {
changeset '**/*.js'
}
steps {
sh 'npm test'
}
}
// 根据触发原因判断
stage('Scheduled Tasks') {
when {
triggeredBy 'TimerTrigger'
}
steps {
sh './scheduled-task.sh'
}
}
}
组合条件
// 所有条件都满足
stage('Deploy') {
when {
allOf {
branch 'main'
expression { params.DEPLOY == true }
}
}
steps {
sh './deploy.sh'
}
}
// 任一条件满足
stage('Test') {
when {
anyOf {
branch 'main'
branch 'develop'
branch 'release/*'
}
}
steps {
sh 'mvn test'
}
}
// 条件取反
stage('Skip') {
when {
not {
branch 'main'
}
}
steps {
echo 'Not main branch'
}
}
// 嵌套组合
stage('Complex') {
when {
allOf {
anyOf {
branch 'main'
branch 'release/*'
}
not {
expression { params.SKIP_DEPLOY }
}
}
}
steps {
sh './deploy.sh'
}
}
beforeAgent 选项
默认情况下,Jenkins 会先分配节点,再评估 when 条件。使用 beforeAgent true 可以在分配节点前评估条件,节省资源:
stage('Optional Build') {
when {
beforeAgent true
expression { params.BUILD_NEEDED }
}
agent { label 'expensive-node' }
steps {
sh 'build.sh'
}
}
这个配置的工作流程是:
- 首先评估
when条件中的表达式 - 如果条件为 false,跳过此阶段,不会分配节点
- 如果条件为 true,才分配指定的 Agent 并执行步骤
这对于以下场景特别有用:
- Agent 资源昂贵(如 GPU 服务器、大内存机器)
- Agent 数量有限,需要避免不必要的资源占用
- 条件评估速度快,而 Agent 分配可能需要时间
beforeInput 选项
类似于 beforeAgent,beforeInput 选项控制 when 条件的评估时机。当设置为 true 时,条件会在等待用户输入之前评估:
stage('Production Deploy') {
when {
beforeInput true
branch 'main'
}
input {
message "确认部署到生产环境?"
ok "确认部署"
submitter "admin,ops"
}
steps {
sh './deploy-production.sh'
}
}
这个配置的工作流程是:
- 首先检查是否为 main 分支
- 如果不是 main 分支,直接跳过,不会等待用户输入
- 如果是 main 分支,才显示输入提示等待用户确认
这避免了在非目标分支上仍然需要人工介入才能继续的问题。
并行执行
并行执行可以同时运行多个任务,显著缩短构建时间。
parallel 块
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'mvn clean compile'
}
}
stage('Test') {
parallel {
stage('Unit Tests') {
steps {
sh 'mvn test -Dtest=UnitTest*'
}
}
stage('Integration Tests') {
steps {
sh 'mvn test -Dtest=IntegrationTest*'
}
}
stage('Code Quality') {
steps {
sh 'mvn sonar:sonar'
}
}
}
}
stage('Deploy') {
steps {
sh './deploy.sh'
}
}
}
}
并行执行选项
stage('Test') {
parallel {
stage('Unit Tests') {
steps {
sh 'mvn test'
}
}
stage('E2E Tests') {
stages {
stage('Setup') {
steps {
sh './setup-e2e.sh'
}
}
stage('Run') {
steps {
sh './run-e2e.sh'
}
}
}
}
}
}
动态并行
使用脚本块动态生成并行任务:
pipeline {
agent any
stages {
stage('Build Matrix') {
steps {
script {
def platforms = ['linux', 'windows', 'macos']
def parallelStages = [:]
platforms.each { platform ->
parallelStages[platform] = {
stage("Build on ${platform}") {
echo "Building for ${platform}"
// 实际构建命令...
}
}
}
parallel parallelStages
}
}
}
}
}
failFast 选项
当一个并行分支失败时,是否终止其他分支:
stage('Test') {
parallel {
stage('Unit Tests') {
steps {
sh 'mvn test'
}
}
stage('Integration Tests') {
steps {
sh 'mvn integration-test'
}
}
}
// 任一分支失败时立即终止其他分支
failFast true
}
或者在 Pipeline 级别设置:
pipeline {
agent any
options {
parallelsAlwaysFailFast()
}
stages {
// ...
}
}
Matrix 构建
Matrix 构建是 Declarative Pipeline 的高级特性,允许你定义多维度的构建矩阵。这对于需要在多种环境组合下测试项目的场景非常有用,例如在不同操作系统、不同 Java 版本、不同浏览器等组合下运行测试。
基本语法
pipeline {
agent none
stages {
stage('Matrix Build') {
matrix {
axes {
axis {
name 'PLATFORM'
values 'linux', 'windows', 'macos'
}
axis {
name 'BROWSER'
values 'chrome', 'firefox', 'safari'
}
}
agent { label "${PLATFORM}" }
stages {
stage('Build') {
steps {
echo "Building on ${PLATFORM} with ${BROWSER}"
sh "./build-${PLATFORM}.sh"
}
}
stage('Test') {
steps {
echo "Testing on ${PLATFORM} with ${BROWSER}"
sh "./test-${BROWSER}.sh"
}
}
}
}
}
}
}
上面的例子会生成 9 个构建组合(3 个平台 × 3 个浏览器),每个组合都会执行 Build 和 Test 阶段。
axes 配置
axes 定义矩阵的维度,每个 axis 代表一个维度:
axes {
axis {
name 'JAVA_VERSION'
values '11', '17', '21'
}
axis {
name 'DATABASE'
values 'mysql', 'postgresql', 'mongodb'
}
axis {
name 'ENVIRONMENT'
values 'development', 'staging'
}
}
excludes 配置
使用 excludes 可以排除不需要的构建组合:
matrix {
axes {
axis {
name 'PLATFORM'
values 'linux', 'windows', 'macos'
}
axis {
name 'BROWSER'
values 'chrome', 'firefox', 'safari'
}
}
excludes {
exclude {
axis {
name 'PLATFORM'
values 'macos'
}
axis {
name 'BROWSER'
values 'chrome' // Mac 上不测试 Chrome
}
}
exclude {
axis {
name 'PLATFORM'
values 'linux'
}
axis {
name 'BROWSER'
values 'safari' // Linux 上不测试 Safari
}
}
}
// ...
}
Matrix 中的 when 条件
可以在 matrix 级别或阶段级别使用 when 条件:
matrix {
axes {
axis {
name 'ENV'
values 'dev', 'staging', 'prod'
}
}
stages {
stage('Deploy') {
when {
anyOf {
expression { ENV == 'staging' }
expression { ENV == 'prod' }
}
}
steps {
sh "./deploy-${ENV}.sh"
}
}
}
}
完整示例
以下是一个完整的跨平台、多版本构建示例:
pipeline {
agent none
options {
parallelsAlwaysFailFast()
}
stages {
stage('Build and Test Matrix') {
matrix {
axes {
axis {
name 'JAVA'
values '11', '17', '21'
}
axis {
name 'PLATFORM'
values 'linux', 'windows'
}
}
excludes {
exclude {
axis {
name 'JAVA'
values '11'
}
axis {
name 'PLATFORM'
values 'windows'
}
}
}
agent {
docker {
image "maven:3.9-eclipse-temurin-${JAVA}"
label "${PLATFORM}"
}
}
environment {
MAVEN_OPTS = '-Xmx1024m'
}
stages {
stage('Build') {
steps {
sh 'mvn clean compile'
}
}
stage('Test') {
steps {
sh 'mvn test'
}
post {
always {
junit 'target/surefire-reports/*.xml'
}
}
}
}
}
}
stage('Deploy') {
agent { label 'deploy' }
when {
branch 'main'
}
steps {
sh './deploy.sh'
}
}
}
post {
always {
echo 'Matrix build completed'
}
}
}
这个 Pipeline 会:
- 在 Linux 和 Windows 上分别使用 Java 11、17、21 进行构建测试(排除 Windows + Java 11 组合)
- 总共执行 5 个构建组合(2 平台 × 3 版本 - 1 排除)
- 所有测试完成后,如果是 main 分支,执行部署
后置处理
post 块定义在 Pipeline 或阶段执行完成后的操作,用于清理资源、发送通知等。
post 条件
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'mvn clean package'
}
}
}
post {
// 总是执行,无论构建结果如何
always {
echo 'Pipeline completed'
cleanWs() // 清理工作空间
}
// 构建成功时执行
success {
echo 'Build succeeded!'
mail to: '[email protected]',
subject: "Build Success: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
body: "Build completed successfully."
}
// 构建失败时执行
failure {
echo 'Build failed!'
mail to: '[email protected]',
subject: "Build Failed: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
body: "Check the console output at ${env.BUILD_URL}"
}
// 构建不稳定时执行(如测试失败)
unstable {
echo 'Build is unstable'
}
// 构建被中止时执行
aborted {
echo 'Build was aborted'
}
// 构建状态发生变化时执行
changed {
echo 'Build status changed from previous build'
}
// 从失败变为成功时执行
fixed {
echo 'Build was fixed!'
}
// 从成功变为失败时执行
regression {
echo 'Build regressed'
}
}
}
阶段级别的 post
stages {
stage('Test') {
steps {
sh 'mvn test'
}
post {
always {
// 发布测试报告
junit 'target/surefire-reports/*.xml'
}
success {
echo 'All tests passed'
}
failure {
echo 'Some tests failed'
}
}
}
}
构建选项
options 块用于配置 Pipeline 的行为,如超时、重试、日志轮转等。
常用选项
pipeline {
agent any
options {
// 构建历史保留策略
buildDiscarder(logRotator(
numToKeepStr: '10',
artifactNumToKeepStr: '5'
))
// 构建超时
timeout(time: 1, unit: 'HOURS')
// 禁止并发构建
disableConcurrentBuilds()
// 禁止并发构建,并中止正在运行的构建
disableConcurrentBuilds(abortPrevious: true)
// 添加时间戳到日志
timestamps()
// 跳过默认的代码检出
skipDefaultCheckout()
// 设置构建显示名称
buildName '#${BUILD_NUMBER} - ${BRANCH_NAME}'
// 静默期(触发后等待一段时间再执行)
quietPeriod(10)
// 重试次数
retry(3)
// 跳过阶段
skipStagesAfterUnstable()
}
stages {
stage('Build') {
steps {
echo 'Building...'
}
}
}
}
阶段级别的选项
stages {
stage('Long Task') {
options {
timeout(time: 30, unit: 'MINUTES')
}
steps {
sh 'long-running-script.sh'
}
}
stage('Retry Task') {
options {
retry(3)
}
steps {
sh 'flaky-script.sh'
}
}
}
触发器
triggers 块定义 Pipeline 的触发方式,除了手动触发,还可以配置定时触发或 Webhook 触发。
Cron 定时触发
pipeline {
agent any
triggers {
// 每15分钟执行一次
cron('H/15 * * * *')
// 每天凌晨2点执行
cron('H 2 * * *')
// 工作日早上8点执行
cron('H 8 * * 1-5')
}
stages {
stage('Build') {
steps {
echo 'Scheduled build'
}
}
}
}
Cron 表达式说明:
┌───────────── 分钟 (0-59)
│ ┌───────────── 小时 (0-23)
│ │ ┌───────────── 日期 (1-31)
│ │ │ ┌───────────── 月份 (1-12)
│ │ │ │ ┌───────────── 星期 (0-7, 0和7都表示周日)
│ │ │ │ │
* * * * *
// H 表示自动分散负载,避免所有定时任务在同一时间触发
H/15 * * * * // 每小时内的每15分钟(H会被替换为一个固定值,如 3,18,33,48)
H 2 * * * // 每天凌晨2点的某个时刻
Poll SCM
定期检查代码仓库是否有变更,有变更时触发构建:
triggers {
// 每5分钟检查一次
pollSCM('H/5 * * * *')
}
注意:Poll SCM 会产生额外的网络请求,推荐使用 Webhook 代替。
Webhook 触发
使用 Webhook 可以在代码推送时立即触发构建,无需轮询:
triggers {
// GitHub Webhook
githubPush()
// GitLab Webhook
gitlab(triggerOnPush: true, triggerOnMergeRequest: true)
// Bitbucket Webhook
bitbucketPush()
// 通用 Webhook
GenericTrigger(
genericVariables: [
[key: 'ref', value: '$.ref']
],
token: 'my-token',
causeString: 'Triggered by $ref'
)
}
工具配置
tools 块用于声明 Pipeline 需要使用的工具,Jenkins 会自动配置环境变量。
pipeline {
agent any
tools {
// Maven(需要在全局工具配置中定义)
maven 'Maven-3.9'
// JDK(推荐使用 Java 21)
jdk 'JDK-21'
// Gradle
gradle 'Gradle-8'
// Node.js
nodejs 'NodeJS-20'
}
stages {
stage('Build') {
steps {
sh 'mvn --version'
sh 'java -version'
}
}
}
}
工具需要在 Jenkins 全局配置(Manage Jenkins → Tools)中预先定义。
重要说明:JDK 版本配置需要区分两个概念:
- 运行 Jenkins 的 Java 版本:Jenkins 控制器和 Agent 进程使用的 Java 版本,必须符合 Jenkins 版本的要求
- 构建项目使用的 Java 版本:构建 Java 项目时使用的 JDK 版本,可以是任何版本,与运行 Jenkins 的版本独立
可以在同一个 Pipeline 中配置多个 JDK 版本,根据不同阶段的需要选择使用:
pipeline {
agent any
tools {
// 默认使用 Java 21
jdk 'JDK-21'
}
stages {
stage('Build with Java 21') {
steps {
sh 'java -version' // 输出 Java 21
sh 'mvn clean package'
}
}
stage('Test with Java 17') {
tools {
jdk 'JDK-17' // 阶段级别覆盖
}
steps {
sh 'java -version' // 输出 Java 17
sh 'mvn test'
}
}
}
}
输入与审批
input 步骤允许 Pipeline 暂停执行,等待人工输入或审批。
基本用法
stage('Deploy to Production') {
steps {
input message: '确认部署到生产环境?', ok: '确认部署'
sh './deploy-prod.sh'
}
}
带参数的输入
stage('Deploy') {
steps {
script {
def userInput = input(
id: 'DeployApproval',
message: '部署配置',
parameters: [
choice(
name: 'ENVIRONMENT',
choices: ['us-east-1', 'us-west-2', 'eu-west-1'],
description: '选择部署区域'
),
string(
name: 'VERSION',
defaultValue: env.BUILD_NUMBER,
description: '部署版本'
),
booleanParam(
name: 'SKIP_BACKUP',
defaultValue: false,
description: '跳过备份'
)
],
submitter: 'admin,deployer', // 只有这些用户可以审批
submitterParameter: 'APPROVER' // 审批者用户名存入此参数
)
echo "Approved by: ${userInput.APPROVER}"
echo "Environment: ${userInput.ENVIRONMENT}"
echo "Version: ${userInput.VERSION}"
echo "Skip backup: ${userInput.SKIP_BACKUP}"
sh "./deploy.sh ${userInput.ENVIRONMENT} ${userInput.VERSION}"
}
}
}
超时保护
为防止无限等待审批,建议配合超时使用:
stage('Approval') {
steps {
timeout(time: 24, unit: 'HOURS') {
input message: '请在24小时内确认部署'
}
}
}
错误处理
Pipeline 提供多种方式处理错误和异常。
try-catch 块
在脚本块中使用 Groovy 的异常处理:
stage('Build') {
steps {
script {
try {
sh 'mvn clean package'
} catch (Exception e) {
echo "构建失败: ${e.getMessage()}"
currentBuild.result = 'FAILURE'
// 继续执行后续阶段
}
}
}
}
catchError 步骤
捕获错误但允许 Pipeline 继续:
stage('Test') {
steps {
// 捕获错误,设置构建结果,但继续执行
catchError(buildResult: 'SUCCESS', stageResult: 'UNSTABLE') {
sh 'mvn test'
}
}
}
warnError 步骤
将错误转换为警告:
stage('Optional Step') {
steps {
warnError('Optional step failed but continuing') {
sh 'optional-script.sh'
}
}
}
unstable 和 error 步骤
steps {
script {
// 设置构建状态为不稳定
unstable('Tests have warnings')
// 终止构建并标记为失败
if (criticalError) {
error('Critical error occurred')
}
}
}
完整示例
以下是一个完整的 Java 项目 CI/CD Pipeline 示例:
pipeline {
agent {
label 'linux && docker'
}
environment {
APP_NAME = 'my-app'
DOCKER_REGISTRY = 'registry.example.com'
GIT_COMMIT_SHORT = sh(
script: 'git rev-parse --short HEAD',
returnStdout: true
).trim()
}
parameters {
string(
name: 'BRANCH',
defaultValue: 'main',
description: '要构建的分支'
)
choice(
name: 'ENV',
choices: ['dev', 'staging', 'prod'],
description: '部署环境'
)
booleanParam(
name: 'SKIP_TESTS',
defaultValue: false,
description: '跳过测试'
)
}
options {
buildDiscarder(logRotator(numToKeepStr: '20'))
timeout(time: 1, unit: 'HOURS')
disableConcurrentBuilds()
timestamps()
}
triggers {
githubPush()
}
tools {
maven 'Maven-3.8'
jdk 'JDK-11'
}
stages {
stage('Checkout') {
steps {
checkout scm
echo "Building branch: ${env.BRANCH_NAME ?: params.BRANCH}"
echo "Commit: ${env.GIT_COMMIT}"
}
}
stage('Build') {
steps {
sh 'mvn clean package -DskipTests'
archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
}
}
stage('Test') {
when {
expression { !params.SKIP_TESTS }
}
parallel {
stage('Unit Tests') {
steps {
sh 'mvn test'
}
post {
always {
junit 'target/surefire-reports/*.xml'
}
}
}
stage('Integration Tests') {
steps {
sh 'mvn verify -DskipUnitTests'
}
post {
always {
junit 'target/failsafe-reports/*.xml'
}
}
}
}
}
stage('Code Quality') {
steps {
withSonarQubeEnv('SonarQube') {
sh 'mvn sonar:sonar'
}
}
}
stage('Quality Gate') {
steps {
timeout(time: 5, unit: 'MINUTES') {
waitForQualityGate abortPipeline: true
}
}
}
stage('Build Image') {
steps {
script {
docker.build(
"${DOCKER_REGISTRY}/${APP_NAME}:${GIT_COMMIT_SHORT}",
'--build-arg JAR_FILE=target/*.jar .'
)
}
}
}
stage('Push Image') {
when {
anyOf {
branch 'main'
branch 'release/*'
}
}
steps {
script {
docker.withRegistry(
"https://${DOCKER_REGISTRY}",
'docker-registry-credentials'
) {
docker.image("${DOCKER_REGISTRY}/${APP_NAME}:${GIT_COMMIT_SHORT}").push()
docker.image("${DOCKER_REGISTRY}/${APP_NAME}:${GIT_COMMIT_SHORT}").push('latest')
}
}
}
}
stage('Deploy') {
when {
branch 'main'
}
steps {
script {
if (params.ENV == 'prod') {
input message: '确认部署到生产环境?', ok: '部署'
}
}
sh """
kubectl set image deployment/${APP_NAME} \
${APP_NAME}=${DOCKER_REGISTRY}/${APP_NAME}:${GIT_COMMIT_SHORT} \
-n ${params.ENV}
kubectl rollout status deployment/${APP_NAME} -n ${params.ENV}
"""
}
}
}
post {
always {
sh 'docker system prune -f || true'
}
success {
echo 'Pipeline completed successfully!'
slackSend(
color: 'good',
message: "Build Success: ${env.JOB_NAME} #${env.BUILD_NUMBER}"
)
}
failure {
echo 'Pipeline failed!'
slackSend(
color: 'danger',
message: "Build Failed: ${env.JOB_NAME} #${env.BUILD_NUMBER} - ${env.BUILD_URL}"
)
}
}
}
下一步
掌握 Pipeline 基础后,你可以继续学习:
- 分布式构建 - 配置和管理 Jenkins Agent
- 多分支 Pipeline - 自动化多分支构建
- 共享库 - 封装和复用 Pipeline 代码
- 安全配置 - 权限管理和认证配置