世界上第一个将流水线引入到生产中的,是福特汽车,生产效率大幅提高,大获成功。软件中是否也可以流水作业来提高效率呢?
如同工厂的生产线,每个节点只关注自己的任务,然后流向下一个节点。 我们在编排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的唯一真实来源,可以由项目组的多个成员查看和编辑。
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,前者结构性更强,而后者则更简洁,但它更像一门编程语言,因此对使用者的编程知识要求更高。
声明式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()
Section可以包含一个或多个Directive、steps,常见的Section有
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可以包含一个或多个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对语法的要求比较宽松,顶层可以是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爱好部落