• Jenkins构建Maven项目



    Jenkins项目构建类型

    Jenkins中自动构建项目的类型有很多,常用的有如下的三种:

    • 自由风格软件项目(FreeStyle Project)
    • Maven项目(Maven Project)
    • 流水线项目(Pipeline Project)

    每种类型的构建其实都可以完成一样的构建过程和结果,只是在操作方式、灵活度等方面有所区别,在实际开发中可以根据自己的需求和习惯灵活选择(强烈推荐流水线类型,因为灵活度非常高)


    自由风格项目构建

    安装Publish over SSH插件

    在这里插入图片描述

    配置Publish over SSH

    • Manage Jenkins–>Configure System。

    在这里插入图片描述

    • 找到Publish over SSH,新增SSH Servers:

    在这里插入图片描述

    • 添加远程服务器的配置信息:

    在这里插入图片描述


    创建项目

    在这里插入图片描述

    配置源码管理,从Gitee或者Github或者Gitlab上拉取代码

    在这里插入图片描述

    编译打包

    • 构建–>添加构建步骤–>Executor Shell。
    echo "构建开始"
    mvn clean install -Dmaven.test.skip=true
    echo "构建成功"
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    部署

    • 将SpringBoot生成的jar包发送到远程服务器。
    • 在远程服务器192.168.18.102新建stop.sh和start.sh文件:
    cd /usr/local
    vim stop.sh
    
    • 1
    • 2
    #!/bin/bash
    echo "stop SpringBoot BAppApiServerApplication"
    pid=`ps -ef | grep java | grep -v grep | awk '{print $2}'`
    echo “旧应用进程id:$pid”
    if [ -n "$pid" ]
    then
    kill -9 $pid
    rm -rf springboot2-1.0.jar
    fi
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    vim start.sh
    
    • 1
    #!/bin/bash
    export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-11.0.9.11-2.el7_9.x86_64
    echo ${JAVA_HOME}
    echo "授权当前用户"
    chmod 777 /usr/local/springboot2-1.0.jar
    echo "执行...."
    cd /usr/local/
    nohup ${JAVA_HOME}/bin/java -jar springboot2-1.0.jar > /dev/null &
    echo "启动成功"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 构建后操作–>Send Build artifacts over SSH:

    在这里插入图片描述

    cd /usr/local
    chmod 777 *.sh
    ./stop.sh
    ./start.sh
    
    • 1
    • 2
    • 3
    • 4
    • 点击Build Now即可。

    Maven项目构建

    ● Maven项目构建和自由风格项目构建差不多,唯一不同的是,只能只用Maven来构建项目。

    ● 需要安装Maven Integration插件。

    在这里插入图片描述
    使用Maven项目构建的方式和自由风格项目构建的方式类似,只是在构建的时候强制使用Maven工具来构建项目而已。

    在这里插入图片描述


    Pipeline流水线项目构建(强烈推荐)

    Pipeline,简单来说,就是一套运行在Jenkins上的工作流框架,将原本独立运行于单个或多个节点的任务连接起来,实现单个任务难以完成的复杂流程编排和可视化的工作

    好处:

    ● 代码:Pipeline以代码的形式实现,通常被检入源代码控制,使团队能够编辑,审查和迭代其传送流程。
    ● 持久:无论是计划内还是计划外的服务器重启,Pipeline都是可恢复的。
    ● 可停止:Pipeline可以接受交互式输入,以确定是否继续执行Pipeline。
    ● 多功能:Pipeline支持现实世界中复杂的持续交付要求。它支持fork/join,循环执行,并行执行任务的功能。
    ● 可扩展:Pipeline插件支持其DSL的自定义扩展,以及和其他插件集成的多个选项。

    如何创建Jenkins的Pipeline:

    ● Pipeline脚本是由Groovy语言实现的,但是我们没必要单独去学习Pipeline。
    ● Pipeline支持两种语法:Declarative(声明式)和Script Pipeline(脚本式)语言。
    ● Pipeline支持两种创建方法:可以直接在Jenkins的Web UI界面输入脚本,也可以通过创建一个Jenkinsfile脚本文件放入到项目源代码库中(推荐)。


    安装Pipeline插件

    • Manage Jenkins–>Manage Plugins–>可选插件:

    在这里插入图片描述

    • 安装插件后,创建项目的时候就会多“流水线”类型:

    在这里插入图片描述


    Pipeline语法快速入门之Declarative声明式

    创建项目:

    在这里插入图片描述

    • 流水线–>选择Hello World模板:

    在这里插入图片描述

    • 生成的内容如下:
    pipeline {
        agent any
        
        stages {
            stage('Hello') {
                steps {
                    echo 'Hello World'
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    1. stages:代表整个流水线的所有执行阶段。通常而言,stages只有1个,里面包含多个stage。
    2. stage:代表流水线中的某个阶段,可能会出现多个。一般分为拉取代码、编译构建、部署等阶段。
    3. steps:代表一个阶段内需要执行的逻辑。steps里面是shell脚本,git拉取代码,ssh远程发布等任意内容。

    • 编写一个简单声明式的Pipeline:
    pipeline {
        agent any
    
        stages {
            stage('拉取代码') {
                steps {
                    echo '拉取代码'
                }
            }
    		stage('编译构建') {
                steps {
                    echo '编译构建'
                }
            }
    		stage('项目部署') {
                steps {
                    echo '项目部署'
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 点击构建,可以看到整个构建过程:

    在这里插入图片描述


    Pipeline语法快速入门之脚本式

    ● 创建项目和声明式一样。

    ● 流水线–>选择Script Pipeline:

    在这里插入图片描述
    生成的内容如下:

    node {
        def mvnHome
        stage('Preparation') { // for display purposes
            // Get some code from a GitHub repository
            git 'https://github.com/jglick/simple-maven-project-with-tests.git'
            // Get the Maven tool.
            // ** NOTE: This 'M3' Maven tool must be configured
            // **       in the global configuration.
            mvnHome = tool 'M3'
        }
        stage('Build') {
            // Run the maven build
            withEnv(["MVN_HOME=$mvnHome"]) {
                if (isUnix()) {
                    sh '"$MVN_HOME/bin/mvn" -Dmaven.test.failure.ignore clean package'
                } else {
                    bat(/"%MVN_HOME%\bin\mvn" -Dmaven.test.failure.ignore clean package/)
                }
            }
        }
        stage('Results') {
            junit '**/target/surefire-reports/TEST-*.xml'
            archiveArtifacts 'target/*.jar'
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • node:节点,一个Node就是一个Jenkins节点,Master或者Agent,是执行Step的具体运行环境。
    • Stage:阶段,一个Pipeline可以划分为若干个Stage,每个Stage代表一组操作,比如Build、Test、Deploy、State是一个逻辑分组的概念。
    • Step:步骤,Step是最基本的操作单元,可以是打印一句话,也可以是构建一个Docker镜像,由各类Jenkins插件提供。比如命令:sh ‘make’,相当于我们平时Shell终端中执行的make命令一样。

    编写一个简单的脚本式Pipeline:

    node {
        def mvnHome
        stage('拉取代码') { 
           echo '拉取代码'
        }
        stage('编译构建') {
             echo '编译构建'
        }
        stage('项目部署') {
            echo '项目部署'
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    构建结果和声明式一样。


    拉取代码

    在这里插入图片描述
    在这里插入图片描述

    • 拉取代码的流水线的声明式代码:
    pipeline {
        agent any
    
        stages {
            stage('拉取代码') {
                steps {
    checkout([$class: 'GitSCM', branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: 'cde7fe8a-f426-4f93-9f05-e96e60177952', url: 'https://gitee.com/DaHuYuXiXi/volunteer.git']]])
                }
            }
    		
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    编译打包

    • 和上面拉取代码的步骤一样。

    在这里插入图片描述

    • 编译打包的流水线的声明式代码:
    pipeline {
        agent any
    
        stages {
            stage('拉取代码') {
                steps {
                    checkout([$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: '7d5c4945-2533-41e2-bd47-5dd97eb37f38', url: 'git@192.168.18.100:develop_group/springboot2.git']]])
                }
            }
    		stage('编译打包') {
                steps {
                    sh '''echo "开始构建"
                    mvn clean install -Dmaven.test.skip=true
                    echo "构建结束"'''
                }
            }
    				
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    远程部署

    • 和上面拉取代码的步骤一样。

    在这里插入图片描述

    • 远程部署的流水线的声明式代码:
    pipeline {
        agent any
    
        stages {
            stage('拉取代码') {
                steps {
                    checkout([$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: '7d5c4945-2533-41e2-bd47-5dd97eb37f38', url: 'git@192.168.18.100:develop_group/springboot2.git']]])
                }
            }
    		stage('编译打包') {
                steps {
                    sh '''echo "开始构建"
                    mvn clean install -Dmaven.test.skip=true
                    echo "构建结束"'''
                }
            }
    		stage('远程部署') {
                steps {
                    sshPublisher(publishers: [sshPublisherDesc(configName: '192.168.18.102', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '''cd /usr/local
    chmod 777 *.sh
    ./stop.sh
    ./start.sh''', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: 'target', sourceFiles: 'target/*.jar')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
                }
            }
    				
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    Pipeline Script from SCM(强烈推荐)

    ● 之前都是直接在Jenkins的UI界面里面编写Pipeline代码,这样很不方便脚本维护,建议是把Pipeline脚本放在项目中(一起进行版本控制)。
    ● 在项目的根目录建立Jenkinsfile文件,把内容复制到该文件中:

    在这里插入图片描述
    ● 将Jenkinsfile文件上传到Gitee,Github或者GitLab中。
    ● 在项目中引用该文件:

    在这里插入图片描述


    构建细节

    常用的构建触发器

    ● Jenkins内置4种构建触发器:
    ○ 触发远程构建。
    ○ 其他工程构建后触发(Build after other projects are build)。
    ○ 定时构建(Build periodically)。
    ○ 轮询SCM(Poll SCM)。

    触发远程构建

    在这里插入图片描述

    • 触发构建的URL:http://192.168.18.101:8888/job/test04/build?token=666。

    其他工程构建后触发

    在这里插入图片描述


    定时构建

    在这里插入图片描述
    定时字符串从左往右分别为:分 时 日 月 周。

    一些定时表达式的例子(H代表形参 ):

    • 每30分钟构建一次: H/30 10:02 10:32
    • 每2个小时构建一次: H H/2 *
    • 每天的8点,12点,22点,一天构建3次: (多个时间点中间用逗号隔开) 0 8,12,22 *
    • 每天中午12点定时构建一次:H 12 *
    • 每天下午18点定时构建一次: H 18 *
    • 在每个小时的前半个小时内的每10分钟: H(0-29)/10
    • 每两小时一次,每个工作日上午9点到下午5点(也许是上午10:38,下午12:38,下午2:38,下午 4:38) :H
      H(9-16)/2 1-5

    轮询SCM(不建议)

    • 轮询SCM,是指定时扫描本地代码仓库的代码是否发生变更,如果代码有变更就触发项目构建:

    在这里插入图片描述

    注意:这种构建触发器,Jenkins会定时扫描本地整个项目的代码,增大系统的开销,不建议使用。


    Git Hook自动触发构建

    在Jenkins的内置触发构建器中,轮询SCM可以实现GitLab代码更新、项目自动构建,但是该方案的性能不佳,有没有更好的方案?有,就是利用Gitlab的webhook实现代码push到仓库的时候,立即触发项目自动构建。

    在这里插入图片描述

    安装Gitee Hook

    在这里插入图片描述

    Jenkins设置自动构建

    在这里插入图片描述


    在项目中添加webhook

    在这里插入图片描述


    Jenkins的参数化构建

    ● 有时在项目构建的过程中,我们需要根据用户的输入动态传入一些参数,从而影响整个构建结果,这时我们可以使用参数化构建。

    ● Jenkins支持非常丰富的参数类型。

    在这里插入图片描述


    使用Gitlab的分支名称来部署不同的分支项目
    • 修改Jenkinsfile文件:
    pipeline {
        agent any
    
        stages {
            stage('拉取代码') {
                steps {
                    checkout([$class: 'GitSCM', branches: [[name: '*/${branch}']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: '7d5c4945-2533-41e2-bd47-5dd97eb37f38', url: 'git@192.168.18.100:develop_group/springboot2.git']]])
                }
            }
    		stage('编译打包') {
                steps {
                    sh '''echo "开始构建"
                    mvn clean install -Dmaven.test.skip=true
                    echo "构建结束"'''
                }
            }
    		stage('远程部署') {
                steps {
                    sshPublisher(publishers: [sshPublisherDesc(configName: '192.168.18.102', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '''cd /usr/local
    chmod 777 *.sh
    ./stop.sh
    ./start.sh''', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: 'target', sourceFiles: 'target/*.jar')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
                }
            }
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    “${branch}”是重点。

    • 创建master和v1分支:略。

    在这里插入图片描述

    • 点击Build with Parameters:

    在这里插入图片描述


    配置邮箱服务器发送构建结果

    需要安装Email Extension Template插件
    Jenkins设置邮箱参数
    • Manage Jenkins–>Configure System。

    在这里插入图片描述

    • 设置邮箱参数:

    在这里插入图片描述

    在这里插入图片描述


    准备邮箱内容

    在项目的根目录编写email.html,并把文件推送到Gitlab中,内容如下:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次构建日志</title>
    </head>
    
    <body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4"
          offset="0">
    <table width="95%" cellpadding="0" cellspacing="0"
           style="font-size: 11pt; font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif">
        <tr>
            <td>(本邮件是程序自动下发的,请勿回复!)</td>
        </tr>
        <tr>
            <td><h2>
                <font color="#0000FF">构建结果 - ${BUILD_STATUS}</font>
            </h2></td>
        </tr>
        <tr>
            <td><br />
                <b><font color="#0B610B">构建信息</font></b>
                <hr size="2" width="100%" align="center" /></td>
        </tr>
        <tr>
            <td>
                <ul>
                    <li>项目名称&nbsp;&nbsp;${PROJECT_NAME}</li>
                    <li>构建编号&nbsp;&nbsp;第${BUILD_NUMBER}次构建</li>
                    <li>触发原因:&nbsp;${CAUSE}</li>
                    <li>构建日志:&nbsp;<a href="${BUILD_URL}console">${BUILD_URL}console</a></li>
                    <li>构建&nbsp;&nbsp;Url&nbsp;&nbsp;<a href="${BUILD_URL}">${BUILD_URL}</a></li>
                    <li>工作目录&nbsp;&nbsp;<a href="${PROJECT_URL}ws">${PROJECT_URL}ws</a></li>
                    <li>项目&nbsp;&nbsp;Url&nbsp;&nbsp;<a href="${PROJECT_URL}">${PROJECT_URL}</a></li>
                </ul>
            </td>
        </tr>
        <tr>
            <td><b><font color="#0B610B">Changes Since Last
                Successful Build:</font></b>
                <hr size="2" width="100%" align="center" /></td>
        </tr>
        <tr>
            <td>
                <ul>
                    <li>历史变更记录 : <a href="${PROJECT_URL}changes">${PROJECT_URL}changes</a></li>
                </ul> ${CHANGES_SINCE_LAST_SUCCESS,reverse=true, format="Changes for Build #%n:
    %c
    "
    ,showPaths=true,changesFormat=" <pre>[%a]<br />%m</pre>",pathFormat="&nbsp;&nbsp;&nbsp;&nbsp;%p"} </td> </tr> <tr> <td><b>Failed Test Results</b> <hr size="2" width="100%" align="center" /></td> </tr> <tr> <td><pre style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">$FAILED_TESTS</pre> <br /></td> </tr> <tr> <td><b><font color="#0B610B">构建日志 (最后 100):</font></b> <hr size="2" width="100%" align="center" /></td> </tr> <tr> <td><textarea cols="80" rows="30" readonly="readonly" style="font-family: Courier New">${BUILD_LOG, maxLines=100}</textarea> </td> </tr> </table> </body> </html>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71

    编写Jenkinsfile添加构建后发送邮箱
    • Jenkinsfile:
    pipeline {
        agent any
    
        stages {
            stage('拉取代码') {
                steps {
                   checkout([$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'bacbbbb1-2df9-470d-adf8-5cb6dc496807', url: 'git@192.168.209.100:develop_group/springboot2.git']]])
                }
            }
    		stage('编译构建') {
                steps {
                    sh '''echo "开始构建"
                    mvn clean install -Dmaven.test.skip=true
                    echo "构建结束"'''
                }
            }
    		stage('项目部署') {
                steps {
                    sshPublisher(publishers: [sshPublisherDesc(configName: '192.168.209.102', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '''#!/bin/bash
                    echo "stop SpringBoot BAppApiServerApplication"
                    pid=`ps -ef | grep java | grep -v grep | awk \'{print $2}\'`
                    echo “旧应用进程id:$pid”
                    if [ -n "$pid" ]
                    then
                    kill -9 $pid
                    rm -rf springboot2-1.0.jar
                    fi
                    export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-11.0.9.11-2.el7_9.x86_64
                    echo ${JAVA_HOME}
                    echo "授权当前用户"
                    chmod 777 /usr/local/springboot2-1.0.jar
                    echo "执行...."
                    cd /usr/local/
                    nohup ${JAVA_HOME}/bin/java -jar springboot2-1.0.jar > /dev/null &
                    echo "启动成功"
    
                    ''', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: 'target', sourceFiles: 'target/*.jar')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
                }
            }
        }
        post {
          always {
             emailext (
                 subject: '构建通知:${PROJECT_NAME} - Build # ${BUILD_NUMBER} - ${BUILD_STATUS}!',
                 body: '${FILE,path="email.html"}',
                 to: 'xxx@qq.com'
             )
          }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

  • 相关阅读:
    嵌入式单片机智能药盒设计(含代码)
    18C++之引用
    Aws配置钉钉告警实现
    AI写作生成器-AI写作生成器下载和用途
    HAProxy 生产环境架构
    从业一年,我是如何涨薪13K+?
    Windows&Linux文件传输方式总结
    越来越流行的认证-FSC
    紫光集团、展讯通信、锐迪科(RDA)、紫光展锐以及翱捷科技(ASR)关系梳理
    Spring整合Mybatis
  • 原文地址:https://blog.csdn.net/m0_53157173/article/details/126578748