4. Jenkins Pipeline 基础:声明式 Pipeline 语法、Stage 与 Step 详解
声明式 Pipeline(Declarative Pipeline)是 Jenkins 2.x 引入的流水线定义方式,它提供了一种结构化、更易读的语法来定义持续交付流水线。与脚本式 Pipeline(Scripted Pipeline)相比,声明式 Pipeline 强制使用 pipeline 块作为顶层结构,并通过 agent、stages、post 等指令明确划分职责,非常适合团队协作与版本化管理。
stage 代表一个逻辑阶段,每个 step 代表该阶段内执行的最小操作单元。这种分层设计让流水线既清晰又易于调试。
4.1 声明式 Pipeline 的骨架结构
一个完整的声明式 Pipeline 由以下核心块组成:
pipeline {
agent any
stages {
stage('Build') {
steps {
echo 'Building...'
}
}
stage('Test') {
steps {
echo 'Testing...'
}
}
stage('Deploy') {
steps {
echo 'Deploying...'
}
}
}
post {
always {
echo 'This will always run'
}
success {
echo 'This will run only if successful'
}
failure {
echo 'This will run only if failed'
}
}
}
| 指令块 | 作用 | 是否必须 |
|---|---|---|
pipeline |
声明式 Pipeline 的根级容器,所有指令必须位于此块内 | 是 |
agent |
指定流水线或某个阶段在哪个执行节点上运行(如 any、label、docker) |
是 |
stages |
包含一个或多个 stage,定义流水线的执行阶段 |
是 |
stage |
单个逻辑阶段,必须包含 steps 块 |
是 |
steps |
阶段内实际执行的步骤列表,可以包含多个命令或插件调用 | 是 |
post |
流水线或阶段完成后执行的条件性操作(如清理、通知) | 否 |
post 块中定义 always 条件来执行清理操作(如删除临时文件、释放锁),避免资源泄漏。
4.2 Stage 与 Step 的深度解析
Stage(阶段)是流水线的逻辑分割点,通常对应 CI/CD 流程中的一个关键环节,例如编译、单元测试、集成测试、部署。每个 stage 必须有一个唯一的名称,并且可以嵌套 when 条件、environment 变量、tools 等指令。
Step(步骤)是 stage 内可执行的最小操作单元。Jenkins 提供了数百种内置步骤(如 sh、echo、git、docker),同时 Pipeline 插件也可以扩展自定义步骤。
stage 块内直接写 sh 命令而不包裹在 steps 块中。声明式 Pipeline 强制要求 steps 作为 stage 的直接子级,否则会报语法错误。
以下是一个包含多步骤的典型阶段示例:
stage('Build & Unit Test') {
steps {
echo 'Checking out source code...'
checkout scm
echo 'Installing dependencies...'
sh 'npm install'
echo 'Running unit tests...'
sh 'npm test'
echo 'Building artifact...'
sh 'npm run build'
}
}
4.3 声明式 Pipeline 核心指令速查
| 指令 | 用途 | 示例 |
|---|---|---|
agent |
指定执行节点 | agent { label 'linux' } |
environment |
定义环境变量(支持全局或阶段级) | environment { APP_ENV = 'production' } |
tools |
自动安装并配置工具(如 Maven、JDK) | tools { maven 'Maven-3.8' } |
when |
条件判断,决定是否执行某个阶段 | when { branch 'main' } |
parallel |
并行执行多个阶段或步骤 | parallel { stage('A'){...} stage('B'){...} } |
input |
等待用户手动确认后继续 | input message: 'Deploy to production?' |
retry |
失败后自动重试指定次数 | retry(3) { sh 'deploy.sh' } |
timeout |
设置阶段或步骤的超时时间 | timeout(time: 10, unit: 'MINUTES') |
4.4 声明式 Pipeline 执行流程示意图
下图展示了声明式 Pipeline 从触发到完成的完整执行路径,重点突出 stages 与 post 的关系:
4.5 实战:多环境蓝绿发布中的 Stage 设计
在蓝绿发布场景中,声明式 Pipeline 的 stage 设计需要兼顾环境切换、健康检查和回滚能力。以下是一个典型的蓝绿发布流水线阶段划分:
- Checkout — 从 Git 仓库拉取指定分支代码。
- Build — 编译代码并生成 Docker 镜像,打上版本标签。
- Unit Test — 执行单元测试,失败则中止流水线。
- Deploy to Blue — 将新版本部署到蓝环境(当前空闲环境)。
- Smoke Test — 对蓝环境执行冒烟测试,验证基本功能。
- Switch Traffic — 将负载均衡流量从绿环境切换到蓝环境。
- Health Check — 持续监控新环境 5 分钟,确认无异常。
- Cleanup Old — 销毁旧绿环境,释放资源。
Switch Traffic 阶段之前加入 input 步骤,要求运维人员手动确认切换,避免自动化误操作导致生产故障。
4.6 声明式 vs 脚本式 Pipeline 对比
| 对比维度 | 声明式 Pipeline | 脚本式 Pipeline |
|---|---|---|
| 语法结构 | 严格分层,使用 pipeline、stages、steps 块 |
自由 Groovy 脚本,node 块包裹 |
| 学习曲线 | 较低,适合初学者和团队标准化 | 较高,需要 Groovy 编程基础 |
| 可读性 | 强,结构一目了然 | 中等,复杂逻辑时容易混乱 |
| 灵活性 | 受限,部分复杂逻辑需借助 script 块 |
极高,可编写任意 Groovy 代码 |
| 错误处理 | 内置 post 块,条件清晰 |
需手动 try/catch/finally |
| 推荐场景 | 标准 CI/CD、多团队协作、蓝绿发布 | 复杂自定义逻辑、动态并行、高级 DSL |
4.7 使用 when 指令实现条件化阶段
在蓝绿发布中,某些阶段可能只在特定分支或特定条件下执行。声明式 Pipeline 的 when 指令可以优雅地解决这个问题:
stage('Deploy to Production') {
when {
branch 'main'
expression { return env.DEPLOY_ENV == 'production' }
}
steps {
echo 'Deploying to production environment...'
sh './deploy-prod.sh'
}
}
when 支持多种内置条件:branch、environment、expression、not、allOf、anyOf,可以组合使用实现复杂的触发逻辑。
when 指令在 stage 级别生效,不会影响 post 块。即使阶段被跳过,post 块中的条件仍然会基于流水线整体状态执行。
4.8 声明式 Pipeline 中的环境变量与 Secrets 注入
在蓝绿发布场景中,不同环境(蓝/绿)通常需要不同的配置和密钥。声明式 Pipeline 支持在 environment 块中定义变量,并配合 Jenkins Credentials 插件安全注入 Secrets:
pipeline {
agent any
environment {
// 从 Jenkins 凭据存储中安全获取
DOCKER_REGISTRY_CREDS = credentials('docker-registry-credentials')
// 普通环境变量
APP_VERSION = '1.3.0'
}
stages {
stage('Deploy to Blue') {
environment {
TARGET_ENV = 'blue'
DB_PASSWORD = credentials('blue-db-password')
}
steps {
sh '''
docker login --username=$DOCKER_REGISTRY_CREDS_USR \
--password=$DOCKER_REGISTRY_CREDS_PSW
docker-compose -f docker-compose-$TARGET_ENV.yml up -d
'''
}
}
}
}
使用 credentials() 方法时,Jenkins 会自动生成两个变量:变量名_USR(用户名)和 变量名_PSW(密码),确保敏感信息不会明文出现在日志中。
4.9 常见错误与调试技巧
- 语法错误:声明式 Pipeline 对缩进和括号敏感,建议在 Jenkins 的 Pipeline Syntax 工具中验证代码。
- 步骤未找到:某些步骤需要安装对应的 Pipeline 插件(如
docker步骤需要 Docker Pipeline 插件)。 - 环境变量未生效:检查变量作用域——
environment定义在pipeline级别为全局,定义在stage级别仅在该阶段有效。 - 并行阶段死锁:使用
parallel时确保每个分支不竞争同一资源(如文件锁、端口)。
echo "当前分支: ${env.BRANCH_NAME}" 和 echo "工作目录: ${pwd()}",快速定位上下文问题。