Jenkins迁移之pipeline共享库的实践示例
作者:alwans
背景
我们一直使用的 jenkins 服务还是 2.0 以下不支持 pipeline 的版本。平时创建任务多数使用 maven 项目,构建后的 shell 部署命令都是在各个 job 中独立维护。这种方式的缺点就是:
1.脚本维护麻烦 (环境对应的服务器变更,构建入参更新等等状况);
2.不利于后期功能扩展 (例如 java 服务想接入覆盖率服务);
3.不利于 jenkins 项目迁移 (例如磁盘不足等原因)。
刚好上述原因都遇到了,所以计划迁移到新的 Jenkins 服务中,所有 job 都通过 pipeline 来管理。在使用 pipelin 之后的感觉用 2 个字来形容:真香
顺便感谢一下大佬,但是不知道他的 id,所以直接贴一下他的gitee 共享库项目地址
我的共享库项目中缝合了大佬很多代码,写的太好了,忍不住借鉴一下
初期需求
迁移之初,参考了网上很多的 pipeline 使用教程。首先肯定不想在每个项目中,维护大量的 Jenkinsfile 文件 (万一需要修改,那不是得改到吐,虽然也可以用 git 项目来统一管理 jenkinsfile),最终采用了 Multibranch Pipeline with defaults(多分支流水线) + Pipeline: Multibranch with defaults 插件的方式,通过维护简单的 default jenkinfile 文件来实现 pipeline 的使用。第二个考虑的问题就是,后期对脚本的维护和扩展希望尽可能的简单,这自然就想到 pipeline 共享库的使用。
成果展示
先展示下目前的成果:
1.创建 job
这里是说在 Jenkins 中配置简单,其实还有一些信息配置的,是保存在文件或者数据库中
2.job 参数配置
default jenkinsfile 文件的维护 (仅仅负责调用共享库,所有的实现均在共享库项目中完成)
共享库
共享库结构
├─resources │ app.json │ base.json │ host_info.json ├─src │ │ │ └─com │ │ common_util.groovy │ │ exec_shell.groovy │ │ Log.groovy │ │ │ ├─beans │ │ AppJobInfo.groovy │ │ HostInfo.groovy │ │ JavaJobInfo.groovy │ │ JobInfo.groovy │ │ │ ├─build │ │ androidBuild.groovy │ │ build.groovy │ │ gradleBuild.groovy │ │ mavenBuild.groovy │ │ npmBuild.groovy │ │ yarnBuild.groovy │ │ │ ├─deploy │ │ deploy.groovy │ │ │ ├─enums │ │ BuildType.groovy │ │ PipelineType.groovy │ │ ToolsType.groovy │ │ │ ├─qikqiak │ │ GlobalVars.groovy │ │ │ └─services │ JacocoHandle.groovy └─vars defaultPipeline.groovy initParamsStage.groovy loadPipeline.groovy testPipeline.groovy unknownPipeline.groovy
入口代码: loadPipeline.groovy
def call(PipelineType pipelineType) { JobInfo jobInfo = creatJobInfo() switch (pipelineType) { case PipelineType.DefaultPipeline: defaultPipeline jobInfo break case PipelineType.TestPipeline: testPipeline jobInfo break default: unknownPipeline null break } }
参数使用 jobInfo 对象管理
/** 针对不同类型的项目,使用不同的jobInfo:JavaJobInfo/AppJobinfo */ class JobInfo { /** * 页面入参 */ String jobName String env BuildType buildType String branchName JobInfo(Map map){ this.jobName = map.job_name this.env = map.env this.buildType = BuildType.getBuildTypeByKey(map.buildType) this.branchName = map.branchName } /** * 配置参数 */ //通用字段 String groupName ToolsType toolsType Map<String, String> envMap def setConfigParams(Map map){ this.groupName = map.groupName this.toolsType = com.enums.ToolsType.getToolsTypeByKey(map.toolsType) this.envMap = map.env_map } def getEnvKeyList(){ return this.envMap.keySet().toList() } def getHost(){ return this.envMap.get(this.env) } //默认项 /** * 是否为自动构建 */ boolean isAutoBuild = false /** * 自动构建时,默认构建的环境:加入构建指令需要环境参数时 */ String defaultEnv = "test" /** * 默认构建方式:仅构建 */ BuildType defaultBuildType = BuildType.BUILD @NonCPS def setAutoBuildParams(){ this.env = defaultEnv this.buildType = defaultBuildType } @Override @NonCPS public String toString() { return "JobInfo{" + "jobName='" + jobName + '\'' + ", env='" + env + '\'' + ", buildType=" + buildType + ", branchName='" + branchName + '\'' + ", groupName='" + groupName + '\'' + ", toolsType=" + toolsType + ", envMap=" + envMap + ", isAutoBuild=" + isAutoBuild + ", defaultEnv='" + defaultEnv + '\'' + ", defaultBuildType=" + defaultBuildType + '}'; } }
pipeline 结构:defaultPipeline.groovy
动态参数:initParamsStage.groovy
stage("init params step"){ script{ log.info("start init params...") /** * 先根据构建工具,来构建不同的构建参数 * 后期如果同一个构建工具,针对不同的job,入参类型不同,那么在根据job处理 */ switch (jobInfo.toolsType){ case ToolsType.MVN: properties([ parameters([ choice(name:'env', choices:env_list, description:'选择构建环境'), booleanParam(defaultValue:false, name: 'isCollectCoverage',description: '是否启用jacoco收集代码覆盖率'), choice(name:'buildType', choices:['buildAndDeploy', 'build', 'deploy'], description:'选择部署方式:编译并部署、仅编译、仅部署') ]) ]) break case ToolsType.GRADLE: if(jobInfo instanceof AppJobInfo){ properties([ parameters([ choice(name:'env', choices:env_list, description:'选择构建环境'), choice(name:'buildType', choices:['buildAndDeploy', 'build', 'deploy'], description:'选择部署方式:编译并部署、仅编译、仅部署') ]) ]) }else{ properties([ parameters([ choice(name:'env', choices:env_list, description:'选择构建环境'), booleanParam(defaultValue:false, name: 'isCollectCoverage',description: '是否启用jacoco收集代码覆盖率'), choice(name:'buildType', choices:['buildAndDeploy', 'build', 'deploy'], description:'选择部署方式:编译并部署、仅编译、仅部署') ]) ]) } break default: properties([ parameters([ choice(name:'env', choices:env_list, description:'选择构建环境'), choice(name:'buildType', choices:['buildAndDeploy', 'build', 'deploy'], description:'选择部署方式:编译并部署、仅编译、仅部署') ]) ]) } } }
共享库的扩展示例
java 服务增加 jacoco 覆盖率功能
1.维护 JavaAppInfo 对象
class JavaJobInfo extends JobInfo{ boolean isCollectCoverage JavaJobInfo(Map map) { super(map) this.isCollectCoverage = map.isCollectCoverage } //Jacoco相关属性 String jacocoPort String projectId //jacoco覆盖率服务中,coverage_app表中的project_id字段 String commitId String includes //需要增强类的通配符表达式 String excludes //需要排除增强类的通配符表达式 }
2.在部署时,启动 jacoco
def exec_jar(JavaJobInfo jobInfo){ def util = new common_util() def log = new Log() def jacocoHandle = new JacocoHandle() //判断是否要启用jacoco服务 if(jobInfo.isCollectCoverage){ //先获取jacoco port jacocoHandle.getJacocoPort(jobInfo) //在获取本次构建代码最新的commit id jacocoHandle.getCommitId(jobInfo) def shell_str = "ssh root@${jobInfo.getHost()} '/home/deployscripts/deploy.sh -d jar //省略 " if(jobInfo.includes !=""){ shell_str += " -I ${jobInfo.includes}" } if(jobInfo.excludes != ""){ shell_str += " -E ${jobInfo.excludes}" } shell_str += "'" sh "${shell_str}" }else{ sh "ssh root@${jobInfo.getHost()} '/home/deployscripts/deploy.sh -d jar //省略 " } }
以上就是Jenkins迁移之pipeline共享库的实践示例的详细内容,更多关于Jenkins迁移共享库pipeline的资料请关注脚本之家其它相关文章!