点击上方“中兴开发者社区”,关注我们
每天读一篇一线开发者原创好文
概述
XXX项目原CI系统由项目自行搭建,使用Jenkins传统的Job方式来实现VerifyCI和MergeCI以及DailyBuild。随着项目规模越来越大,分支越来越多,合代码的频率也逐渐增大的情况下,现有系统呈现出诸多不便之处。为解决这些问题,项目尝试引入一系列现成公司级Devops研发工具并结合Jenkins2.0的Pipeline新特性来改造本项目Pipeline流程。
Pipeline as Code 是 Jenkins 2.0 版本的精华所在,是帮助 Jenkins 实现从 CI 到 CD 华丽转身的关键工具。所谓 Pipeline,简单来说,就是一套运行于 Jenkins 上的工作流框架,将原本独立运行于单个或者多个节点的任务连接起来,实现单个任务难以完成的复杂发布流程。落实到代码级别,即我们只需要把精力集中在编写 Jenkinsfile 文件上,然后将其随同代码库一起托管,Jenkins可以根据Jenkinsfile来迅速拉起项目的CI流程,方便高效。
但是随着多个项目的试行、落地,发现基于Jenkins2.0的Pipeline功能强大,但是具体应用到各个项目还有如下几个痛点:
各个项目都在编写自己特色的Jenkinsfile,很多时候互相复制修改一下代码实现,Jenkinsfile冗余度非常高;
按照Jenkins1.x时代的思路,订制化自己的CI/CD流程、邮件通知、报告输出,转换过程缓慢而痛苦;
-
遇到技术问题没有能力解决、采用一些过时的方法和工具,而其他项目组已经解决一些技术问题或者采用了更加先进的方法和工具,互相并不能及时分享;
为了解决这些问题,经过项目反复调研和摸底,最终采用了中开社上开源的Jenkins2.0的Pipeline共创库iPipeline(又称plll库)来辅助本项目重构CI流程。
iPipeline是简化CI Pipeline部署的工具集,是面向开发人员和CI配置管理员的函数库,其封装了Jenkins 2.0的常用函数,集成了Gerrit、制品库、云CI、度量、告警采集、邮件通知,另外提供docker封装的工具集(复杂度、Klocwork、度量分析、度量导入等)。利用其可以帮助我们节省很多精力,避免重复造轮子,因此非常满足我们项目的需求。
问题描述
iPipeline框架在本项目的实践过程中确实提高了很多效率和幸福感,但结合本项目一些实际的使用情况,发现其仍然存在一些优化和改进的点。为此针对我们项目的需要,我们对iPipeline做了如下一些优化并实践。
问题1
利用plll库提供的pdocker接口,可以很方便地在指定的节点上运行指定的Docker容器来完成相关CI任务。比如本项目圈复杂度检查已经Docker化,因此可以利用pdocker接口,通过配置上镜像名、映射目录以及需要运行的指令与脚本来执行代码的圈复杂度检查。
但是实际在对pdocker接口的使用过程中发现,plll库每次都会去节点上pull镜像,然后再运行,这对于镜像其实已经存在于本地节点的情况其实并没有必要,因此需要改造。
问题2
目前plll库提供的Update接口仅支持Gerrit代码仓库的代码检出更新,但本项目运行某些用例测试需要的报文存储于SVN库上,因此有必要扩充plll库原有接口,使其支持SVN库的代码更新
带着这两个问题,我们对plll库做出了对应的一些优化并且实践之。
优化实践
优化1:pdocker接口是否需要拉取镜像由用户自定义
改造pdocker接口,添加参数来控制是否需要pull镜像,接口代码片段如下:
/*** 工具名称:docker执行* 工具描述:* image - 镜像的全路径* needPull - 是否需要pull镜像* before_cmd - 以root执行的命令行,在执行user_cmd前执行* volumes - 路径映射清单,"a:b,c:d"* params - 执行参数* profile - 环境文件,可执行* user_cmd - 以当前用户执行的命令行(需要镜像支持adduser命令)* after_cmd - 以root执行的命令行,在执行user_cmd后执行* local_dir - 存放临时文件的目录(要求有权限映射到容器内)* shared_dir - 存放代码和产出文件的目录(要求有权限映射到容器内)* sh_exec - shell进程,默认为sh**/def call(image, needPull, before_cmd, volumes='', params='', profile='', user_cmd='', after_cmd='',local_dir=env.LOCAL, shared_dir=env.SHARED, sh_exec='sh') {// ...此处代码省略...if( needPull == "no" ) {echo "no need to pull image !!! The image exists in local!"writeFile file:docker_entry_file, text:"""set -edocker run --rm ${params} ${volumes} ${image} ${sh_exec} -x -c ${docker_run_file}"""} else if( needPull == "yes" ) {writeFile file:docker_entry_file, text:"""set -edocker pull ${image}docker run --rm ${params} ${volumes} ${image} ${sh_exec} -x -c ${docker_run_file}"""}// ...此处代码省略...}
由代码可以看出,通过添加needPull参数,即可由用户自定义是否需要pull镜像。
使用举例:
例如本项目调用pdocker接口利用自制docker镜像完成代码圈复杂度检查:
pnode("${env.NODE_NAME}") {plll.Check("CCN_DOCKER", "CCN_DOCKER", [run_execute:{ pdocker (/* image */ "docker.zte.com.cn:5000/10010891/lizard:v1",/* need pull */ "no",/* cmd */ "cd /home/code/ && chmod -R 777 * && cd script/VerifyCI/CCNCheck/ && sh +x lizard.sh",/* volumes */ "-v ${env.SHARESPACE}/${env.XXXXX_DIR}:/home",/* params */ "--privileged",)},param:[report_file:[]]]);}
由于docker.zte.com.cn:5000/10010891/lizard:v1已经存在于我们的外挂节点上,因此此处needPull参数置为no即可控制pdocker内部无需再去pull镜像。
优化2:扩充框架Update接口,使其支持SVN代码更新
优化Plll库代码,加入UpdateSVN接口来支持SVN库的代码检出与更新
/*** 功能名称:Update* 功能描述:通过SVN更新代码**/def UpdateSVN(name, desc, args) {LogDebug("[DEBUG] Update: ${name}, ${desc}")args.run_execute = {dir("${args.scm.path}") {svn_checkout( args.scm.keyid, args.scm.repo, args.scm.path )}}/* 调用功能适配 */FunctionAdapter("Update", "update", name, desc, args) {}return}/*** 工具名称:svn_checkout* 工具描述:svn更新代码* 参数描述:* - keyid: SVN库的Credentials ID* - repo: SVN库Repo路径* - path: 代码下载路径**/def svn_checkout(keyid, repo, path) {checkout([$class: 'SubversionSCM',additionalCredentials: [],excludedCommitMessages: '',excludedRegions: '',excludedRevprop: '',excludedUsers: '',filterChangelog: false,ignoreDirPropChanges: false,includedRegions: '',locations: [[credentialsId: "${keyid}", depthOption: 'infinity', ignoreExternalsOption: true, local: ".", remote: "${repo}"]],workspaceUpdater: [$class: 'UpdateUpdater']])return}
使用举例:
用户只需要配置上:
SVN库的Credentials ID
SVN库Repo路径
代码下载路径
即可完成SVN代码检出和更新,示例如下:
// 先配置好SVN相关参数env.SVN_KEY_ID = "89a6fe98-8f0c-4fe6-829e-6d1cbda188e1"env.CASE_DIR = "/jenkins_ci/CASE_TEST/PATH"env.CASE_SVN_URL = "svn://XXX.XX.XXX.XXX/XXXXXXX/case/XXXX"// 调用UpdateSVN接口完成SVN库代码更新plll.UpdateSVN( 'SVN_UP', '更新SVN上报文',[scm:[keyid:"${env.SVN_KEY_ID}", repo:"${env.CASE_SVN_URL}", path:"env.CASE_DIR"],run_dir:"${->OUTPUT_PATH}"])
推广建议
本文章相关优化改进可推广至需要利用docker镜像完成相关CI任务和代码管控涉及SVN库的项目
下篇文章将于明天发布,主要介绍报告/邮件可扩展,敬请期待~
拓展阅读