前言
近些年来Docker、 Kubernetes、 Helm、 云原生如火如荼,Jenkins 凭借开源社区的贡献以及类似 CloudBees 团队的加持。紧跟技术发展趋势,产出了集成于 Docker、 Kubernetes、 Helm、AWS等各种工具插件,还有 Jenkins X,原来配置页的 Manage Nodes 也"悄悄地"变成了 Manage Nodes and Clouds。 另一方面,自研能力不错的企业,也纷纷基于 Jenkins API开发一套 Devops CICD 平台,给 Jenkins那个"老头"套上了一层年轻的外衣,效果也十分理想。
Jenkins开源的特性,还有浩瀚如海的插件,学习门槛低等等,都让其成为一个不错的选择。至少可以在有限资源的条件下,针对项目中需要搭建少数的几个流水线这样的需求而言,Jenkins再合适不过了。
纵使作为一个新技术的爱好者,当你用户其他新的CI工具时,也不妨回过头来看一看这个“老头”,其中包含的一些通用法则、思想会让你明白如何才能搭建使用于某个项目易用、易扩展、易维护的流水线。
提高代码复用性之Shared Library
如果你为一个项目里的多个Code Repo写多个jenkinsfile,你八成会遇到多个不同流水线中有大量重复代码的情况,尤其在服务众多的微服务的项目当中。很多时候为了方便省事我们都是直接复制粘贴类似的逻辑代码到不同的jenkinsfile中去,但如果某一天你需要更改一个小小的命令,那你就要受点小罪了。
而Shared Library便是解决代码重复的方法之一,只需根据流水线段落的合理划分,将流水线逻辑重复或共通的部分进行抽象和封装,便可在所有的流水线中简单地引用这些共享库下面的代码,并可大大缩短jenkinsfile中的代码行数,也显得更加易读、易维护。
而后期之秀中的Azure Pipelines, Github Actions 似乎深知复用功能函数的好处,并将其常用的Tasks/Actions放置到了公共的Marketplace中。开发者即可直接使用,也可以自行开发后上传到Marketplace中供更多人使用。使用者更是免于维护一个单独的类似于Jenkins Shared Libray的代码仓库,一举多得。另外,云原生工具中的Tekton, 其中的Task也有类似的实践。
共享库越来越大,调用关系越来越复杂时,不得不考虑代码质量的问题。那就需要测试代码来保证质量,如何对Shared Library进行测试?当然可以编写Jenkinsfile放到Jenkins中创建Job去运行,跑一跑便知代码是否有问题。但无疑这种方法不太优雅,推荐使用JenkinsPipelineUnit(一个共享库单元测试的框架)。
模板化之 JTE
正如一套开发框架一样,目的是为了快速地搭建起一个标准化的许多项目,模板提供的功能也是如此:对于同一类型的流水线而言,大多数的构建过程均是一样的,甚至连运行的命令也是一模一样,这样的流水线 配置文件相似度自然也是非常的高。那么 Jenkins Templating Engine就是针对这样的场景的一个非常好的解决方案。
例如,在微服务的大型项目中,往往一个系统是由数十个小的微服务组成的,而着数十个微服务均需要各自的CICD的流水线,来完成打包、部署的过程,彼此之间又是同一套开发框架,所需要的构建环境、工具、测试流程、发布策略等等均是一个模子刻出来的。
"人"如其名, Jenkins Templating Engine就是用来做流水线模板化的工具,简称 JTE。从 JTE 主页可看到诞生时间是2019年5月份,相当年轻。针对不同类型的项目,比如Maven、 Gradle来做一些模板化的规定,简单而言就是用来统一内部流水线的Stage、Steps中的逻辑、参数等。
在完成上述代码,以及安装JTE插件、正确配置 Jenkins的前提下,在具体业务代码中添加默认文件pipeline_config.groovy之后,新建流水线时针对 build configuration 选项去选择Jenkins Templating Engine,即可完成流水线的搭建,只需要简简单单的2、3行。
而反观 JTE 的优势,便是以下三点:
(来源于 https://www.jenkins.io/blog/2019/05/09/templating-engine/)
而去其他CICD工具中寻找一下,也可见到类似实践的身影。例如 Gocd 的Pipeline Templates, Azure Pipelines 的 templates。
集中管理之Job DSL
如果你正在经历一个微服务项目,Code Repo 数量众多,而每个Repo都需要通过一个Jenkinsfile定义一个流水线。当你面对几十上百个Repo,分散地管理维护它们便些许繁琐。Job DSL Plugin 允许使用DSL以编程方式创建项目,将作业创建的操作通过脚本实现,使你能够自动化和标准化 Jenkins 配置。
这款插件不单单能够创建各种类型的Job(Maven jobs、Freestyle jobs、流水线 jobs...),还能创建 Folder、 Dashboard View、 List View等等。形象生动的效果如下图,“埋下一颗种子,收获几颗大树”。
在代码库的目录层级上,首先建议按照 Project 划分,给每个 Project 定义单独的 Seed Job;其次将Job等的定义与逻辑实现隔离,这样能确保 xxx.jenkinsfile 里的内容的独立性,且在采纳Job DSL插件后,针对原先的 jenkinsfile 无需做很大幅度的修改,拿过来便可使用。
该工具无疑将Pipeline As Code的理念又进化了一步,将流水线的创建过程也代码化了。然后在 Jenkins 实践中,如果想追求更多的配置代码化,不妨看看 Jenkins Configuration as Code,简称 JCasC。这个工具能完全将大部分的Jenkins的资源、配置代码化,安装插件、配置Github Server、管理凭证、新建任务等等都可通过文件完成,不需要在UI界面上做任何的操作。
后记
以上几种思想在本文中都提供了对应的一种实现方式,但远远不止于所提及的方法,当然还有或多或少类似的方法,但万变不离其宗。纵使今后有更多的CICD新工具的出现,或许在一些小的地方上可以另辟蹊径,但大体的解决方案也绕不开已有的这些解决问题的思想。例如在Azure Pipelines中, Templates的功能能提供类似 Shared Library 和 JTE的功能,只是实现形式不同,核心思想却还是一致的。
具体使用还需要结合项目属性、分支策略、发布策略、权限管理、服务器环境情况等多个方面综合考虑,另外也有很多类似于 Nightly Build 这种构建策略值得我们借鉴。“条条道路通罗马”,怎么省时、省力的达成我们最终的目标,以及达成之后如何维护好流水线,都值得好好思考与设计。