Jenkins中使用pipeline
- 2019 年 10 月 4 日
- 筆記
世界上第一个将流水线引入到生产中的,是福特汽车,生产效率大幅提高,大获成功。软件中是否也可以流水作业来提高效率呢?
如同工厂的生产线,每个节点只关注自己的任务,然后流向下一个节点。 我们在编排jenkins时,也可以使用这种思想。

Jenkins1.0也能实现自动化构建,但Pipeline能够将以前project中的配置信息以steps的方式放在一个脚本里,将原本独立运行于单个或者多个节点的任务连接起来,实现单个任务难以完成的复杂流程,形成流水式发布,构建步骤视图化。简单来说,Pipeline适用的场景更广泛,能胜任更复杂的发布流程。举个例子,job构建工作在master节点,自动化测试脚本在slave节点,这时候jenkins1.0就无法同时运行两个节点,而Pipeline可以。
简单来说,Pipeline是由一系列任务构成的脚本,这些任务以串行的方式执行。脚本可以用jenkins code(Jenkins插件提供支持)、bash script(Linux)、bat/powershell(Windows)等编写。
这些脚本可以保存在Jenkins的Web UI或Jenkinsfile中。基于以下三个原因,官方推荐把Pipeline保存在Jenkinsfile中
便于Pipeline脚本的审查/迭代 便于Pipeline脚本的审计跟踪 Pipeline的唯一真实来源,可以由项目组的多个成员查看和编辑。
Pipeline中的几个基本概念:
Stage: 阶段,一个Pipeline可以划分为若干个Stage,每个Stage代表一组操作。注意,Stage是一个逻辑分组的概念,可以跨多个Node。 Node: 节点,一个Node就是一个Jenkins节点,或者是Master,或者是slave,是执行Step的具体运行期环境。 Step: 步骤,Step是最基本的操作单元,小到创建一个目录,大到构建一个Docker镜像,由各类Jenkins Plugin提供。
使用Pipeline有以下好处:
代码:Pipeline以代码的形式实现,通常被列入源代码控制,使团队能够编辑,审查和迭代其传送流程。
持久:无论是计划内的还是计划外的服务器重启,Pipeline都是可恢复的。
可停止:Pipeline可接收交互式输入,以确定是否继续执行Pipeline。
多功能:Pipeline支持现实世界中复杂的持续交付要求。它支持fork/join、循环执行,并行执行任务的功能。
可扩展:Pipeline插件支持其DSL的自定义扩展 ,以及与其他插件集成的多个选项。
Pipeline的两种语法 Pipeline可以使用两种语法编写,分别是Delcarative Pipeline(声明式)和Scripted Pipeline(脚本式)。声明式的语法出现比脚本式语法晚,目的是更容易地编写Pipeline,前者结构性更强,而后者则更简洁,但它更像一门编程语言,因此对使用者的编程知识要求更高。
Declarative Pipeline
声明式Pipeline必须包含在名为pipeline的语句块中,典型的声明式Pipeline语法如下:
pipeline { agent any environment { } stages { stage("Build") { steps { sh 'echo Building... } } stage("Test") { steps { sh 'echo Testing...' } } } }
一个合法的Pipeline遵从下面的几个原则:
顶层语句块只能是pipeline {} 每一个语句只能写在一行,没有分隔符,例如分号“;” 结构块只能是Sections、Directive、steps或者赋值语句其中之一 所有的属性引用都被视为没有参数的方法调用,例如input等同于input()
Sections
Section可以包含一个或多个Directive、steps,常见的Section有
agent
agent指的是一台远程计算机,或者一个docker服务,通常是一台Jenkins slave服务器。agent必须在pipeline{}块里面的顶层中定义。stage块中可选,如果pipeline块中agent的值为none,则每一个stage中都必须设置agent的值。
它的值可以是
any none label node label customWorkspace docker dockerfile post
post 是一个后处理阶段,取决于post的位置,如果post定义在pipeline块中,则所有stage构建完毕,post中的代码被执行,如果post定义在某个stage中,则该stage构建完毕之后post被执行。
post中的值有:
always changed fixed regression aborted failure success unstable cleanup
例如:
pipeline { agent any stages { stage('stage 1') { agent any } post { always { echo 'I will always execute after stage 1 finish' } } } post { always { echo 'I will always execute' } } }
stages
stages可以包含一个或多个stage,一个stage指一个构建阶段 代表stages中的每一个阶段,stage中可以嵌套包含stages,嵌套stages中的stage属于串行(Sequential)任务,即串行stage不能再包含parallel或stages。
pipeline { agent any stages { stage { agent any stages { stage("nested stage") { //此stage中不能继续包含parallel或stages } } } } }
steps steps里面包含真正的可执行脚本
environment 用于定义环境变量
pipeline { agent any environment { BUILD_VERSION = '1.0' } stages { stage('Get The Evn'){ steps { sh 'pintenv' //or sh 'env' } } } }
parameters 定义参数,可定义的参数类型有两种,分别是字符串和布尔值。parameters中定义的参数可以在steps中通过params对象引用。
pipeline { agent any parameters { string(name: 'PERSON', defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?') } stages { stage('Example') { steps { echo "Hello ${params.PERSON}" } } } }
triggers 触发器,可定义的触发器类型如下:
cron 定时执行 pollSCM 定时拉取仓库中的源码 upstream 某个上层项目构建完毕触发
pipeline { agent any triggers { cron('H */4 * * 1-5') } stages { .... } }
parallel 定义并行任务,并行任务通常用于多分支Pipeline构建任务中
pipeline { agent any stages { stage('Non-Parallel Stage') { steps { echo 'This stage will be executed first.' } } stage('Parallel Stage') { when { branch 'master' } failFast true parallel { stage('Branch A') { agent { label "for-branch-a" } steps { echo "On Branch A" } } stage('Branch B') { agent { label "for-branch-b" } steps { echo "On Branch B" } } stage('Branch C') { agent { label "for-branch-c" } stages { stage('Nested 1') { steps { echo "In stage Nested 1 within Branch C" } } stage('Nested 2') { steps { echo "In stage Nested 2 within Branch C" } } } } } } } }
Scripted Pipeline
Scripted Pipeline对语法的要求比较宽松,顶层可以是node,也可以是stage。node可以嵌套stage,stage反过来也可以嵌套node。典型的脚本式Pipeline语法如下:
node { //node可以指定label 例如 node ('label_name') {} stage("Build") { sh 'echo Building...' } stage("Test"){ sh 'echo Testing...' } }
基础语法 相比起Declarative Pipeline语法中使用块或指定的形式定义构建过程,Scripted Pipeline则是使用方法(函数)
node 这里的node对应于Declarative Pipeline的agent,用于指定构建步骤应该在哪个构建服务器执行。
node('master'){ stage('Build'){ echo 'Building...' } }
node可以嵌套stage,也可以被stage嵌套
stage('Build'){ node('linux'){ sh 'echo building in linux' } node('windows'){ bat 'echo building in windows' } }
withEnv withEnv方法和environment语句块对应,用于定义环境变量。
try catch finally 对应于post后处理语句块
try{ stage('Build'){ echo 'do something' } }catch(err){ }finally{ }
properties 可用于添加参数,有Delcarative Pipeline的parameters的作用,也用于建立触发器
parameters
properties([parameters([string(name: 'username', defaultValue: 'jenkins', description: 'remote user')])]) node { stage('Build'){ echo "${params.username}" } }
triggers
node { properties([pipelineTriggers([cron('H */1 * * *')])]) stage('Build') { echo 'Building...' } }
parallel 语法和Declarative Pipeline有点不一样,并行任务之间使用逗号”,“分隔。
stage('Test') { parallel linux: { node('linux') { checkout scm try { unstash 'app' sh 'make check' } finally { junit '**/target/*.xml' } } }, windows: { node('windows') { /* .. snip .. */ } } }
OK, 看起来需要记住很多东西,我这里有两个方法,减少记忆。 一是用它的语法帮助; 点击job页面的Pipline syntax

可以看到各种关键字,还可以测试。
二是使用blue ocean blue ocean是一个为Pipeline重新设计的Web UI。jenkins默认没有安装这个插件,因此使用之前需要安装该插件,只需要在插件管理中搜索Blue Ocean,勾选安装即可,安装的过程会连同其他依赖插件一起安装。 安装完毕重启,左侧面板会自动出现Blue Ocean的菜单. 然后就可以图形化编辑工作流:

编辑完后会生成Jenkinsfile.
OK, 用一个简单的实践,来巩固这些知识点。 新建一个“流水线”的job。 配置一下自己的jenkins file

运行以后,结果是这样的。

去blue ocean中看看

如果有不明白的地方,可以去官方文档看看:https://jenkins.io/zh/doc/tutorials/create-a-pipeline-in-blue-ocean/
如果掌握好了Jenkins pipline, CI/CD 甚至 Devops就更容易上手了。
更多精彩,请关注微信公众号:python爱好部落