从零开始带你实现一套自己的CI/CD(四)Jenkins Pipeline流水线

一、简介

从零开始带你实现一套自己的CI/CD(一)Jenkins
从零开始带你实现一套自己的CI/CD(二)Jenkins+Sonar Qube
从零开始带你实现一套自己的CI/CD(三)Jenkins+Harbor

通过前面的文章,我们已经实现了Jenkins 自由风格部署项目,每个步骤流程都要通过不同的方式设置,并且构建过程中整体流程是不可见的,无法确认每个流程花费的时间,并且问题不方便定位问题。

Jenkins的Pipeline可以让项目的发布整体流程可视化,明确执行的阶段,可以快速的定位问题。并且整个项目的生命周期可以通过一个Jenkinsfile文件管理,而且Jenkinsfile文件是可以放在项目中维护。

所以Pipeline相对自由风格或者其他的项目风格更容易操作。
下面我们就来介绍一下使用Jenkins Pipeline构建项目。

二、Groovy

2.1 HelloWorld

使用Jenkins Pipeline部署项目,需要编写Jenkinsfile文件,Jenkinsfile文件使用groovy语言进行编写的。
下面是groovy编写的HelloWorld程序:

pipeline {
    
    
    agent any

    stages {
    
    
        stage('Hello') {
    
    
            steps {
    
    
                echo 'Hello World'
            }
        }
    }
}

在这里插入图片描述

点击应用 保存,返回项目点击立即构建

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

2.2 Pipeline script from SCM

但是我们并不在Jenkins这里编写脚本,而是把Jenkinsfile文件放在项目里,Jenkins从Git仓库拉去代码执行Jenkinsfile文件中的脚本。
需要将Jenkins流水线定义为Pipeline script from SCM,输入Git仓库的地址。

在这里插入图片描述

在项目中新建一个Jenkinsfile文件:

pipeline {
    
    
    agent any

    stages {
    
    
        stage('拉取Git代码') {
    
    
            steps {
    
    
                echo '拉取Git代码'
            }
        }

        stage('检测代码质量') {
    
    
            steps {
    
    
                echo '检测代码质量'
            }
        }

        stage('构建代码') {
    
    
            steps {
    
    
                echo '构建代码'
            }
        }

        stage('制作自定义镜像并发布Harbor') {
    
    
            steps {
    
    
                echo '制作自定义镜像并发布Harbor'
            }
        }

        stage('基于Harbor部署工程') {
    
    
            steps {
    
    
                echo '基于Harbor部署工程'
            }
        }
    }
}

然后通过Jenkins进行构建,可以看到每个步骤构建的过程。

三、Jenkinsfile

上面的脚本只是输出了日志,现在我们将一一实现上面的每个步骤。
在这里插入图片描述
Jenkins为我们提供了生成Groovy脚本的方法。

3.1 拉取代码

进入流水线语法,选择checkout,填入Git地址,点击生成流水线语法即可。
在这里插入图片描述
在这里插入图片描述

checkout([$class: 'GitSCM', branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[url: 'https://gitee.com/L1692312138/jenkins-demo.git']]])

我们将这个脚本直接粘贴到上面拉取Git代码的地方。

3.2 代码质量检测

执行脚本进行Sonar代码质量检测

/var/jenkins_home/sonar-scanner/bin/sonar-scanner -Dsonar.sources=./ -Dsonar.projectname=${JOB_NAME} - Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=target/ -Dsonar.login=31388be45653876c1f51ec02f0d478e2d9d0e1fa

Sonar可以在此处生成Token:
在这里插入图片描述
在这里插入图片描述

sh '/var/jenkins_home/sonar-scanner/bin/sonar-scanner -Dsonar.sources=./ -Dsonar.projectname=${JOB_NAME} -Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=target/ -Dsonar.login=7d66af4b39cfe4f52ac0a915d4c9d5c513207098'

3.3 构建代码

执行shell脚本进行Mavne打包(注意:Jenkins安装Mavne的位置)

/var/jenkins_home/apache-maven-3.8.6/bin/mvn clean package -DskipTests

在这里插入图片描述

sh '/var/jenkins_home/apache-maven-3.8.6/bin/mvn clean package -DskipTests'

3.4 制作镜像并发布镜像仓库

cp ./target/*.jar ./deploy/
cd ./deploy
docker build -t ${
    
    JOB_NAME}:${
    
    tag} .
docker login -u ${
    
    harborUser} -p ${
    
    harborPasswd} ${
    
    harborHost}
docker tag ${
    
    JOB_NAME}:${
    
    tag} ${
    
    harborHost}/${
      
      harborRepo}/${
    
    JOB_NAME}:${
    
    tag}
docker push ${
    
    harborHost}/${
      
      harborRepo}/${
    
    JOB_NAME}:${
    
    tag}

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

   sh '''cp ./target/*.jar ./deploy/
   cd ./deploy
   docker build -t ${JOB_NAME}:${tag} .'''

   sh '''docker login -u ${harborUser} -p ${harborPasswd} ${harborHost}
   docker tag ${JOB_NAME}:${tag} ${harborHost}/${harborRepo}/${JOB_NAME}:${tag}
   docker push ${harborHost}/${harborRepo}/${JOB_NAME}:${tag}'''

3.5 部署到目标服务器

连接到目标服务器,执行目标服务器准备好的deploy.sh脚本

deploy.sh $harbor_url $harbor_project_name $JOB_NAME $tag $container_port $host_port

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

sshPublisher(publishers: [sshPublisherDesc(configName: '131', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: 'deploy.sh $harbor_url $harbor_project_name $JOB_NAME $tag $container_port $host_port', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])

注意:在之前的文章中已经准备了deploy.sh脚本和配置了目标服务器

3.6 完整的Jenkinsfile

pipeline {
    
    
    agent any
    environment{
    
    
        harborHost = '192.168.153.131:80'
        harborRepo = 'helloworld'
        harborUser = 'admin'
        harborPasswd = 'Harbor12345'
    }

    // 存放所有任务的合集
    stages {
    
    

        stage('Pull Code') {
    
    
            steps {
    
    
                checkout([$class: 'GitSCM', branches: [[name: '${tag}']], extensions: [], userRemoteConfigs: [[url: 'https://gitee.com/L1692312138/jenkins-demo.git']]])
            }
        }

//         stage('Sonar Scan') {
    
    
//             steps {
    
    
//                 sh '/var/jenkins_home/sonar-scanner/bin/sonar-scanner -Dsonar.sources=./ -Dsonar.projectname=${JOB_NAME} -Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=target/ -Dsonar.login=7d66af4b39cfe4f52ac0a915d4c9d5c513207098'
//             }
//         }

        stage('Maven Build') {
    
    
            steps {
    
    
                sh '/var/jenkins_home/apache-maven-3.8.6/bin/mvn clean package -DskipTests'
            }
        }

        stage('Push Harbor') {
    
    
            steps {
    
    
                sh '''cp ./target/*.jar ./deploy/
                cd ./deploy
                docker build -t ${JOB_NAME}:${tag} .'''

                sh '''docker login -u ${harborUser} -p ${harborPasswd} ${harborHost}
                docker tag ${JOB_NAME}:${tag} ${harborHost}/${harborRepo}/${JOB_NAME}:${tag}
                docker push ${harborHost}/${harborRepo}/${JOB_NAME}:${tag}'''
            }
        }

        stage('Publish Over SSH') {
    
    
            steps {
    
    
                sshPublisher(publishers: [sshPublisherDesc(configName: '131', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "deploy.sh $harborHost $harborRepo $JOB_NAME $tag $container_port $host_port", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
            }
        }
    }
}

因为博主的机器是arm64架构,sonar-scanner不支持这个架构,所以注释了。
在这里插入图片描述

3.7 参数配置

在Jenkinsfile中使用了$符号取值,我们需要配置这些变量。

  1. Git 参数 tag
  2. 字符参数 container_port
  3. 字符参数 host_port

在这里插入图片描述

在这里插入图片描述

3.8 通过参数构建

在这里插入图片描述

在这里插入图片描述

可以看到构建成功了
去Harbor也可以看到镜像已经上传

在这里插入图片描述

目标服务器Docker容器也已经运行了

在这里插入图片描述

Jenkins Pipeline构建成功!

四、添加邮件通知

在项目构建成功后,发送邮件通知构建结果

4.1 配置Jenkins邮件配置

下载Jenkins插件 Email Extension Plugin
在这里插入图片描述

进入QQ邮箱设置:
开启POP3/SMTP服务
在这里插入图片描述
在这里插入图片描述

邮箱 POP3服务器(端口995) SMTP服务器(端口465或587)
qq.com pop.qq.com smtp.qq.com

生成授权码

在这里插入图片描述
在Jenkins设置中配置 系统管理员邮件地址
在这里插入图片描述

在Jenkins设置中配置邮件通知

在这里插入图片描述

点击 Test Configuration 测试配置是否成功

在这里插入图片描述

4.2 生成Pipeline语法

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

 post {
    
    
      always {
    
    
        emailext body: '${FILE,path="email.html"}', subject: '【构建通知】:$PROJECT_NAME - Build # $BUILD_NUMBER - $BUILD_STATUS!', to: '[email protected]'
      }
    }

4.3 邮件发送内容

在项目中新建email.html文件:

<!DOCTYPE html>
<html>
<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: Tahoma, Arial, Helvetica, sans-serif">
    <tr>
        本邮件由系统自动发出,无需回复!<br/>
        各位同事,大家好,以下为${PROJECT_NAME }项目构建信息</br>
        <td><font color="#CC0000">构建结果 - ${BUILD_STATUS}</font></td>
    </tr>
    <tr>
        <td><br />
            <b><font color="#0B610B">构建信息</font></b>
            <hr size="2" width="100%" align="center" /></td>
    </tr>
    <tr>
        <td>
            <ul>
                <li>项目名称 : ${PROJECT_NAME}</li>
                <li>构建编号 : 第${BUILD_NUMBER}次构建</li>
                <li>触发原因: ${CAUSE}</li>
                <li>构建状态: ${BUILD_STATUS}</li>
                <li>构建日志: <a href="${BUILD_URL}console">${BUILD_URL}console</a></li>
                <li>构建  Url : <a href="${BUILD_URL}">${BUILD_URL}</a></li>
                <li>工作目录 : <a href="${PROJECT_URL}ws">${PROJECT_URL}ws</a></li>
                <li>项目  Url : <a href="${PROJECT_URL}">${PROJECT_URL}</a></li>
            </ul>

            <h4><font color="#0B610B">失败用例</font></h4>
            <hr size="2" width="100%" />
            $FAILED_TESTS<br/>

            <h4><font color="#0B610B">最近提交</font></h4>
            <hr size="2" width="100%" />
            <ul>
                ${CHANGES_SINCE_LAST_SUCCESS, reverse=true, format="%c", changesFormat="<li>%d [%a] %m</li>"}
            </ul>
            详细提交: <a href="${PROJECT_URL}changes">${PROJECT_URL}changes</a><br/>

        </td>
    </tr>
</table>
</body>
</html>

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

完整Jenkinsfile文件

pipeline {
    
    
    agent any
    environment{
    
    
        harborHost = '192.168.153.131:80'
        harborRepo = 'helloworld'
        harborUser = 'admin'
        harborPasswd = 'Harbor12345'
    }

    // 存放所有任务的合集
    stages {
    
    

        stage('Pull Code') {
    
    
            steps {
    
    
                checkout([$class: 'GitSCM', branches: [[name: '${tag}']], extensions: [], userRemoteConfigs: [[url: 'https://gitee.com/L1692312138/jenkins-demo.git']]])
            }
        }

//         stage('Sonar Scan') {
    
    
//             steps {
    
    
//                 sh '/var/jenkins_home/sonar-scanner/bin/sonar-scanner -Dsonar.sources=./ -Dsonar.projectname=${JOB_NAME} -Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=target/ -Dsonar.login=7d66af4b39cfe4f52ac0a915d4c9d5c513207098'
//             }
//         }

        stage('Maven Build') {
    
    
            steps {
    
    
                sh '/var/jenkins_home/apache-maven-3.8.6/bin/mvn clean package -DskipTests'
            }
        }

        stage('Push Harbor') {
    
    
            steps {
    
    
                sh '''cp ./target/*.jar ./deploy/
                cd ./deploy
                docker build -t ${JOB_NAME}:${tag} .'''

                sh '''docker login -u ${harborUser} -p ${harborPasswd} ${harborHost}
                docker tag ${JOB_NAME}:${tag} ${harborHost}/${harborRepo}/${JOB_NAME}:${tag}
                docker push ${harborHost}/${harborRepo}/${JOB_NAME}:${tag}'''
            }
        }

        stage('Publish Over SSH') {
    
    
            steps {
    
    
                sshPublisher(publishers: [sshPublisherDesc(configName: '131', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "deploy.sh $harborHost $harborRepo $JOB_NAME $tag $container_port $host_port", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
            }
        }
    }
    post {
    
    
      always {
    
    
        emailext body: '${FILE,path="email.html"}', subject: '【构建通知】:$PROJECT_NAME - Build # $BUILD_NUMBER - $BUILD_STATUS!', to: '[email protected]'
      }
    }
}

猜你喜欢

转载自blog.csdn.net/DreamsArchitects/article/details/128191172