自从 Jenkins 2.0 版本升级之后,支持了通过代码(Groovy DSL)来描述一个构建流水线,灵活方便地实现持续交付,大大提升 Jenkins Job 维护的效率,实现从 CI 到 CD 到转变。而在2016 Jenkins World 大会上,Jenkins 发布了1.0版本的声明式流水线 - Declarative Pipeline,目前已经到发布了1.2版本,它是一种新的结构化方式定义一个流水线。今天我们一起对比这两种定义流水线的方式以及特性。
Pipeline 特性 - Pipeline As Code
Jenkins 从根本上讲是一种支持多种自动化模式的自动化引擎。Pipeline 为其添加了一套强大的自动化工具,支持从简单的持续集成到全面的持续交付。Jenkins Pipeline 特性如下:
代码:Pipeline 以代码的形式描述,通常存储于源代码控制系统,如 Git,使团队能够编辑,审查和迭代其流程定义。
持久性:Pipeline 可以在计划和计划外重新启动 Jenkins Master 管理时不被影响。
可暂停:Pipeline 可以选择停止并等待人工输入或批准,然后再继续 Pipeline 运行。
多功能:Pipeline 支持复杂的项目持续交付要求,包括并行分支/连接,循环和执行 Job 的能力。
可扩展:Pipeline 插件支持其 DSL 的自定义扩展以及与其他插件集成。
基于 Jenkins Pipeline,用户可以在一个 JenkinsFile 中快速实现一个项目的从构建、测试以到发布的完整流程,并且可以保存这个流水线的定义。
下面的流程图是在 Jenkins Pipeline 中建模的一个持续交付方案的示例:
Pipeline 基本概念
Node: 一个 Node 就是一个 Jenkins 节点,或者是 Master,或者是 Agent,是执行 Step 的具体运行环境,Pipeline 执行中的大部分工作都是在一个或多个声明 Node 步骤的上下文中完成的。
Stage: 一个 Pipeline 可以从逻辑上划分为若干个 Stage,每个 Stage 代表一组操作,如:Build、Test、Deploy。注意,Stage 是一个逻辑分组的概念,可以跨多个 Node。
Step: Step 是最基本的操作单元,小到执行一个 Shell 脚本,大到构建一个 Docker 镜像,由各类 Jenkins Plugin 提供,当插件扩展Pipeline DSL 时,通常意味着插件已经实现了一个新的步骤。
另外在 Jenkins Pipeline 中定义的 Stage(各个阶段的逻辑划分),Jenkins 提供了 Stage View 插件,按照 Stage 逻辑划分任务,对用户透明化、可视化展示流水线的执行,如下图:
Scripted Pipeline
上图通过 Jenkinsfile 定义了流水线的各个阶段(不仅限这几个阶段):构建,测试以及发布,在每个阶段可以执行相应的任务,而在 Scripted Pipeline 中,用户可以使用 Groovy 语法脚本来自定义流程控制,如下:
CurrentBuild 可以获取档次执行的结果,可以用于判读后续流程走向,Jenkins 还提供了更多内置环境变量以及 DSL 对象,方便我们操作流水线任务,如:BUILD_ID、JOB_NAME、BRANCH_NAME、CHANGE_ID 等等,可参考Global Variable。这种方式受 Jenkins 的限制较少,我们可以灵活控制和定义一个流水线,甚至我们可以在 JenkinsFile 中定义多个 Groovy 函数来扩展 Jenkins Pipeline 的能力。
Declarative Pipeline
同样的,上图定义了流水线的各个阶段,Declarative Pipeline 这种方式受 Jenkins 限制较多,需使用预定义的结构。Jenkins 已经预置了很多描述流水线的结构,可以在没有 Groovy 基础上快速建立流水线,当然在 Declarative Pipeline 同样支持写 Groovy 脚本,但官方不推荐把脚本直接写在流水线中,应该把这些逻辑定义在 Shared Libraries 中。
如下:
Declarative Pipeline 语法
下面介绍几个重点 Declarative Pipeline 语法:
定义执行环境
通过 Agent 来定义 Pipeline 的执行环境,在每个 Pipeline,Agent 是必需存在的。Agent 也可以用 Label 指定具体的 Jenkins Slave Node,并且每个 Stage 可以单独指定 Agent,灵活调度资源以及运行环境。
环境变量
可以定义为全局的,也可以为 Stage 来定义。
已定义的环境变量,可以通过 Env 来访问,与 Scripted Pipeline 一样,可以访问 Jenkins 预置的环境变量。
参数
可以通过 Params 对象来访问构建时的参数。如:
流程控制
可以通过 When 语法控制流程走向,判断环境变量或自定义表达式,是否执行某一个 Stage,同时 Anyof, Allof 进行逻辑运算,Anyof 对应或运算,Allof 对应与运算。
超时、重试机制
资源的清理工作 & 结束后操作
使用 Post 来完成一些资源的清理工作。其和 Stages 平级:
清理结束阶段也可以执行一个邮件通知:
并发 Stages
Declarative Pipeline 1.2 版本对并发语法做了升级:
其中 FailFast 可以控制如果并发的任务的其中一个失败,立即结束流水线,执行清理结束任务。
总结
Scripted Pipeline 和 Declarative Pipeline 两种流水线定义的主要区别在于语法和灵活性上, Declarative Pipeline 语法要求更严,需使用 Jenkins 预定义的DSL 结构,使用简单; Scripted Pipeline 受限很少,限制主要在 Groovy 的结构和语法,大家可以根据个人或企业的情况选择两种方式,比如如果公司没有 Groovy 技术栈,可以考虑直接使用 Declarative Pipeline, 学习曲线低,可以快速上手,并且新的 Blue Ocean Editor 插件可以帮助我们可视化的创建一个流水线,如果对 Groovy 非常熟悉,那 Scripted Pipeline 是一个不错的选择。