持续构建ci全流程(jenkins+git+maven+docker+sonar+gatling)

概述

image.png
  • 第一个红框里是加特林(gatling)脚本的存放目录位置与结构

  • 第二个红框的Dockerfile也是必须的

  • 项目必须为maven项目

  • 前提用docker-compose构建服务器,步骤如下

    • 创建宿主机挂载目录:mkdir -p /data/docker/ci/nexus /data/docker/ci/jenkins/lib /data/docker/ci/jenkins/home /data/docker/ci/sonarqube /data/docker/ci/postgresql /data/docker/ci/gatling/results

    • 赋权(避免挂载的时候,一些程序需要容器中的用户的特定权限使用):chmod -R 777 /data/docker/ci/nexus /data/docker/ci/jenkins/lib /data/docker/ci/jenkins/home /data/docker/ci/sonarqube /data/docker/ci/postgresql /data/docker/ci/gatling/results

    • 使用docker-compose执行如下脚本

    
    version: '3'
    
    networks:
    
      prodnetwork:
    
        driver: bridge
    
    services:
    
      sonardb:
    
        image: postgres:9.6.6
    
        restart: always
    
        ports:
    
          - "5433:5432"
    
        networks:
    
          - prodnetwork
    
        volumes:
    
          - /data/docker/ci/postgresql:/var/lib/postgresql
    
        environment:
    
          - POSTGRES_USER=sonar
    
          - POSTGRES_PASSWORD=sonar
    
      sonar:
    
        image: sonarqube:6.7.1
    
        restart: always
    
        ports:
    
        - "19000:9000"
    
        - "19092:9092"
    
        networks:
    
          - prodnetwork
    
        depends_on:
    
          - sonardb
    
        volumes:
    
          - /data/docker/ci/sonarqube/conf:/opt/sonarqube/conf
    
          - /data/docker/ci/sonarqube/data:/opt/sonarqube/data
    
          - /data/docker/ci/sonarqube/extension:/opt/sonarqube/extensions
    
          - /data/docker/ci/sonarqube/bundled-plugins:/opt/sonarqube/lib/bundled-plugins
    
        environment:
    
          #- SONARQUBE_JDBC_URL=jdbc:postgresql://sonardb:5433/sonar
    
          - SONARQUBE_JDBC_URL=jdbc:postgresql://sonardb:5432/sonar
    
          - SONARQUBE_JDBC_USERNAME=sonar
    
          - SONARQUBE_JDBC_PASSWORD=sonar
    
      nexus:
    
        image: sonatype/nexus3
    
        restart: always
    
        ports:
    
          - "18081:8081"
    
        networks:
    
          - prodnetwork
    
        volumes:
    
          - /data/docker/ci/nexus:/nexus-data
    
      jenkins:
    
        image: wine6823/jenkins:1.1
    
        restart: always
    
        ports:
    
          - "18080:8080"
    
        networks:
    
          - prodnetwork
    
        volumes:
    
          - /var/run/docker.sock:/var/run/docker.sock
    
          - /etc/localtime:/etc/localtime:ro
    
          - $HOME/.ssh:/root/.ssh
    
          - /data/docker/ci/jenkins/lib:/var/lib/jenkins/
    
          - /usr/bin/docker:/usr/bin/docker
    
          - /data/docker/ci/jenkins/home:/var/jenkins_home
    
        depends_on:
    
          - nexus
    
          - sonar
    
        environment:
    
          - NEXUS_PORT=8081
    
          - SONAR_PORT=9000
    
          - SONAR_DB_PORT=5432
    
    
  • 最后用dockers启动一个nginx服务器,命令如下


docker run --name some-nginx -v /data/docker/ci/gatling/results:/usr/share/nginx/html:ro -p 8080:80 -d nginx

步骤一(jenkins)

image.png
image.png
  • Jenkinsfiles脚本代码如下

node {

/*****************************git代码块***********************************/

    // ! git 仓库路径

    gitUrl = 'https://github.com/14251104246/spring-boot-ci-demo.git'

    // ! git 分支

    gitBranch = 'master'

    // ! git 使用的jenkins证书id

    gitCredential = '5b3912a8-0074-4955-b48f-c0af217785ac'

    stage ('git') {

        git branch: gitBranch,

            credentialsId: gitCredential,

            url: gitUrl

    }

/*****************************预处理代码块***********************************/

    // ! maven最终构建项目ArtifactId(项目目录请和ArtifactId一致)(可改)

    mavenArtifactId = 'yisike-parent'

    // 文件夹分隔

    DELIMITER = '/'

    // jenkins挂载在宿主机的所有项目地址

    volumeRoot = '/data/docker/ci/jenkins/home';

    // jenkins在容器中的所有项目地址

    jenkinsRoot = '/var/jenkins_home'

    // 具体项目工作区

    projectWorkspace = 'workspace'

    // jenkins挂载在宿主机的项目地址

    volumeDeployRootPath = volumeRoot + DELIMITER + projectWorkspace + DELIMITER + env.JOB_NAME

    // jenkins在容器中的项目路径

    jenkinsDeployRootPath = env.WORKSPACE

    // jenkins挂载在宿主机的构建地址

    volumeDeployPath = ''

    // jenkins在容器中的构建路径

    jenkinsDeployPath = ''

    //是否只有一个项目

    mavenSingleModule = true

    String relativePath = ''

    stage ('pre') {

        echo '路径预处理'

        volumeDeployPath = volumeDeployRootPath

        jenkinsDeployPath = jenkinsDeployRootPath

        println 'jenkins挂载在宿主机的项目地址:' + volumeDeployRootPath

        println 'jenkins在容器中的项目路径:' + jenkinsDeployRootPath

        println 'jenkins挂载在宿主机的构建地址:' + volumeDeployPath

        println 'jenkins在容器中的构建路径:' + jenkinsDeployPath

    }

  /*******************************maven代码块*********************************/

    // maven地址

    MVN_HOME = 'docker run -t --rm --name my-maven-project -v '+volumeDeployPath+':/usr/src/mymaven -v $HOME/.m2:/root/.m2 -w /usr/src/mymaven maven:3.3-jdk-8 '

    stage ('mvn') {

        echo 'start mvn'

        //暂时使用sh,后边替换为 ArtifactoryMavenBuild

        stage ('mvn-clean') {

            sh """

${MVN_HOME} mvn clean

"""

        }

        stage ('mvn-package') {

            thisPath = jenkinsDeployRootPath + DELIMITER + (relativePath == null || relativePath.size() == 0 ? relativePath : relativePath + DELIMITER)+ DELIMITER

            sh """

            ${MVN_HOME} mvn package  -DskipTests

            """

        }

        echo 'stop mvn'

    }

/**********************************docker代码块************************************************************/

/**********************************docker代码块************************************************************/

    //服务名称(子模块目录名称)

    def srvName = 'demo'

    //仓库地址

    def registryUrl = 'hboverseas.banggood.cn'

    //远程服务器地址(用于部署)

    def devHost = '122.152.225.111'

    def devDockerDaemon = "tcp://${devHost}:2376"

    //项目名称

    def project = 'ad'

    //远程docker容器启动参数

    def dockerParam = "--name ${srvName} -v /etc/hosts:/etc/hosts -v /data/docker/logs/yisike/yisike-registry:/data/docker/logs --restart=always  -p 8090:8090"

    stage ('docker') {

        echo 'start docker'

        stage ('构建镜像')

        {

            sh """

                cd ${jenkinsDeployPath}/

                docker build -t $registryUrl/$project/$srvName:$BUILD_NUMBER ./

              """

        }

        //stage ('推送镜像')

        //{

        //    sh """

        //      docker push $registryUrl/$project/$srvName:$BUILD_NUMBER

        //      docker rmi $registryUrl/$project/$srvName:$BUILD_NUMBER

        //      """

        //}

        //stage ('部署生产环境')

        //{

        // sh """

        //  docker -H ${devDockerDaemon} pull $registryUrl/$project/$srvName:$BUILD_NUMBER

        //  docker -H ${devDockerDaemon} rm -f ${srvName} | true

        //  docker -H ${devDockerDaemon} run -d  ${dockerParam}  $registryUrl/$project/$srvName:$BUILD_NUMBER

        //    """

        //}

        stage ('部署生产环境')

        {

          sh """

            docker rm -f ${srvName} | true

            docker run -d  ${dockerParam}  $registryUrl/$project/$srvName:$BUILD_NUMBER

            """

        }

        echo 'complete docker'

    }

}

  • 点击保存后进入ci-demo流水线,点击立即构建(图中2是构建结果)
image.png

步骤二(集成sonar)

  • 进入sonarQube服务器创建一个新的需要分析的项目(打开官方引导教程)
image.png
  • 复制生成的mvn命令
image.png
image.png
  • 把mvn命令加入到Jenkinsfiles脚本,如下

node {

/*****************************git代码块***********************************/

    // ! git 仓库路径

    gitUrl = 'https://github.com/14251104246/spring-boot-ci-demo.git'

    // ! git 分支

    gitBranch = 'master'

    // ! git 使用的jenkins证书id

    gitCredential = '5b3912a8-0074-4955-b48f-c0af217785ac'

    stage ('git') {

        git branch: gitBranch,

            credentialsId: gitCredential,

            url: gitUrl

    }

/*****************************预处理代码块***********************************/

    // ! maven最终构建项目ArtifactId(项目目录请和ArtifactId一致)(可改)

    mavenArtifactId = 'yisike-parent'

    // 文件夹分隔

    DELIMITER = '/'

    // jenkins挂载在宿主机的所有项目地址

    volumeRoot = '/data/docker/ci/jenkins/home';

    // jenkins在容器中的所有项目地址

    jenkinsRoot = '/var/jenkins_home'

    // 具体项目工作区

    projectWorkspace = 'workspace'

    // jenkins挂载在宿主机的项目地址

    volumeDeployRootPath = volumeRoot + DELIMITER + projectWorkspace + DELIMITER + env.JOB_NAME

    // jenkins在容器中的项目路径

    jenkinsDeployRootPath = env.WORKSPACE

    // jenkins挂载在宿主机的构建地址

    volumeDeployPath = ''

    // jenkins在容器中的构建路径

    jenkinsDeployPath = ''

    //是否只有一个项目

    mavenSingleModule = true

    String relativePath = ''

    stage ('pre') {

        echo '路径预处理'

        volumeDeployPath = volumeDeployRootPath

        jenkinsDeployPath = jenkinsDeployRootPath

        println 'jenkins挂载在宿主机的项目地址:' + volumeDeployRootPath

        println 'jenkins在容器中的项目路径:' + jenkinsDeployRootPath

        println 'jenkins挂载在宿主机的构建地址:' + volumeDeployPath

        println 'jenkins在容器中的构建路径:' + jenkinsDeployPath

    }

  /*******************************maven代码块*********************************/

    // maven地址

    MVN_HOME = 'docker run -t --rm --name my-maven-project -v '+volumeDeployPath+':/usr/src/mymaven -v $HOME/.m2:/root/.m2 -w /usr/src/mymaven maven:3.3-jdk-8 '

    stage ('mvn') {

        echo 'start mvn'

        //暂时使用sh,后边替换为 ArtifactoryMavenBuild

        stage ('mvn-clean') {

            sh """

${MVN_HOME} mvn clean

"""

        }

        stage ('mvn-package') {

            thisPath = jenkinsDeployRootPath + DELIMITER + (relativePath == null || relativePath.size() == 0 ? relativePath : relativePath + DELIMITER)+ DELIMITER

            sh """

            ${MVN_HOME} mvn package  -DskipTests

            """

        }

        stage ('mvn-代码质量') {

            sh """

            ${MVN_HOME} mvn sonar:sonar \

                            -Dsonar.host.url=http://172.17.0.1:19000 \

                            -Dsonar.login=40aee4cc56ecf6d6742af9cb36fd0f00f896e306

            """

        }

        echo 'stop mvn'

    }

/**********************************docker代码块************************************************************/

/**********************************docker代码块************************************************************/

    //服务名称(子模块目录名称)

    def srvName = 'demo'

    //仓库地址

    def registryUrl = 'hboverseas.banggood.cn'

    //远程服务器地址(用于部署)

    def devHost = '122.152.225.111'

    def devDockerDaemon = "tcp://${devHost}:2376"

    //项目名称

    def project = 'ad'

    //远程docker容器启动参数

    def dockerParam = "--name ${srvName} -v /etc/hosts:/etc/hosts -v /data/docker/logs/yisike/yisike-registry:/data/docker/logs --restart=always  -p 8090:8090"

    stage ('docker') {

        echo 'start docker'

        stage ('构建镜像')

        {

            sh """

                cd ${jenkinsDeployPath}/

                docker build -t $registryUrl/$project/$srvName:$BUILD_NUMBER ./

              """

        }

        //stage ('推送镜像')

        //{

        //    sh """

        //      docker push $registryUrl/$project/$srvName:$BUILD_NUMBER

        //      docker rmi $registryUrl/$project/$srvName:$BUILD_NUMBER

        //      """

        //}

        //stage ('部署生产环境')

        //{

        // sh """

        //  docker -H ${devDockerDaemon} pull $registryUrl/$project/$srvName:$BUILD_NUMBER

        //  docker -H ${devDockerDaemon} rm -f ${srvName} | true

        //  docker -H ${devDockerDaemon} run -d  ${dockerParam}  $registryUrl/$project/$srvName:$BUILD_NUMBER

        //    """

        //}

        stage ('部署生产环境')

        {

          sh """

            docker rm -f ${srvName} | true

            docker run -d  ${dockerParam}  $registryUrl/$project/$srvName:$BUILD_NUMBER

            """

        }

        echo 'complete docker'

    }

}

  • 点击保存后进入ci-demo流水线,点击立即构建

步骤三(集成gatling)

  • 打开jenkins服务器首页,创建gatling的测试

  • Jenkinsfile脚本如下


node {

/*****************************git代码块***********************************/

    // ! git 仓库路径

    gitUrl = 'https://github.com/14251104246/spring-boot-ci-demo.git'

    // ! git 分支

    gitBranch = 'master'

    // ! git 使用的jenkins证书id

    gitCredential = '5b3912a8-0074-4955-b48f-c0af217785ac'

    stage ('git') {

        git branch: gitBranch,

            credentialsId: gitCredential,

            url: gitUrl

    }

/*****************************预处理代码块***********************************/

    // ! maven最终构建项目ArtifactId(项目目录请和ArtifactId一致)(可改)

    mavenArtifactId = 'yisike-parent'

    // 文件夹分隔

    DELIMITER = '/'

    // jenkins挂载在宿主机的所有项目地址

    volumeRoot = '/data/docker/ci/jenkins/home';

    // jenkins在容器中的所有项目地址

    jenkinsRoot = '/var/jenkins_home'

    // 具体项目工作区

    projectWorkspace = 'workspace'

    // jenkins挂载在宿主机的项目地址

    volumeDeployRootPath = volumeRoot + DELIMITER + projectWorkspace + DELIMITER + env.JOB_NAME

    // jenkins在容器中的项目路径

    jenkinsDeployRootPath = env.WORKSPACE

    // jenkins挂载在宿主机的构建地址

    volumeDeployPath = ''

    // jenkins在容器中的构建路径

    jenkinsDeployPath = ''

    //是否只有一个项目

    mavenSingleModule = true

    String relativePath = ''

    stage ('pre') {

        echo '路径预处理'

        volumeDeployPath = volumeDeployRootPath

        jenkinsDeployPath = jenkinsDeployRootPath

        println 'jenkins挂载在宿主机的构建地址:' + volumeDeployPath

        println 'jenkins在容器中的构建路径:' + jenkinsDeployPath

    }

  /*******************************gatling代码块*********************************/

    scalaScriptDir = volumeDeployPath + '/src/test/gatling/user-files'

    resultDir = '/data/docker/ci/gatling/results'

    // 加特林命令行

    COM_DOCKER = 'docker run  -t --rm  -v '+ scalaScriptDir +':/opt/gatling/user-files -v '+ resultDir +':/opt/gatling/results denvazh/gatling --mute'

    stage ('gatling') {

        echo 'start gatling'

        //暂时使用sh,后边替换为 ArtifactoryMavenBuild

        stage ('gatling') {

            sh """

            rm -f out.txt | true

${COM_DOCKER}  1>>out.txt

cat out.txt

echo http://localhost:8080\$(cat out.txt | grep 'Please open the following file' | cut -b 53- )

"""

        }

        echo 'stop gatling'

    }

}

  • 创建完成后,点击构建,等待构建完成后查看输出
image.png
  • 点击上图中2指向的蓝点,查看最底下的输出
image.png
  • 点击链接,查看gatling的测试结果
image.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,711评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,079评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,194评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,089评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,197评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,306评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,338评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,119评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,541评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,846评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,014评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,694评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,322评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,026评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,257评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,863评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,895评论 2 351

推荐阅读更多精彩内容