4. Jenkins Pipeline 基础:声明式与脚本式 Pipeline 的区别,第一个 Hello World 流水线

说实话,我刚接触 Jenkins Pipeline 那会儿,也被它整得挺懵。明明都是写脚本,怎么还分两种写法?后来踩了几个坑才明白,这两种风格说白了就是「约定大于配置」和「自由发挥」的区别。这一节,我带你一次搞懂它们。

4.1 为什么需要 Pipeline?

以前 Jenkins 的 Job 配置,全在 Web 界面里点点点。你想想看,一旦项目多了,每个 Job 的配置都得手动维护,版本控制?不存在的。有一次我半夜升级 Jenkins 插件,结果所有 Freestyle job 全崩了——因为某个参数在新版里改了名称,可界面配置根本不会告诉我。

Pipeline 的出现就是为了解决这个痛点——把构建、测试、部署的流程用代码写出来,然后塞进 Git 仓库。好处是:可版本控制、可复用、可审核。再也不用担心「谁手抖改了一个配置,构建就炸了」。

4.2 声明式 Pipeline vs 脚本式 Pipeline

先看一张对比图,这是我画的结构,帮你快速理解两者的定位。

Jenkins Pipeline 两大流派 声明式 Pipeline (Declarative) 脚本式 Pipeline (Scripted) 特点 固定结构:pipeline { agent { ... } stages { stage('') { steps { ... } } } } 仅支持预定义指令,不易出错 语法检查更严格,适合团队标准 特点 本质上是 Groovy 脚本,node { stage(''){ ... } } 高度灵活,可以写条件、循环、异常处理 调试难度稍高,容易写出难以维护的脚本 声明式示例 pipeline { agent any stages { stage('Build') { steps { echo 'building...' } } 脚本式示例 node { stage('Build') { echo 'building...' } 倾向:新手/团队首选声明式;高级定制/复杂逻辑选脚本式

4.3 两者的核心区别

对比维度 声明式 Pipeline 脚本式 Pipeline
代码结构 固定的 pipeline 块 + stages + steps 任意 Groovy 代码,node() 包裹即可
错误处理 只能通过 post 块处理 try-catch-finally 任你写
语法检查 Jenkins 会严格校验结构,写错直接报错 运行时才知道,容易在半夜炸
适用场景 标准 CI/CD,团队协作,新人友好 需要动态生成阶段、复杂条件判断、调用外部 API
可读性 高,一眼看出流程 中~低,取决于写的人的 Groovy 水平

我个人习惯:新项目 90% 用声明式,只有遇到了「需要根据 Git 分支动态决定跑多少个并行测试」这种场景,才改用脚本式。别为了炫技全写脚本式,后期维护的人会骂娘。

4.4 第一个 Hello World 流水线

废话不多说,直接上手。我们用声明式 Pipeline 写一个最简单的流水线:输出一行 "Hello World"。

pipeline {
    agent any
    stages {
        stage('Hello') {
            steps {
                echo 'Hello World'
            }
        }
    }
}

这段代码每一个单词都认识,但结合起来……你可能会问:「agent any 是啥?」

简单解释一下:

  • pipeline { ... } 是声明式 Pipeline 的根容器,所有逻辑都要塞进去。
  • agent any 告诉 Jenkins:「随便给我一个可用的节点(master 或 agent)来跑这个流水线。」如果你有专门的 build 服务器,可以改成 agent { label 'linux' }。
  • stages 块里面放一个或多个 stage,每个 stage 代表一个阶段。这里我们只定义了一个名叫 'Hello' 的阶段。
  • steps 里面是具体的操作步骤。这里只有一句 echo 'Hello World',打印日志。

实践提示:你可以在 Jenkins 的 Web 界面里新建一个 Pipeline 类型的 Job,然后在 Pipeline 定义中选择「Pipeline script」,直接把上面的代码粘贴进去,点「Build Now」就能看到控制台输出 "Hello World"。

4.5 脚本式版本长什么样?

作为对比,同样功能用脚本式写出来是这样的:

node {
    stage('Hello') {
        echo 'Hello World'
    }
}

看起来更短是吧?但注意,脚本式没有「pipeline」这个关键字,取而代之的是 node { }。这个 node 就指明了「这段代码要在哪个节点上执行」,作用等价于声明式里的 agent。你甚至可以在脚本式里写多个 node 块,在不同节点上跑不同任务——声明式里这点就做不到(除非用并行指令配合 agent 切换)。

4.6 选择哪种?我的一点经验

  • 如果你在带团队,我建议强制用声明式。因为它的结构固定,新人写出来的流水线不会太离谱,review 起来也快。
  • 如果你自己搞一个单机玩具项目,随便用脚本式也没关系,反正就你一个人看。
  • 我曾经踩过一个坑:用脚本式写了一个多阶段并行部署的流水线,里面嵌套了 3 层 parallel 和 try-catch,结果某个节点网络闪断,异常只被内层捕获,外层没正确处理,导致整个 Job 显示成功但实际部署失败。后来改成声明式配合 post { failure { ... } } 统一处理,再也没出过这种诡异问题。

特别注意:无论你选哪种,都要把 Pipeline 脚本放到 Git 仓库里(一般在项目根目录下叫 Jenkinsfile),然后 Jenkins Job 配置里选择「Pipeline script from SCM」。这样每次提交代码,流水线会自动更新。别再手动复制粘贴了——我见过有人把生产环境的 Jenkinsfile 直接在网页端改了没保存……

4.7 你的第一个作业

看完这些,我建议你立刻动手:

  1. 在 Jenkins 中新建一个 Pipeline Job。
  2. 把第一节的 Hello World 声明式代码粘贴进去,构建一次,观察控制台输出。
  3. 试着在 steps 里多加一行 echo '你好,Pipeline!',再跑一次。
  4. 改一下 stage('Hello') 的名字,比如 stage('Greeting'),感受一下 stage 如何影响 Blue Ocean 的展示。

做完这些,你就已经跨过了 Pipeline 的第一道门槛。咱们下个知识点见——不过这次你先别急,把 Hello World 跑通了再说。