持续集成(jenkins + pipeline + k8s)

目前网上自动化持续集成的资料很多,但基本上都是局限于jenkins自由风格的job,结合shell脚本来实现持续集成,这种方式的缺点也很明显:
构建出问题,排查困难构建节点挂了,就不能完成构建任务
而当前主流技术是 “ k8s + 微服务 ” 等,我们完全可以利用k8s的优势来完成持续构建任务,每次构建时可以调度到任意节点,或者是具有指定标签的节点,这就实现了高可用,另外,结合pipeline,可以轻松简单实现持续集成,并且哪个阶段出问题了一目了然,排查起来也容易。

02

自动化测试框架

_____

0基础到实现:java + testng + httpclient + allure参考:https://www.cnblogs.com/uncleyong/p/15867903.html

03

企业级持续集成技术栈

_____

git + gitlab + jenkins + pipeline + maven + harbor + docker + k8s可以整合python、java等各种自动化测试框架流程:拉取代码--》mvn打包--》构建镜像--》新镜像发布到k8s--》拉取自动化测试代码--》自动化测试--》allure报告环境:jenkins使用k8s作为构建环境,在某个节点执行测试

 

 

 

04

环境规划

_____

192.168.117.160:harbor、jenkins、maven

192.168.117.161:k8s-master

192.168.117.162:k8s-node01

192.168.117.163:k8s-node02

192.168.117.180:gitlab

每台虚拟机都安装了git 

05

环境搭建

_____

git安装及使用:https://www.cnblogs.com/uncleyong/p/10854115.html

gitlab安装及使用:https://www.cnblogs.com/uncleyong/p/16557785.html

maven安装及使用:https://www.cnblogs.com/uncleyong/p/10743181.html

docker安装及使用:https://www.cnblogs.com/uncleyong/p/8894133.html

harbor安装以及使用:https://www.cnblogs.com/uncleyong/p/15469575.html

k8s安装:https://www.cnblogs.com/uncleyong/p/15499732.html(k8s操作:https://www.cnblogs.com/uncleyong/p/15499743.html)

jenkins搭建及devops自动化平台相关配置:https://www.cnblogs.com/uncleyong/p/16555667.html

allure报告:allure-commandline下载、安装、配置(linux或者docker),https://www.cnblogs.com/uncleyong/p/16726826.html

jenkins把自动化测试结果发送到钉钉群:https://www.cnblogs.com/uncleyong/p/16724590.html

06

pipeline设计

_____

pipeline常用功能:https://www.cnblogs.com/uncleyong/p/16705620.html

使用Blue Ocean设计pipeline脚本:https://www.cnblogs.com/uncleyong/p/16727971.html说明:由于资源不足,暂未加入sonarq

 

 

07

pipeline具体实现

 

_____

结合上面在Blue Ocean中设计的pipeline骨架,我们来完善并实现整个过程

parameters

可以选择要构建的分支
parameters {gitParameter branch: '', branchFilter: 'origin/(.*)', defaultValue: '', description: '构建的分支', name: 'BRANCH', quickFilterEnabled: false, selectedValue: 'NONE', sortMode: 'NONE', tagFilter: '*', type: 'GitParameterDefinition'}
 

环境变量

environment {  HARBOR_ADDRESS = "192.168.117.160"  IMAGE_NAME = "gift"  NAMESPACE = "gift"}
 

agent

k8s作为构建环境
  agent {    kubernetes {      cloud 'qzcsbj_kubernetes'      yaml '''apiVersion: v1kind: Podspec:  containers:    - image: 'registry.cn-chengdu.aliyuncs.com/qzcsbj6/jnlp:alpine'           name: jnlp      imagePullPolicy: IfNotPresent      args: [\'$(JENKINS_SECRET)\', \'$(JENKINS_NAME)\']      volumeMounts:        - mountPath: "/etc/localtime"          name: "localtime"          readOnly: false    - image: "registry.cn-chengdu.aliyuncs.com/qzcsbj6/kubectl"      imagePullPolicy: "IfNotPresent"      name: "kubectl"      tty: true      command:        - "cat"      env:        - name: "LANGUAGE"          value: "en_US:en"        - name: "LANG"          value: "en_US.UTF-8"      volumeMounts:        - mountPath: "/etc/localtime"          name: "localtime"          readOnly: false    - image: "registry.cn-chengdu.aliyuncs.com/qzcsbj6/docker"      imagePullPolicy: "IfNotPresent"      name: "docker"      tty: true      command:        - "cat"      env:        - name: "LANGUAGE"          value: "en_US:en"        - name: "LANG"          value: "en_US.UTF-8"      volumeMounts:        - mountPath: "/etc/localtime"          name: "localtime"          readOnly: false        - mountPath: "/var/run/docker.sock"          name: "dockersock"          readOnly: false    - image: "registry.cn-chengdu.aliyuncs.com/qzcsbj6/maven"      imagePullPolicy: "IfNotPresent"      name: "maven"      tty: true      command:        - "cat"      env:        - name: "LANGUAGE"          value: "en_US:en"        - name: "LANG"          value: "en_US.UTF-8"      volumeMounts:        - mountPath: "/etc/localtime"          name: "localtime"        - mountPath: "/root/.m2/"          name: "m2dir"          readOnly: false    - image: "registry.cn-chengdu.aliyuncs.com/allure-commandline"      imagePullPolicy: "IfNotPresent"      name: "allure"      tty: true      command:        - "cat"      env:        - name: "LANGUAGE"          value: "en_US:en"        - name: "LANG"          value: "en_US.UTF-8"      volumeMounts:        - mountPath: "/etc/localtime"          name: "localtime"          readOnly: false  restartPolicy: "Never"  volumes:    - name: "dockersock"      hostPath:        path: "/var/run/docker.sock"    - name: "localtime"      hostPath:        path: "/usr/share/zoneinfo/Asia/Shanghai"    - name: "m2dir"      hostPath:        path: "/opt/m2"'''    }  }
 

pull project code

stage('pull project code') {  parallel {    stage('ui build') {      when {        expression {          env.gitlabBranch == null        }      }      steps {        sh """          echo '=================开始拉取项目代码'        """        git(url: 'git@192.168.117.180:qzcsbj/gift.git', branch: "${BRANCH}", credentialsId: 'qzcsbj_gitlab')        script {            COMMIT_ID = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim()            TAG = BUILD_TAG + '-' + COMMIT_ID            println "Current branch is ${BRANCH}, Commit ID is ${COMMIT_ID}, Image TAG is ${TAG}"        }                 }      post {        failure {          dingtalk (            robot:'dd01',            type:'MARKDOWN',            atAll: true,            title: "notice: 拉取项目代码失败",            text: ["#### '${JOB_NAME}'项目代码拉取失败\n - 构建:第'${BUILD_NUMBER}'次\n - 状态:'${currentBuild.result}'\n - [查看本次构建详情](${BUILD_URL})"]          )        }      }    }    stage('trigger build') {      steps {        sh """          echo "待更新。。。"        """      }    }  }}

 

mvn package

stage('mvn package') {  steps {    container(name: 'maven') {      sh """        echo '=================mvn开始打包'        mvn clean package -Dmaven.test.skip=true        echo '=================mvn打包完成'      """    }  }  post {    failure {      dingtalk (        robot:'dd01',        type:'MARKDOWN',        atAll: true,        title: "notice: mvn package失败",        text: ["#### '${JOB_NAME}'项目mvn package失败\n - 构建:第'${BUILD_NUMBER}'次\n - 状态:'${currentBuild.result}'\n - [查看本次构建详情](${BUILD_URL})"]      )    }  }}
  

build and push image

stage('build and push image') {  environment {    HARBOR_USER = credentials('qzcsbj_harbor')  }  steps {    container(name: 'docker') {      sh """        echo '=================开始构建镜像'        docker build -t ${HARBOR_ADDRESS}/${REGISTRY_DIR}/${IMAGE_NAME}:${TAG} .        docker login -u ${HARBOR_USER_USR} -p ${HARBOR_USER_PSW} ${HARBOR_ADDRESS}        docker push ${HARBOR_ADDRESS}/${REGISTRY_DIR}/${IMAGE_NAME}:${TAG}        echo '=================镜像推送完成'      """    }  }  post {    failure {      dingtalk (        robot:'dd01',        type:'MARKDOWN',        atAll: true,        title: "notice: 构建或者推送镜像失败",        text: ["#### '${JOB_NAME}'项目构建或者推送镜像失败\n - 构建:第'${BUILD_NUMBER}'次\n - 状态:'${currentBuild.result}'\n - [查看本次构建详情](${BUILD_URL})"]      )    }  }}
 

deploy to k8s

stage('deploy to k8s') {  environment {    MY_KUBECONFIG = credentials('qzcsbj_k8s')  }  steps {    container(name: 'kubectl'){      sh """        echo '=================开始部署到k8s'        /usr/local/bin/kubectl --kubeconfig $MY_KUBECONFIG set image deploy -l app=${IMAGE_NAME} ${IMAGE_NAME}=${HARBOR_ADDRESS}/${REGISTRY_DIR}/${IMAGE_NAME}:${TAG} -n $NAMESPACE        echo '=================部署到k8s完成'      """    }  }  post {    success {      dingtalk (        robot:'dd01',        type:'MARKDOWN',        atAll: true,        title: "notice: 自动化部署到k8s完成",        text: ["#### '${JOB_NAME}'项目自动化部署到k8s完成\n - 构建:第'${BUILD_NUMBER}'次\n - 状态:'${currentBuild.result}'\n - [查看本次构建详情](${BUILD_URL})"]      )    }    failure {      dingtalk (        robot:'dd01',        type:'MARKDOWN',        atAll: true,        title: "notice: 自动化部署到k8s失败",        text: ["#### '${JOB_NAME}'项目自动化部署到k8s失败\n - 构建:第'${BUILD_NUMBER}'次\n - 状态:'${currentBuild.result}'\n - [查看本次构建详情](${BUILD_URL})"]      )    }  }}
 

pull autotest code

stage("pull autotest code"){  steps{    sh """      echo '=================开始拉取自动化测试代码'    """    git(      credentialsId: 'qzcsbj_gitlab',      url: 'git@192.168.117.180:root/apiautotest.git'    )  }  post {    failure {      dingtalk (        robot:'dd01',        type:'MARKDOWN',        atAll: true,        title: "notice: 拉取自动化测试代码失败",        text: ["#### 拉取自动化测试代码失败\n - 构建:第'${BUILD_NUMBER}'次\n - 状态:'${currentBuild.result}'\n - [查看本次构建详情](${BUILD_URL})"]      )    }  }}
  

run autotest

stage("run autotest"){  steps{    sh """      mvn clean test -Dsurefire.suiteXmlFiles=testngXML/testng.xml    """  }  post {    success {      dingtalk (        robot:'dd01',        type:'MARKDOWN',        atAll: true,        title: "notice: 自动化测试完成",        text: ["#### '${JOB_NAME}'项目自动化测试完成\n - 构建:第'${BUILD_NUMBER}'次\n - 状态:'${currentBuild.result}'\n - [查看本次构建详情](${BUILD_URL}console)"]      )    }    failure {      dingtalk (        robot:'dd01',        type:'MARKDOWN',        atAll: true,        title: "notice: 自动化测试运行出错",        text: ["#### '${JOB_NAME}'项目自动化测试运行出错\n - 构建:第'${BUILD_NUMBER}'次\n - 状态:'${currentBuild.result}'\n - [查看本次构建详情](${BUILD_URL})"]      )    }  }}
  

allure report

stage("allure report"){  steps{    sh """      echo '=================开始生成测试报告'    """    allure(      includeProperties: false,      jdk: '',      results: [[path: 'target/allure-results']]    )  }  post {    success {      dingtalk (        robot:'dd01',        type:'MARKDOWN',        atAll: true,        title: "notice: 自动化测试报告已生成,全部通过",        text: ["#### '${JOB_NAME}'项目自动化测试报告已生成,全部通过\n - 构建:第'${BUILD_NUMBER}'次\n - 状态:'${currentBuild.result}'\n - [查看本次测试报告](${BUILD_URL}allure)"]      )    }    unstable {      dingtalk (        robot:'dd01',        type:'MARKDOWN',        atAll: true,        title: "notice: 自动化测试报告已生成,有未通过的",        text: ["#### '${JOB_NAME}'项目自动化测试报告已生成,有未通过的\n - 构建:第'${BUILD_NUMBER}'次\n - 状态:'${currentBuild.result}'\n - [查看本次测试报告](${BUILD_URL}allure)"]      )    }    failure {      dingtalk (        robot:'dd01',        type:'MARKDOWN',        atAll: true,        title: "notice: 自动化测试报告生成出错",        text: ["#### '${JOB_NAME}'项目自动化测试报告生成出错\n - 构建:第'${BUILD_NUMBER}'次\n - 状态:'${currentBuild.result}'\n - [查看本次构建详情](${BUILD_URL})"]      )    }  }}
 

08

构建及效果展示

 

_____

pipeline脚本可以放在流水线项目的脚本框中

 

 

 

也可以放gitlab上,选择SCM

 

 

 

 

 

 

  
pipeline脚本放到Jenkinsfile中,Jenkinsfile在gift项目master分支下

 

 


第一次构建,点击“Build Now”,会失败,因为我们使用了参数化构建,这次构建获取不到参数值

 

 

 

刷新页面,就可以看到参数化构建了,就可以选择要构建的分支

 

 


部署到k8s的通知

 

 

消息

 

 

 

运行自动化测试的通知

 

 

消息

 

 

 

生成allure测试报告的通知

 

 

消息

 

 

测试报告的通知可以优化,直接链接到allure测试报告

 

 


测试报告

 

 

posted @ 2022-10-09 15:34  AlamZ  阅读(1775)  评论(1编辑  收藏  举报