【编者的话】Andy Pemberton领导CloudBees的解决方案架构团队。CloudBees是一家依赖Jenkins实现云化持续集成平台的创业公司,目前已经得到C轮融资。Andy拥有超过十年的软件交付经验,同时他也是经常发表演讲和撰写博客。本文是Andy做为Jenkins专家给出的10条Jekins管道化使用的最佳实践。
Jenkins的管道化插件对于其用户来说是个变局者。依赖于域领域语言(DSL)Groovy,管道化插件实现了脚本化。这对于开发复杂且步骤繁多的DevOps管道非常有帮助。本文提供了你最应该知道的关于Jekins管道化插件中“要做”和“不要做”的最佳实践-并且包含代码示例。
不要使用诸如Build Pipeline和Buildflow等老插件。应该使用真正的 Jenkins管道化插件套件 。
为什么呢?因为管道化插件是在底层任务上的一种改善。与那些自由式的插件不同,管道化插件对于Jenkins主节点重启是有感知能力的,并且包含了一些內建的功能。这些功能在构建多步骤、复杂的发布管道时,效果大大超越了之前的老式插件。
更多关于管道化的内容: https://jenkins.io/solutions/pipeline/
使用这种方法你可以在SCM中存储Jenkinsfile。并且像写其他软件一样的去版本化和测试它。
为什么要这么做呢?把你的管道作为代码会强化一种约束,并且得到GitHub和BitBucket提供的多种新功能,诸如:多分支,pull request检查和组织扫描。
你需要给你的管道脚本一个默认名字:Jenkinsfile,并且以如下的内容作为脚本头,这样的话你的IDE,GitHub和其他工具会识别出来脚本是Groovy,并提供语法高亮功能:
你的管道中任何非初始化的任务都要放到一个Stage块中。
为什么呢?因为Stage是管道的逻辑段。将任务分拆到不同Stage中等同于你将管道拆分成一个个独立的任务段。
stage 'build'
//build
stage 'test'
//test
并且有福利哦:Pipeline Stage View插件可以将管道中的一个个段进行可视化:
任何管道中重量级的工作需要放到node块中执行。
为什么呢?因为默认情况下,Jenkinsfile脚本运行在Jenkins的主节点中,并且为了减少资源的消耗而使用了轻型的执行器。任何重量级的工作,例如从Git上下载代码或编译Java应用,需要使用Jenkins的分布式构建能力并且运行在代理节点中。
stage 'build'
node{
checkout scm
sh 'mvn clean install'
}
管道提供了一个向前(straight-forward)的语法来支持将你的管道拆分成并行的步骤。推荐使用它。
为什么呢?因为将任务转为并行可以加快你的管道运行,将你的管道步骤放到“left”中,开发者和团队其他的成员会更快的得到反馈。
parallel 'shifting':{
//everything
}, 'left':{
//I can
}
提示:使用 并行测试执行插件 可以使Jenkins自动决定如何在可选的并行桶中运行你的单元测试!获取详细信息请阅读 Parallel Test Execution on the CloudBees Blog 。
为什么呢?管道并行化最大的好处是:做更多的重量级任务(参见最佳实践4)!通常情况下你需要在管道并行分支内部使用一个节点。
parallel 'integration-tests':{
node('mvn-3.3'){ ... }
}, 'functional-tests':{
node('selenium'){ ... }
}
你千万不要在node块内部使用input语句。
为什么呢?因为输入会暂停管道的执行,去等待自动的或手动的输入。自然这类等待一定会占用时间。而另一方面,node语句在工作区上获取并持有锁和重型的Jenkins执行器,去获取这么昂贵的资源而仅仅为了停下来等待输入是不合适的。
所以,请在node的外部创建input输入。
stage 'deployment'
input 'Do you approve deployment?'
node{
//deploy the things
}
管道有一套很简单的机制来应对任务的超时。这其中的最佳实践是:你应该总是为你的输入规划好超时时间。
为什么呢?为了管道的健康清理,这就是原因。当输入的内容在指定时间窗口内没有送达时,将你的输入包装到一个超时内部可以使它们被清理掉(例如:被暂停)。
timeout(time:5, unit:'DAYS') {
input message:'Approve deployment?', submitter: 'it-ops'
}
如果你想在env全局变量中编辑一些设置时,你应该使用withEnv语法来这么做。
为什么呢?因为env变量是全局的,直接改变它是不被鼓励的,因为它改变了全局的环境。所以withEnv语法是被推荐使用的。
withEnv(["PATH+MAVEN=${tool 'm3'}/bin"]) {
sh "mvn clean verify"
}
在暂存能力被添加到管道化DSL之前,归档是在node和stage之间共享文件的最佳方案。如果你仅仅是想在stage和node之间共享文件,那么你应该使用stash/unstash,而不是archive。
为什么呢?因为暂存是被设计为共享文件的,例如:在stage和node之间共享你的应用源代码。而另外一方面,归档是被设计为长期存储文件的(例如:你的构建的中间二进制文件)。
stash excludes: 'target/', name: 'source'
unstash 'source'
感谢您的阅读!新的Jenkins管道化插件已经获得了越来越多的关注,特别是在 Jenkins 2.0 发布后。我也同时相信随着全世界的开发者使用Jenkins开发他们的DevOps管道,将会有越来越多的最佳实践产生出来。
原文链接: Top 10 Best Practices for Jenkins Pipeline (翻译:高洪涛)
===========================================
译者介绍
高洪涛,当当网架构师,开源数据库分库分表中间件Sharding-JDBC作者。目前从事Docker相关研究工作。