4、Jenkins Pipeline语法:声明式Pipeline vs 脚本式Pipeline、Pipeline基本结构、Stage与Step设计、Post条件处理
好,咱们今天聊聊 Jenkins Pipeline 的语法。说实话,Pipeline 是 Jenkins 的核心能力,没有它,Jenkins 就是个普通的手动构建工具。我刚开始接触时也被两种语法搞晕过——声明式和脚本式,到底选哪个?别急,咱们一个一个拆开看。
4.1 声明式 Pipeline vs 脚本式 Pipeline
这两种语法,说白了就是「写配置」和「写代码」的区别。
声明式 Pipeline:结构固定,像填表格。你只需要告诉 Jenkins「我要做什么」,它帮你管流程。适合大多数场景,尤其是团队里不全是开发人员的情况。
脚本式 Pipeline:更灵活,像写程序。你可以用 Groovy 语言写逻辑判断、循环、异常处理。适合复杂场景,比如动态生成 Stage。
我个人习惯:能用声明式就用声明式。为什么?因为可读性强,团队成员一看就懂。我在项目中遇到过,脚本式 Pipeline 写得太灵活,后来维护的人根本看不懂,最后全重写了。
核心区别一句话:声明式是「框架内填空」,脚本式是「自由发挥」。新手建议从声明式入手。
来看个对比示例:
// 声明式 Pipeline
pipeline {
agent any
stages {
stage('Build') {
steps {
echo 'Building...'
}
}
}
}
// 脚本式 Pipeline
node {
stage('Build') {
echo 'Building...'
}
}
看出来了吗?声明式多了 pipeline、stages 这些关键字,结构更清晰。脚本式就一个 node 块,剩下的全靠 Groovy 代码。
4.2 Pipeline 基本结构
声明式 Pipeline 的结构其实很固定,就像盖房子有地基、柱子、屋顶一样。我把它拆成几个核心部分:
| 组成部分 | 作用 | 是否必须 |
|---|---|---|
| pipeline | 最外层容器,所有内容都包在里面 | 是 |
| agent | 指定在哪个节点上运行(比如用哪个 Jenkins Slave) | 是 |
| stages | 包含所有 Stage 的集合 | 是 |
| stage | 单个阶段,比如「编译」「测试」「部署」 | 是 |
| steps | 每个 Stage 里具体执行的命令 | 是 |
| post | Pipeline 或 Stage 执行后的处理逻辑 | 否 |
| environment | 定义环境变量 | 否 |
| options | 配置 Pipeline 的选项(如超时、重试) | 否 |
嗯,这里要注意:agent 可以放在全局,也可以放在某个 Stage 里。比如编译用 Linux 节点,测试用 Windows 节点,完全没问题。
pipeline {
agent none // 全局不指定,让每个 Stage 自己指定
stages {
stage('Build') {
agent { label 'linux' }
steps {
sh 'make'
}
}
stage('Test') {
agent { label 'windows' }
steps {
bat 'test.bat'
}
}
}
}
4.3 Stage 与 Step 设计
Stage 和 Step 是 Pipeline 的灵魂。Stage 是「阶段」,Step 是「步骤」。你想想看,一个完整的 CI/CD 流程,其实就是把多个 Stage 串起来。
Stage 设计原则:
- 每个 Stage 只做一件事。别把编译和测试写在一个 Stage 里,否则失败了都不知道是哪步出的问题。
- Stage 名称要见名知意。用
Build、Unit Test、Integration Test、Deploy to Staging这种,别用Step1、Step2。 - 可以并行执行。比如单元测试和代码扫描可以同时跑,用
parallel关键字。
Step 设计技巧:
- 每个 Step 尽量短小精悍。一个 Step 里写几十行 shell 脚本?那还不如直接写个脚本文件。
- 善用 Jenkins 插件提供的 Step。比如
sh、bat、git、docker,别自己造轮子。 - 我建议把常用的 Step 封装成共享库,团队里直接调用,省得重复写。
小技巧:Stage 里可以用 when 条件判断,比如只在 master 分支才执行部署。这样能省不少时间。
stage('Deploy to Production') {
when {
branch 'master'
}
steps {
echo 'Deploying to production...'
}
}
4.4 Post 条件处理
Post 是 Pipeline 里的「善后处理」。不管构建成功还是失败,你总得做点什么吧?比如发通知、清理环境、保存日志。
Post 支持的条件有这些:
| 条件 | 触发时机 |
|---|---|
| always | 无论结果如何,都会执行 |
| success | 只有成功时才执行 |
| failure | 只有失败时才执行 |
| unstable | 构建结果不稳定时(比如测试有失败但没崩溃) |
| changed | 当前构建结果与上一次不同时 |
| aborted | 用户手动取消时 |
我曾经踩过一个坑:在 Post 里写清理逻辑,结果忘了加 always,导致构建失败时临时文件没删掉,下次构建直接报磁盘空间不足。嗯,从那以后我养成了习惯——清理操作一定要用 always。
post {
always {
echo '清理临时文件...'
cleanWs() // 清理工作空间
}
success {
echo '构建成功,发送通知'
// 调用通知插件
}
failure {
echo '构建失败,记录日志'
// 保存构建日志到外部存储
}
changed {
echo '构建状态发生变化'
// 比如从成功变成失败,或者从失败变成成功
}
}
注意:Post 可以放在 Pipeline 级别(全局),也可以放在 Stage 级别(只针对某个阶段)。全局 Post 在全部 Stage 执行完后触发,Stage 级别的 Post 在该 Stage 结束后立即触发。
举个例子,你可以在 Deploy 这个 Stage 的 Post 里单独处理部署失败的情况,而不影响其他 Stage 的 Post 逻辑。
stage('Deploy') {
steps {
// 部署操作
}
post {
failure {
echo '部署失败,回滚版本'
// 执行回滚脚本
}
}
}
好了,Pipeline 语法的核心内容就这些。声明式还是脚本式?我建议你先用声明式,等遇到复杂需求再切换到脚本式。Stage 和 Step 的设计,记住「单一职责」原则。Post 条件处理,别忘了 always 清理环境。
下一章咱们聊聊 Jenkins 的凭证管理和安全配置,这可是生产环境的重中之重。