Jenkins实践指南-05-Jenkins pipeline 语法01

3. Jenkins pipeline 语法

3.1 pipeline 组成

    Jenkins pipeline 是基于Groovy语言实现的一种DSL(领域特定语言),用于描述整条流水线是如何进行的。流水线的主要内容包括源码拉取构建打包部署测试生成报告等步骤。

    从源码管理仓库到生成测试报告这些过程中,可以根据需要分成若干阶段,而每个阶段仅处理一件事情,而每个阶段也可以通过多个步骤来完成,因此我们可以基于这些阶段和步骤些进行抽象,形成工程化的pipeline,因此一个基本的pipeline示例如下所示:

pipeline{
 agent any
 stages{
   stage("Sample stage"){
     steps {
       echo "Hi,Surpass.Welcome visit my blog:https://www.cnblogs.com/surpassme/"
     }
   }
 }
}

    以上示例详细解释如下所示:

  • pipeline:代表整条流水线,包含整条流水线的逻辑
  • agent:指定流水线的运行位置

流水线的中每个阶段都必须在某个地方(例如物理机、虚拟机或容器)运行,因此可能通过指定 agent部分来指定具体在哪里运行。

  • stages:流水线中多个stage的容器。该部分至少包含一个stage
  • stage:表示阶段,代表流水线的阶段,每个阶段必须有名称
  • steps:表示阶段中的一个或多个具体步骤的容器

1.steps至少包含一个步骤
2.在一个stage中仅有一个steps

    以上每一个部分都是必需的,否则Jenkins都会报错

官方参考文档:https://www.jenkins.io/doc/pipeline/steps/

3.2 pipeline 支持的命令

    基本的pipeline结构是无法满足日常现实多变的需求。因此,Jenkins pipeline可以通过各种指令来扩展丰富自己。以下为Jenkins pipeline支持的命令。

3.2.1 environment

    environment主要用于设置环境变量。可以定义在stagepipeline部分。环境变量可以分为:Jenkins内置变量自定义环境变量

3.2.1.1 Jenkins 内置环境变量

    在执行pipeline时,可以通过env命令来获取Jenkins的全部内置环境变量,其主要使用方法如下所示:

pipeline {
    agent any
    stages{
        stage("PrintEnviroment"){
            steps{
                // method A
                echo "Running ${env.BUILD_ID} on ${env.JENKINS_URL}"
                // method B
                echo "Running $env.BUILD_ID on $env.JENKINS_URL"
                // method C
                echo "Running ${BUILD_ID} on ${JENKINS_URL}"
            }
        }
    }
}

默认情况下,env中的所有环境变量都可以直接在pipeline中使用。因此上面三种方法都可以使用,但不推荐第三种方法,因为在出现变量名冲突时,排查问题非常难。

    如果需要查看env所有可用的环境变量,可以通过以下方式进行访问。http://jenkins-master-address/pipeline-syntax/globals。示例如下所示:

http://192.168.188.133:9090/pipeline-syntax/globals

    Jenkins 内置环境变量如下所示:

0301 Jenkins内置环境变量.png

    以下为日常经常使用到的内置环境变量简介。如下所示:

  • BRANCH_NAME

    多分支piple 项目支持。可根据不同的分支执行不同的语句。例如当分支为release时,部署到生产环境,分支为test时,部署至测试环境。

  • BUILD_NUMBER

    构建号,同一个项目中,持续累加的数字。

  • BUILD_URL

    当前构建的URL地址,点击该URL,可以快速跳转至构建页面

  • WORKSPACE

    构建的工作空间,为绝对路径

    在调试pipeline时,也可以在pipeline 的开始阶段使用以下代码片断,打印所有env的环境变量,来进行排查问题。如下所示:

sh "printenv"

3.2.1.2 自定义环境变量

    当内置环境变量无法满足要求时,我们也可以定义自己的环境变量。这个时候就需要使用environment命令来自定义环境变量。示例如下所示:

pipeline {
    agent any
    environment{
        NAME="Surpass"
        AGE="28"
    }
    stages{
        stage("PrintGolbalEnviroment"){
            steps{
               echo "Global Enviroment is name is ${env.NAME} age is ${env.AGE}"
            }
        }
        stage("PrintLocalEnviroment"){
            environment{
                CITY="Shanghai"
                FROM="Wuhan"
            }
            steps{
                echo "Global Enviroment is name is ${env.NAME} age is ${env.AGE}"
                echo "Local Enviroment is city is ${env.CITY} from is  ${env.FROM}"
            }
        }
    }
}

    environment 可以在pipeline中定义,属于全局环境变量,代表整个pipeline均可以使用该环境变量。也可以在stage中定义,属于局部环境变量,仅限于该阶段内部有效,外部无法使用。

    除了以上几中自定义环境变量,还可以通过script来定义全局变量,示例如下所示:

pipeline {
    agent any
    environment{
        NAME="Surpass"
        AGE="28"
    }
    stages{
        stage("Set environment by script"){
            steps{
              script{
                  env.SURPASS_NAME="Surpass"
                  env.SURPASS_AGE=28
                }
            }
        }

        stage("PrintGolbalEnvironment"){
            steps{
               echo "Global Enviroment is name is ${env.NAME} age is ${env.AGE}"
            }
        }
        stage("PrintLocalEnvironment"){
            environment{
                CITY="Shanghai"
                FROM="Wuhan"
            }
            steps{
                echo "Global Enviroment is name is ${env.NAME} age is ${env.AGE}"
                echo "Local Enviroment is city is ${env.CITY} from is  ${env.FROM}"
            }
        }
        stage("PrintSetEnvironment"){
            steps{
                echo "print global env by script ${env.SURPASS_NAME}"
                echo "print global env by script ${env.SURPASS_AGE}"
            }
        }
    }
}

    在自定义环境变量,需要注意的地方如下所示:

  • 1.环境变量是不能跨pipeline进行访问的,即不同的pipeline间不能共享环境变量
  • 2.如果用户自定义的环境变量与env环境变量重名,则被重命名的环境将被覆盖

3.2.1.3 自定义全局环境变量

    env中的环境变量都是内置的,用户自定义的环境变量是与具体的pipeline相关的。如果需要定义全局并且跨pipeline自定义环境变量,可以这样设置。

Manage Jenkins->Configure System-> Global properties,勾选 Environment variables,添加对应的环境变量即可。

0302 自定义全局环境变量.png

    以上自定义的全局环境变量,会被加入env环境变量列表中,后续使用时可以使用${env.SURPASS_NAME}${env.SURPASS_AGE}来获取。

3.2.2 tools

    可定义在pipeline或stage部分。在运行时,会自动下载并安装指定的工具和加入PATH变量中。但在agent none时,会失效

基于在线自动安装,受限于网络不可达、网络速度、网络策略等因素,一般还是建议,还是提前下载到本地,然后在Jenkins进行配置好之后,在pipeline中直接使用即可。

3.2.2.1 Go 语言环境搭建

    其操作步骤如下所示:

  • 1.下载golang SDK本地

  • 2.在Jenkins 中安装go插件

  • 3.在Jenkins中进行配置

Manage Jenkins->Configure System-> Global Tool Configuration->GO

0303 添加go tools.png
  • 4.编写pipeline 脚本
pipeline{
    agent any
    tools {
        go "go-1.19"
    }
    stages{
        stage("tools demo"){
            steps{
                sh "go version"
                sh "go env"
            }
        }
    }
}

    运行结果如下所示:

0304 tools 运行结果.png

3.2.2.2 Python 语言环境搭建

    Python 环境很容易产生版本冲突和第三方库冲突等问题,因此Python通过会进行工程级别的环境隔离。在Jenkins中,我们可以使用插件Pyenv Pipeline Plugin(https://plugins.jenkins.io/pyenv-pipeline/)来解决此类问题。其操作步骤如下所示:

  • 1.在Jenkins中安装Python/pip/virtualenv
  • 2.安装插件Pyenv Pipeline Plugin
  • 3.编写pipeline 脚本
pipeline{
    agent any
    stages{
        stage("python virtual env demo"){
            steps{
                withPythonEnv("/usr/local/bin/python3") {
                    // Uses the specific python3.5 executable located in /usr/bin
                    sh "python3 --version"
                    sh "python3 -c \"print('hello,Surpass')\""
                }
            }
        }
    }
}

    运行结果如下所示:

0305 pyenv demo.png

3.2.2.3 利用作用域实现多版本编译

    在实际项目中,同一份源码可能会存在多个版本的编译构建等。tools 除了支持pipeline域也支持stage域。示例如下所示:

pipeline{
    agent any
    stages{
        stage("build with go 1.19"){
            tools {
                go "go-1.15"
            }
            steps{
                echo "use go 1.15 build"
            }
        }
        stage("build with go 1.19"){
            tools {
                go "go-1.19"
            }
            steps{
                echo "use go 1.19 build"
            }
        }
    }
}

3.2.3 input

    input 命令可以实现pipeline中的交互操作。利用input命令,我们可以一些简单的场景。

  • 实现简易的审核流程

在部署环境前,由相应负责人员进行确认

  • 排查定位问题

因为pipeline在遇到input命令时,会暂停执行。因此,我们可以利用这个特性,使运行某个阶段前,暂停执行pipeline

3.2.3.1 常用参数

    input 命令的常用参数如下所示:

  • message

    该参数为必选参数,input命令的消息提示框消息。

  • id

    该参数为可选参数, input命令标识符,默认为stage的名称

  • submitter

    该参数为可选参数,类型为字符串类型,可以进行操作的用户ID或用户组名称,使用,分隔,在,左右不允许有空格。可以用来做权限控制。

  • submitterParameter

    该参数为可选参数,类型为字符串类型,保存input命令的实际操作者的用户名的变量名

  • ok

    该参数为可选参数,自定义确定按钮的文本

  • parameters

    该参数为可选参数,提供参数列表供input命令使用。

3.2.3.2 简易用法

    比如我们现在实现第一种简易的审核流程。示例脚本如下所示:

pipeline{
    agent any
    stages{
        stage("input simple use"){
            steps{
                input message:"Confirm or Cancle ?"
            }
        }
    }
}

    当执行到input simple use阶段时,pipeline会暂停,当鼠标移动到该阶段虚线视图上时,会出现一个浮层 ,以供选择。示意图如下所示:

0306 input简易用法.gif

3.2.3.3 复杂用法

    示例脚本如下所示:

pipeline{
    agent any
    environment {
        DEPLOY_ENV=""
    }
    stages{
        stage("choose deploy nodes"){
            steps{
                script{
                  DEPLOY_ENV=input(
                      message: "准备部署到哪个节点?",
                      parameters:[choice(
                            name:'chooseNode',
                            choices:["node-1","node-2","node-3"],
                            description:"选择部署节点") 
                            ],
                      ok:"确定",
                      submitter:"admin,Surpass",
                      submitterParameter:"approvers"
                      )
                }
            }
        }
        stage("deply"){
            steps{
                echo "操作人员:${DEPLOY_ENV['approvers']}"
                echo "部署节点:${DEPLOY_ENV['chooseNode']}"
            }
        }
    }
}

因为input返回的值需要跨阶段,因此需要将input的返回值定义为全局变量。

    input 命令返回值类型取决于返回的值个数,详情如下所示:

  • 仅返回一个值,返回值类型就是这个值的类型
  • 返回多个值,则返回值类型为Map类型

    运行结果如下所示:

0307 inpu复杂用法.gif

3.2.4 options

    用于配置pipeline本身的选项,可以定义在pipelinestage中。常用的配置项如下所示:

  • buildDiscarder

    用于配置保存最近历史构建记录的数量。示例如下所示:

options{
      buildDiscarder(logRotator(numToKeepStr:'5'))
    }

此选项只能在pipeline下的 options 中使用

  • checkoutToSubdirectory

    Jenkins 从版本控制库中拉取源码时,默认会存放到工作空间目录中,此选项可以指定检出到工作空间的子目录中,示例如下所示:

   options{
      checkoutToSubdirectory('subdir')
    }
  • disableConcurrentBuilds

    同一个pipeline,Jenkins默认是可以同时执行的,而此选项则是禁止多个pipeline并行执行,示例如下所示:

   options {
      disableConcurrentBuilds()
    }
  • retry

    当发生失败时进行重试,可以指定整个pipeline的重试次数。示例如下所示:

   options{
       retry(3)
   }

需要注意的是这里的重试次数是指总次数,即包含第一次失败。当使用retry选项时,options可以放在stage中

  • timeout

    若pipeline执行时间过长,超出了设置的超时时间之后,则Jenkins将中止pipeline。示例如下所示:

   options{
       timeout(time:1,unit:'SECONDS')
   }

1.timeout时间单位有SECONDSMINUTESHOURS
2.当使用timeout选项时,options可以放在stage块中

  • timestamps

    为控制台输出时间戳。示例如下所示:

   options {
        timestamps()
    }

3.2.5 parallel

    在pipeline中使用parallel可以很方便的实现并行构建。

3.2.5.1 阶段并行

    示例如下所示:

pipeline{
    agent any
    stages{
        stage("Non Parallel stage"){
            steps{
                echo "This is non-parallel stage"
            }
        }
        stage("Parallel stage"){
            failFast true
            parallel{
                stage("Parallel A"){
                    steps{
                        echo "Parallel A"
                    }
                }
                stage("Parallel B"){
                    steps{
                        echo "Parallel B"
                    }
                }
                stage("Parallel C"){
                    steps{
                        echo "Parallel C"
                    }
                }
            }
        }
    }
}

    在使用parallel时,注意事项如下所示:

  • parallel 块本身不允许包含agenttools
  • 默认情况下,pipeline要等parallel块下所有的阶段都运行完成,才能确定运行结果。若希望所有并行阶段中某个阶段失败后,就即将中止所有阶段,则需要在parallel同级位置加入failFast true

failFast true 简单来讲就是表示,只要有一个并行阶段运行失败,则立即退出。

3.2.5.2 步骤并行

    示例如下所示:

pipeline{
    agent any
    stages{
        stage("Non-parallel steps"){
            steps{
                echo "Non-parallel steps"
            }
        }
        stage("Parallel steps"){
            steps{
                parallel(
                  parallelA:{
                      echo "parallelA steps"
                  },
                  parallelB:{
                      echo "parallelB steps"
                  },
                  parallelC:{
                      echo "parallelC steps"
                  }
                )
            }
        }
    }
}

    阶段并行和步骤并行的主要区别如下所示:

  • 写法区别:在阶段并行时,使用的是大括号,而步骤并行时,使用的是括号
  • 运行区别:阶段并行是运行在不同的executor,而步骤并行,则是运行在同一个executorr
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容