【实战】企业级持续集成(DevOps自动化平台):git + gitlab + jenkins + pipeline + maven + harbor + docker + k8s...

为什么要写企业级持续集成(jenkins + pipeline + k8s)?

目前网上自动化持续集成的资料很多,但基本上都是局限于jenkins自由风格的job,结合shell脚本来实现持续集成,这种方式的缺点也很明显:

  1、构建出问题,排查困难

  2、构建节点挂了,就不能完成构建任务

而当前主流技术是 “ k8s + 微服务 ” 等,我们完全可以利用k8s的优势来完成持续构建任务,每次构建时可以调度到任意节点,或者是具有指定标签的节点,这就实现了高可用,另外,结合pipeline,可以轻松简单实现持续集成,并且哪个阶段出问题了一目了然,排查起来也容易。

自动化测试框架

0基础到实现:java + testng + httpclient + allure

参考:https://www.cnblogs.com/uncleyong/p/15867903.html

企业级持续集成技术栈

git + gitlab + jenkins + pipeline + maven + harbor + docker + k8s

可以整合python、java等各种自动化测试框架

流程:拉取代码--》mvn打包--》构建镜像--》新镜像发布到k8s--》拉取自动化测试代码--》自动化测试--》allure报告

环境:jenkins使用k8s作为构建环境,在某个节点执行测试

【实战】企业级持续集成(DevOps自动化平台):git + gitlab + jenkins + pipeline + maven + harbor + docker + k8s..._第1张图片

环境规划

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

环境搭建(含必备基础)

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

pipeline设计

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

使用Blue Ocean设计pipeline脚本:https://www.cnblogs.com/uncleyong/p/16727971.html

说明:由于资源不足,暂未加入sonarqube等

【实战】企业级持续集成(DevOps自动化平台):git + gitlab + jenkins + pipeline + maven + harbor + docker + k8s..._第2张图片

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: v1
kind: Pod
spec:
  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: '[email protected]: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: '[email protected]: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})"]
          )
        }
      }
    }

构建及效果展示

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

【实战】企业级持续集成(DevOps自动化平台):git + gitlab + jenkins + pipeline + maven + harbor + docker + k8s..._第3张图片

也可以放gitlab上,选择SCM

【实战】企业级持续集成(DevOps自动化平台):git + gitlab + jenkins + pipeline + maven + harbor + docker + k8s..._第4张图片

【实战】企业级持续集成(DevOps自动化平台):git + gitlab + jenkins + pipeline + maven + harbor + docker + k8s..._第5张图片

【实战】企业级持续集成(DevOps自动化平台):git + gitlab + jenkins + pipeline + maven + harbor + docker + k8s..._第6张图片

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

【实战】企业级持续集成(DevOps自动化平台):git + gitlab + jenkins + pipeline + maven + harbor + docker + k8s..._第7张图片

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

【实战】企业级持续集成(DevOps自动化平台):git + gitlab + jenkins + pipeline + maven + harbor + docker + k8s..._第8张图片

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

【实战】企业级持续集成(DevOps自动化平台):git + gitlab + jenkins + pipeline + maven + harbor + docker + k8s..._第9张图片

部署到k8s的通知

【实战】企业级持续集成(DevOps自动化平台):git + gitlab + jenkins + pipeline + maven + harbor + docker + k8s..._第10张图片

消息

【实战】企业级持续集成(DevOps自动化平台):git + gitlab + jenkins + pipeline + maven + harbor + docker + k8s..._第11张图片

运行自动化测试的通知

【实战】企业级持续集成(DevOps自动化平台):git + gitlab + jenkins + pipeline + maven + harbor + docker + k8s..._第12张图片

消息

【实战】企业级持续集成(DevOps自动化平台):git + gitlab + jenkins + pipeline + maven + harbor + docker + k8s..._第13张图片

生成allure测试报告的通知

【实战】企业级持续集成(DevOps自动化平台):git + gitlab + jenkins + pipeline + maven + harbor + docker + k8s..._第14张图片

消息

【实战】企业级持续集成(DevOps自动化平台):git + gitlab + jenkins + pipeline + maven + harbor + docker + k8s..._第15张图片

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

【实战】企业级持续集成(DevOps自动化平台):git + gitlab + jenkins + pipeline + maven + harbor + docker + k8s..._第16张图片

测试报告

【实战】企业级持续集成(DevOps自动化平台):git + gitlab + jenkins + pipeline + maven + harbor + docker + k8s..._第17张图片

【实战】企业级持续集成(DevOps自动化平台):git + gitlab + jenkins + pipeline + maven + harbor + docker + k8s..._第18张图片

【建议收藏备用】热门技术、项目实战、简历、笔试题、面试题、职业规划(助你少走弯路,轻松跳槽加薪)

点击学习:https://www.cnblogs.com/uncleyong/p/15777706.html

包含以下内容:

测试实战:
	性能:jmeter + k8s + 微服务 + skywalking + efk,测试都在学的热门技术
	自动化:python版、java版
	测开:待更新

简历:写出一份高质量简历

笔试题:linux、shell、mysql、java、python、测开、性能、自动化、docker、k8s等

职业规划:让你少走弯路,尽早跳槽加薪,方向不对,努力白费

摸鱼:上班正确的摸鱼方式

原文会持续更新,原文地址: https://www.cnblogs.com/uncleyong/p/16721826.html

你可能感兴趣的:(jenkins,docker,devops,ci,自动化)