Jenkins2.x 实践指南--pipeline语法讲解

Jenkins pipeline 是基于Groovy语言实现的一种DSL(领域特定语言),用于描述整条流水线是如何进行的。

1. pipeline的组成

1.1最简结构

以下从pipeline最简结构----Hello World 查看Jenkins file文件的构成:

pipeline {
    agent any

    stages {
        stage('Hello') {
            steps {
                echo 'Hello World'
            }
        }
    }
}
  • pipeline:代表整条流水线,包含整条流水线的逻辑

  • stage:代表流水线的阶段。每个阶段都必须有名称。本例中,Hello就是此阶段的名称

  • stages:流水线中多个stage的容器。stages至少包含一个stage

  • steps:代表阶段中的一个或多个具体步骤(step)的容器。steps至少包含一个步骤。本例中的echo就是一个步骤。在一个stage中有且只有 一个steps

  • agent:指定流水线的执行位置(Jenkins agent)。流水线中的每个每段都必须在某个地方(物理机、虚拟机或Docker 容器)执行。agent部分即指定具体在哪里执行。

    以上的每一个部门都是必需的,少任何一个,Jenkins 都会报错。

1.2 步骤(Steps)

pipeline基本结构决定pipeline整体流程,但真正“做事”的还是pipeline中的每一个步骤。步骤是pipeline中已经不能在拆分的最小操作。

步骤是可插拔的。现有的插件不用修改或者只需要简单修改,就能在Jenkins pipeline中当成一个步骤来使用,大大降低了从现有依赖界面的插件过渡到pipeline中步骤的成本。

2. post部分

post {
    failure {
        mail to: 'team@example.com', subject: 'The Pipeline failed :('
    }  
}

post 部分是在整个pipeline或者阶段完成后一些附件的步骤。

post步骤是可选的,所以并不包含在pipeline最简结构中,但并不代表它作用不大。

根据pipeline或阶段的完成状态,post部分分成多种条件块,包括

  • always:不论当前完成状态是什么,都执行。
  • changed:只要当前完成状态与上一次完成状态不同就执行。
  • fixed:上一次完成状态为失败或者不稳定(unstable),当前完成状态 为成功时执行。
  • regression:上一次完成状态为成功,当前完成状态为失败、不稳定或者中止(aborted)时执行。
  • aborted:当前执行结果是中止状态时(一般为人为中止)执行。
  • failure:当前状态为完成失败时执行。
  • success:当前完成状态为成功时执行。
  • unstable:当前完成状态为不稳定时执行。
  • cleanup:清理条件块。不论当前完成状态是什么,在其他所有条件块执行完成后都执行。post部分可以同时包含多种条件块。

post部分完整示例:

pipeline {
    agent any

    stages {
        stage('build') {
            steps {
                echo "build stage"
            }

            post {
                always {
                    echo "stage post always"
                }
            }
        }
    }
    post {
        changed  {
            echo "pipeline post changed"
        }

        always {
            echo "pipeline post always"
        }
        
        success {
            echo "pipeline post success"
        }
        
        //....
    }
}

3. pipeline 支持的指令

基本结构满足不了现实多变的需求,Jenkins pipeline 通过各种指令(directive)来丰富自己。指令可以被理解为对Jenkins pipeline基本结构的补充。

Jenkins pipeline 支持的指令有:

  • environment:用于设置环境变量,可定义在stage或pipeline部分。

  • tools:可定义在stage或pipeline部分,它会自动下载并安装我们我们执行的工具,并讲其加入PATH变量中。

  • input: 定义在stage部分,会暂停pipeline,提示你输入内容。

  • options: 用于配置Jenkins pipeline本身的选项,比如options{retry(3)} 指当pipeline失败时再重试2次。options指令可定义在stage或pipeline部分。

  • parallel:并行执行多个step。在pipeline插件1.2版本后,parallel开始支持对多个阶段进行并行执行。

  • parameters:与input不同,parameters是执行pipeline前传入的一些参数。

  • triggers:用于定义执行pipeline的触发器。

  • when: 当满足when定义的条件时,阶段才执行。

    Action:在使用指令时,需要注意的时每个指令都有自己的“作用域”。

4.配置pipeline本身

options指令用于配置整个Jenkins pipeline本身的选项。根据具体的选项不同,可以将其放在pipeline块或stage块中。

常见的几个选项:

  • buildDiscarder:保存最近历史构建记录的数量。当pipeline执行完成后,会在硬盘上保存制品和构建执行日志,如果长时间不清理会占用大量空间,设置次选项后会自动清理。此选项只能在pipeline下的options中使用。示例如下:

    options {
      buildDiscarder(logRotator(numToKeepStr: '10'))
    }         
    
  • checkoutToSubdirectory: Jenkins从版本控制库拉取源码时,默认检出到工作空间的根目录中,此选项可以指定检出到工作空间的子目录中,示例如下:

    options {
        checkoutToSubdirectory('subdir')
    } 
    
  • disableConcurrentBuilds: 同一个pipeline,Jenkins默认时可以同时执行多次的,该选项是为了禁止pipeline同时执行。示例如下:

    options {
        disableConcurrentBuilds()
    }
    

    在某些pipeline存在抢占资源或者调用冲突的场景下,此选项非常有用。设置此选项后,该次执行为结束时,下一次待执行的pipeline显示在pending状态。

  • newContainerPerStage: 当agent为docker 或dockfile时,指定在同一个Jenkins节点上,每个stage都在分别运行在一个新的容器中,而不是所有stage都运行在同一个容器中。

    options {
        newContainerPerStage()
    }
    
  • retry:当发生失败时进行重试,可以指定整个pipeline的重试次数。需要注意的是,这个次数是指总次数,包含第一次失败。以下例子总共会执行四次。当使用retry选项时,options可以被放在stage块中。

    pipeline {
        agent any
    
        options {
            retry(4)
        }
    
        stages {
            stage('build') {
                steps {
                    echo "ok"
                    error("emmm...")
               }
            }
        }
    }
    
  • timeout:如果pipeline执行时间过长,超出设置的timeout时间,Jenkin将中止pipeline。

    单位有:SECONDS(秒)、MINUTES(分)、HOURS(小时)。

    当使用timeout选项时,options可以被放在stage块中。

    options {
        timeout(time: 6, unit: 'HOURS')
    }
    

    设置次选项后,强迫团队去处理执行是按过长的pipeline,从而优化pipeline的反馈周期。通常将timeout设置为10分钟就可以了

5.在声明式pipeline中使用脚本

在使用声明式pipeline时,直接在steps块中写if-else,或者定义一个变量,Jenkins都会报错。也就是不能再steps块中写Groovy代码。

Jenkins pipeline专门提供了一个script步骤,能在script步骤中像写代码一样写pipeline逻辑。

下面的例子是分别在不同的浏览器上跑测试。

pipeline {
    agent any
    
    stages {
        stage('Example') {
            steps {
                script {
                   def browers = ['chrome', 'firefox']
                   for(int i = 0; i < browers.size(); ++i){
                        echo "Testing the ${browers[i] brower"
                        }
                   }
                }
            }
        }
    }

在script块中其实就是Groovy代码。如果在script步骤中写了大量的逻辑,则说明你应该把这些逻辑拆分到不同的阶段,或者放到共享库中。共享库是一种扩展Jenkins pipeline的技术。

6. pipeline内置基础步骤

6.1 文件目录相关步骤

deleteDir:删除当前目录

deleteDir是一个无参步骤,删除的是当前工作目录。通常它与dir步骤一起使用,用于删除指定目录下的内容。

dir:切换到目录

默认pipeline工作在工作目录空间下,dir步骤可以让我们切换到其他目录。使用方法如下:

{
    dir("/var/logs"){
        deleteDir()
    }
}
fileExists: 判断文件是否存在。

如果参数是相对路径,则判断在相对当前工作目录下,该文件是否存在,结果返回布尔类型。

fileExits('/tmp/a.jar')判断/tmp/a.jar文件是否存在。

isUnix:判断是否在类UNIX系统

如果当前pipeline运行在一个类UNIX系统上,则返回true

pwd:确认当前目录

pwd与Linux的pwd命令一样,返回当前所在目录。它有一个布尔类型的可选参数:tmp。如果参数值为true,则返回与当前工作空间关联的临时目录。

writeFile:将内容写入指定文件中

writeFile支持的参数有:

  • file:文件路径,可以是绝对路径,也可以是相对路径。
  • text:要写入的文件内容。
  • encoding(可选):目标文件的编码。如果为空,则和操作系统系统编码方式保持一致。
readFile:读取文件内容

读取指定文件的内容,以文本返回。readFile支持的参数书有:

  • file:文件路径,可以是绝对路径,也可以是相对路径。
  • encoding:读取文件时使用的编码

示例如下:

{
    //"amvua2lucyBib299r" 是"jenkins book" 进行Base64编码后的值
    writeFile(file: "base64file", text: "amvua2lucyBib299r", encoding;'Base64')
    def content = readFile(file: "base64file",encoding: 'UTF-8')
    echo "${content}"
    //打印结果: jenkins book
}

6.2 产出相关步骤

stash:保存临时文件

stash步骤可以将一些文件保存起来,以便被同一次构建的其他步骤或阶段使用。如果这个pipeline的所有阶段在同一台机器上执行,则说他是步骤是多余的。所以,通常需要stash的文件都是要跨Jenkins node使用的。

stash步骤会将文件存储在tar文件中,对于大文件的stash操作将会消耗Jenkins master的计算资源。Jenkins官方文档推荐,当文件大小为5~100MB时,应考虑使用其他替代方案。

stash步骤的参数列表如下:

  • name:字符串类型,保存文件的集合的唯一标识。
  • allowEmpty:布尔类型,允许stash内容为空。
  • excludes:字符串类型,将哪些文件排除。如果排除多个文件,则使用都好分割。留空代表不排除任何文件。
  • includes:字符串类型,stash哪些文件,留空代表当前文件夹下的所有文件。
  • useDefaultExcludes:布尔类型,如果是true,则代表使用Ant风格路径默认排除文件列表

除了name参数,其他 参数都是可选的。excludes和includes使用的是Ant风格路径表达式。

unstash:取出之前stash的文件

unstash步骤只有一个name参数,即stash时的 唯一标识。通常stash和unstash步骤同时使用。

示例如下:

pipeline {
    agent any
    stages {
        stage('stash'){
            agent { label "master" }
            steps {
                writeFile file: 'a.txt',text: "$BUILD_NUMBER"
                stash(name: "abc",includes: "a.txt")
            }
        }
        stage('unstash')
        {
            agent {label "node2" }
            steps{
                unstash("abc")
                def content = readFile("a.txt")
                echo "${content}"
            }
        }
    }
}

stash步骤在master节点上执行,而unstash步骤在node2节点上执行

6.3 命令相关步骤

Pipeline:Nodes and Processes插件提供的步骤。它是Pipeline插件的一个组件,基本不需要单独安装。

sh: 执行shell命令

sh步骤支持的参数有:

  • script:将要执行的shell脚本,通常在类UNIX系统上可以是多行脚本。
  • encoding:脚本执行后输出日志的编码 ,默认值为脚本运行所在系统的编码。
  • returnStatus:布尔类型,默认脚本返回的是状态码,如果是 一个非零的状态码,则会引发pipeline执行失败。如果returnStatus参数为true,则不论状态码是什么,pipeline的执行都不会受影响。
  • returnStdout:布尔类型,如果是true,则任务的标准输出将作为步骤的返回值,而不是打印到构建日志中(如果有错误,则依然会打印到日志中)。除了script参数,其他参数都是可选的。

returnStatus和returnStdout参数一般不会同时使用,因为返回值只能有一个。如果同时使用,则只有returnStatus参数生效。

bat、powershell步骤

bat步骤执行的是WIndows的批处理命令。powershell步骤执行的是PowerShell脚本,支持3+版本。这两个步骤支持的参数与sh步骤一样。

6.4 其他步骤

error:主动报错,中止当前pipeline

error步骤的执行类似于抛出一个异常。它只有一个必须参数:message。通常省略参数:error("There is an error")。

tool:使用预定义的工具

如果在Global Tool Configuration(全局工具配置)中配置了 工具,可以通过tool步骤得到工具路径。

steps {
    script {
        def t = tool name: 'docker', type: 'org.jenkinsci.plugins.docker.commons.tools.DockerTool'
        echo "${t}" //将打印 /var/lib/docker
    }
}

tool步骤支持的参数有:

  • name:工具名称

  • type(可选):工具类型,指该工具安装类的全路径类名。

每个插件的type值都不一样,而且绝大多数的文档根本不屑type值。除了到该插件的源码中查找,还有一种方法可以让我们快速找到type值,就是前往 Jenkins pipeline代码片段生成器中生成该 tool不走的代码即可。

timeout:代码块超时时间

为timeout步骤闭包内运行的代码设置超时时间限制。如果超时,将。抛出一个 org.jenkinsci.plugins.workflow.steps.FlowInterruptException异常。timeout步骤支持如下参数:

  • time:整型,超时时间。
  • unit(可选):时间单位,支持的值有NANOSESECONDS、MICROSECONDS、MILLISECONDS、SECONDS、MINUTES(默认)、HOURS、DAYS
  • activity(可选):布尔类型,如果值为true,则只有当日志没有活动后,才真正算作超时。
waitUntil:等待条件满足

不断重复waitUntil块内的代码,直到条件为true。waitUntil不负责处理块内代码的异常,遇到异常时直接向外抛出。waitUntil步骤最好与timeout步骤共同使用,避免死循环。示例如下:

timeout(50) {
    waitUntil {
        script {
            def r = sh script: 'curl http://exmaple', returnStatus:true
            return( r==0 )
        }
    }
}
retry:重复执行块

执行N次闭包内的脚本。如果其中某次执行抛出异常,则只中止本次执行,并不会中止整个retry的执行。同时,在执行retry的过程中,用户是无法中止pipeline的。

steps {
    retry(20) {
        script {
            sh script: 'curl http://exmaple', returnStatus:true
        }
    }
}
sleep:让pipeline休眠一段时间

sleep步骤可用于简单地暂停pipeline,其支持的参数有:

  • time:整型,休眠时间。
  • unit(可选):时间单位,支持的值有NANOSESECONDS、MICROSECONDS、MILLISECONDS、SECONDS、MINUTES(默认)、HOURS、DAYS
sleep(120) //休眠120秒
sleep(time: '2', unit: 'MINUTES') //休眠2分钟
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容