本文转载自微信公众号《运维开发故事》,作者:乔可。转载本文请联系运维开发故事公众号。上线发布是运维的日常工作。常见的发布方式有:手动发布Jenkins发布平台GitlabCI...另外需要开源软件,它们都有很好的发布管理功能。面临的问题作为运维人员,在线发布是必不可少的一环。什么是正常的发布流程?有毛病。企业上线一般都是通过一些公共渠道,比如邮箱、钉钉、飞书等。这些很难和线上发布平台的运维实现联系起来,不够直观。所以我们需要解决以下问题:建立流程与运维平台的连接,形成从发起到完成的闭环。为了选择JIRA?JIRA优秀的项目管理、问题跟踪工具,以及它的流程管理和看板模式也可以非常直观的看到你目前在流程中所处的位置。另外可以通过webhook与其他平台建立友好连接,方便扩展。再者,Jira是开发人员、测试人员、项目经理的日常工具,使用熟练度很高,减少了额外的学习成功率。鉴于此,我们选择了JIRA作为运维发布平台,力求做到一切都在一个平台上。方案设计设计思路充分利用了Jira和Gitlab的webhook功能,以及Jenkins的灵活性。Jira上的更新状态触发Jenkins执行合并分支流水线。Gitlab上的代码合并成功后,会触发Jenkins执行发布管道,并通过钉钉等软件将发布结果通知给相应的人。好在Jenkins插件的功能非常丰富。这里使用了GenericWebhookTrigger插件,可以灵活获取触发软件信息。发布流程方案,梳理以下发布流程。涉及软件软件功能Jira发布流程管理Jenkins各种流水线执行Gitlab代码仓库Kubernetes应用管理Helm/kustomize包管理DingTalk消息通知trivy镜像扫描镜像仓库阿里云镜像仓库PS:暂无具体软件部署Jira和Jenkins集成Merge分支Jenkins配置Jenkins配置主要有两部分,如下:配置JenkinsShareLibrary函数编写Jira触发对应的Jenkinsfile(1)在JenkinsSystemConfiguration-->SystemConfiguration-->GlobalPipelineLibraries上配置ShareLibarary(2)创建管道,配置Webhook并添加Jenkinsfile配置触发器先配置一个变量和一个正则然后配置一个Token来配置pipeline,添加对应的Jenkinsfileimage.png(3)Jenkinsfile的主要逻辑如下PS:下面只列出了总体框架,和does不详代码获取Jira的配置信息并分析。根据不同的信息进行不同的操作。合并分支主要是调用Gitlab的API接口#!groovy@Library('lotbrick')_defgitlab=neworg.devops.gitlab()deftool=neworg。devops.工具()defdingmes=neworg.devops.sendDingTalk()管道{agent{node{label"master"}}环境{DINGTALKHOOK="https://oapi.dingtalk.com/robot/send?access_token=xxxx"}stages{stage("FileterData"){steps{script{response=readJSONtext:"""${webHookData}"""//println(response)env.eventType=response["webhookEvent"]if(eventType=="jira:issue_updated"){//获取状态值env.jiraStatus=response['issue']['fields']['status']['name']env.gitlabInfos=response['issue']['fields']['customfield_10219']infos="${gitlabInfos}".split("\r\n")for(infoininfos){prName="$info".split("/")[0]//brName="$info".split("/")[1]brName=info-"${prName}/"println(prName)println(brName)if(jiraStatus=="已发布(UAT)"){println('合并PRE分支操作')}elseif(jiraStatus=="Released(PROD)"){println('合并PROD分支操作')}elseif(jiraStatus="Completed"){println('标记并删除分支去掉原来的分支')}else{println("Noitemfound")}}}}}}}//构造后的操作post{failure{script{println("failure:只有构造失败才会执行")dingmes.SendDingTalk("Branchmergefailed?")}}aborted{script{println("aborted:只有在构建被取消时才会执行")dingmes.SendDingTalk("Branchmergecancel?","pauseorinterrupt")}}}}以上在Jenkins上的配置就基本完成了。Jira上的配置Jira上的主要配置如下:Createworkflow工作流关联项目配置projecttriggerWebhookestablishingworkflowassociateworkflowwithprojectgroup配置webhooksettings-->system-->networkhookconfiguration完成后,Jira上的配置就完成了,然后可以在对应项目的看板上查看到所有待发布的项目,如下:然后拖拽或者点击发布按钮改变状态,触发流水线执行相应的操作。Gitlab与Jenkins集成发布系统开发分支简介这里主要采用功能分支开发模式,主要分为以下几个分支:DEV分支:开发环境分支TEST分支:测试环境分支UAT分支:联调环境分支PREbranch:pre-production发布环境分支MASTERbranch:生产环境分支的代码合并路由为:DEV->TEST->UAT->PRE->MASTER然后根据不同的分支判断执行不同环境的部署。Jenkins配置流水线(1)配置Webhook插件参数获取Gitlab分支定义gitlab推送条件,没有任何变化需要触发流水线定义过滤正则表达式,这样流水线只有在commit的时候才会被触发。(2)ConfigureJenkinsfiledeflabels="slave-${UUID.randomUUID().toString()}"//引用共享库@Library('jenkins_shareLibrary')//应用共享库中的方法deftools=neworg.devops.tools()defbranchName=""//获取分支if("${gitlabWebhook}"=="gitlabPush"){branchName=branch-"refs/heads/"currentBuild.description="Builder${userName}branch${branchName}"}pipeline{agent{kubernetes{labellabelsyaml"""apiVersion:v1kind:Podmetadata:labels:some-label:some-label-valuespec:volumes:-name:docker-sockhostPath:path:/var/run/docker.socktype:''-name:maven-cachepersistentVolumeClaim:claimName:maven-cache-pvccontainers:-name:jnlpimage:registry.cn-hangzhou.aliyuncs.com/rookieops/inbound-agent:4.3-4-name:mavenimage:registry.cn-hangzhou.aliyuncs.com/rookieops/maven:3.5.0-alpinecommand:-cattty:truevolumeMounts:-name:maven-cachemountPath:/root/.m2-name:dockerimage:registry.cn-hangzhou.aliyuncs.com/rookieops/docker:19.03.11command:-cattty:truevolumeMounts:-name:docker-sockmount路径:/var/run/docker.sock-name:sonar-scannerimage:registry.cn-hangzhou.aliyuncs.com/rookieops/sonar-scanner:latestcommand:-cattty:true-name:kustomizeimage:registry。cn-hangzhou.aliyuncs.com/rookieops/kustomize:v3.8.1command:-cattty:true-name:kubedogimage:registry.cn-hangzhou.aliyuncs.com/rookieops/kubedog:v0.5.0command:['猫']tty:true-name:trivyimage:registry.cn-hangzhou.aliyuncs.com/rookieops/trivy:v2command:['cat']tty:truevolumeMounts:-name:docker-sockmountPath:/var/run/docker.sock"""}}environment{auth='joker'}options{timestamps()//日志会有时间skipDefaultCheckout()//删除隐式checkoutscm语句disableConcurrentBuilds()//禁止并行超时(time:1,unit:'HOURS')//设置流水线超时时间}stages{//拉取代码stage('GetCode'){steps{checkout([$class:'GitSCM',branches:[[name:"${gitBranch}"]],doGenerateSubmoduleConfigurations:false,extensions:[],submoduleCfg:[],userRemoteConfigs:[[credentialsId:'83d2e934-75c9-48fe-9703-b48e2feff4d8',url:"${gitUrl}"]]])}}//单元测试和编译打包阶段('Build&Test'){steps{container('maven'){script{tools.PrintMes('编译打包','blue')}}}}//代码扫描阶段('CodeScanner'){steps{container('sonar-scanner'){script{tools.PrintMes('codescanning','blue')}}}}//构建镜像阶段('BuildImage'){steps{container('docker'){script{tools.PrintMes('buildimage','blue')}}}}//镜像扫描阶段('VulnerabilityScanner'){steps{container('trivy'){script{tools.PrintMes('mirrorscan','blue')}}}}//推镜像阶段('PushImage'){steps{container('docker'){script{tools.PrintMes('推镜像','blue')}}}}//部署阶段('DeployDEV'){when{branchName'dev'}steps{container('kustomize'){script{tools.PrintMes('部署DEV环境','blue')}}}}stage('DeployTEST'){when{branchName'test'}steps{container('kustomize'){script{tools.PrintMes('DeployTESTenvironment','blue')}}}}stage('DeployUAT'){when{branchName'uat'}steps{container('kustomize'){script{tools.PrintMes('部署UAT环境','blue')}}}}stage('DeployPRE'){when{branchName'pre'}steps{container('kustomize'){script{tools.PrintMes('DeployPREenvironment','blue')}}}}stage('展开oyPROD'){when{branchName'master'}steps{container('kustomize'){script{tools.PrintMes('部署PROD环境','blue')}}}}//跟踪应用启动阶段('CheckAppStart'){steps{container('kubedog'){script{tools.PrintMes('Trackingapplicationstartup','blue')}}}}//接口测试阶段('InterfaceTest'){steps{sh'echo"interfaceTest"'}}}//构建后的操作post{success{script{println('success:只有构建成功才会执行')currentBuild.description+='\n构建成功!'dingmes.SendDingTalk("构建成功?")}}failure{script{println('失败:只有构建失败才会执行')currentBuild.description+='\n构建失败!'dingmes.SendDingTalk("构建failed?")}}aborted{script{println('aborted:只有在构建被取消时才会执行')currentBuild.description+='\nBuildcancelled!'dingmes.SendDingTalk("Buildfailed?","pausedorinterrupted")}}}}(3)在Gitlab上配置hooksettings->webhook。至此,Gitlab和Jenkins的集成就差不多完成了,接下来就是具体的调试和配置了。写在最后的万条路,才是最适合你的。以上是根据工作实际情况发布的运维发布。总体思路和实现方法并不复杂。主要目的是充分利用各个软件的webhook能力和Jenkins灵活的插件功能,让从制定发布计划到执行发布打通。个人觉得还是有必要记录一下的,希望能对这方面有需要的人有所帮助。
