Jenkins中pipe使用总结

927 阅读3分钟

使用pipe的背景

项目中的测试包以及发布包的构建是通过Jenkins来进行的,使用的是自由风格的任务,但主要的构建任务是写在一系列的python脚本里的。比如一个Release的构建任务,基本就是设置好git的仓库地址,账号密码,然后在构建的一栏里选择执行shell, 然后填上一句类似python /.../build.py -type adhoc这样的语句就行。其中build.py是从项目初期的一些自动化构建脚本整合而来的,涉及的内容包括增加build号, 构建ipa, 上传测试包, 上传符号, 发邮件等一系列操作。

这种方式虽然使用起来很简单,但是也逐渐暴露出一些弊病,比如

  1. 涉及到的所有步骤都是包含在build.py及其子调用里。如果想只进行其中某一个步骤,或者构建失败后,想从中间某个步骤接着重新够建,这是做不到的。必须重头再构建一遍。
  2. 构建错误不好排查,只能从整体的构建日志里去查,看看是哪一步出错了。
  3. Jenkins界面上也不太友好。一个构建步骤开始后,基本只能等着结果或者出错,或者成功。无法从界面上直观的看出进行到什么阶段,以及花费了多长时间

所以基于上面的问题,就对构建方式进行了改造,同时熟悉了一次Jenkins的pipe机制

pipe简介

pipe的机制在官网上有详细的介绍。www.jenkins.io/doc/book/pi…。简单的理解就是某一个pipe做一项简单的工作,然后通过pipe的衔接来流程化完成一系列任务。pipe的语法有两种形式,Declarative PipelineScripted Pipeline两种形式。 创建了pipe类型的Job之后,可以在底部流水线模块,选择Pipeline script或者Pipeline script from SCM。前者是将配置直接写在Jenkins上。后者是将配置写在一个文件里,并且托管到某一个代码仓库,文件一般是Jenkinsfile。后者在Job启动时,先去拉取托管代码,再根据配置的相对路径读取配置文件,继而执行配置的pipe内容。

考虑到可以将配置托管起来,编写、维护都比较方便。所以就使用了SCM的方式,将相关配置托管在一个CI脚本仓库里,并且使用了Declarative Pipeline的语法形式。

基本的pipe结构大致是以下这样

pipeline{
    agent{
        label "$BuildNodeName"
    }
    environment{
        SHARED_PARMS = ""
    }
    stages{
        stage("stage 1"){
            steps{
                sh 'do simple work'
            }
        }
    }
}

其中agent是该任务执行的节点名称。environment中可以配置一些环境变量.每个stage里包含一个stepsstage的名称会在Jenkins的界面上出现,作为流水线中的一环。steps中是具体该环节要执行的一系列指令。

构建流程改造Tips

由于之前的构建脚本中已经笼统包含了所有的构建内容,所以首先必须要做的就是把各个步骤拆分出来。这部分跟具体项目有关,就不用详细说了。最后达到效果是构建,改build号,该项目配置,构建.app文件,导出ipa以及邮件等许多操作,都可以通过单独的脚本来独立运行。之后就是通过pipeline把这些操作衔接起来。 主要的写法很简单,所以只简单记录一下一些注意事项,做个备忘

参数和环境变量

  • 环境变量的引用形式是比如"$env.WORKSPACE"。环境变量可以是Jenkins预留的环境变量,也可以是节点机制配置的自定义环境变量。
  • 参数的引用是比如 "$BuildNodeName"。参数的传入,不论是直接运行job,还是通过pipe,都需要首先在当前Job配置中,勾选参数化构建过程, 预先设置好要用的参数和类型。
  • 注意都是使用双引号, 变量才能被正确替换,单引号会认为是自然文本输出,不替换变量。这个地方卡了一段时间找不到问题。
  • environment中,可以设置一些变量,这些变量可以在后续的steps中,以参数的形式进行引用。

work directory

在steps中,如果需要切换当前的工作目录,经实验使用sh "cd xxx"这种方式是不起作用的。正确的方式是使用dir语法将要在子目录执行的steps包起来,比如如下建立一个子目录,在里面获取git仓库代码

sh 'mkdir -p Appcode'
dir("Appcode")
{
    git branch: "$APP_GIT_BRANCH",
    credentialsId: 'xxxx',
    url: '$APP_GIT_URL'
}

parallel

有些步骤希望并行进行。比如实际构建中,希望内测版,企业版的同时构建和分发,这时可以用parallel语法,声明两个任务并行执行。如果是在同一个节点机器上,别忘了配置节点的并行任务数量大于1。Jenkins官网建议可以设置成CPU核的数量。语法结构大致如下

stage("run all job"){
    parallel{
        stage("build adhoc"){
            steps{
                work 1
            }
        }
        stage("build inhouse"){
            steps{
                work 2
            }
        }
    }
}

多个Job配合

为了让构建更加灵活,可以采用多个Job进行配合。比如纯粹的构建内测版,以及企业版可以分别建立一个单独的Job。再建立一个上层的Job, 这个Job负责升build号,之后启动多个Job完成具体构建任务,子Job都完成之后,上层Job再发邮件等。

启动一个子Job的语法如下:

build job: '/Sub_Job_Name', parameters:[[$class: 'StringParameterValue', name: 'BuildNodeName', value: "$BuildNodeName"]]

其中Sub_Job_Name是子任务的名字。子任务有个字符参数是BuildNodeName,通过上面方式可以在启动子Job时,传递相应的参数值过去。

在step中通过build启动子任务,默认是会一直等待该任务执行结束才继续进行后面的工作。如果这个子任务只是想触发一下,并不需要等待执行结果,可以使用wait参数。

build job: '/Sub_Job_Name', parameters:[[$class: 'StringParameterValue', name: 'BuildNodeName', value: "$BuildNodeName"]], wait:false

构造流程改造效果

使用体验相比旧的方式还是很不错的,Jenkins上外观也有了变化,大致是这个样子,具体某个step的执行情况也可以点击详细log查看

新流程大致有如下几个优点:

  1. 通过pipe化的改造,后续对构建流程扩展,或者流程改造就方便很多,灵活很多。
  2. 目前从界面上可以清楚的看到执行到了哪个stage。通过点击看stage的log,也可以清楚的看到每个step的运行情况,
  3. 每个stage, step都有统计时间,方便做构建时长的优化。