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

news2024/11/24 17:50:33

目录

  • 一、简介
  • 二、Groovy
    • 2.1 HelloWorld
    • 2.2 Pipeline script from SCM
  • 三、Jenkinsfile
    • 3.1 拉取代码
    • 3.2 代码质量检测
    • 3.3 构建代码
    • 3.4 制作镜像并发布镜像仓库
    • 3.5 部署到目标服务器
    • 3.6 完整的Jenkinsfile
    • 3.7 参数配置
    • 3.8 通过参数构建
    • 四、添加邮件通知
    • 4.1 配置Jenkins邮件配置
    • 4.2 生成Pipeline语法
    • 4.3 邮件发送内容
  • 完整Jenkinsfile文件

一、简介

从零开始带你实现一套自己的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也可以看到镜像已经上传
目标服务器容器也已经运行了
在这里插入图片描述

Jenkins Pipeline构建成功!

四、添加邮件通知

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

4.1 配置Jenkins邮件配置

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

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

邮箱POP3服务器(端口995)SMTP服务器(端口465或587)
qq.compop.qq.comsmtp.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: 'xxxx@qq.com'
      }
    }

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: 'liush99@foxmail.com'
      }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/158031.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

开源飞控初探(一):无人机的历史

这章先纠正大疆带给无人机外行小白的认知。定义无人机无人机的正式英文名字是Unmanned Aerial Vehicle&#xff0c;缩写为UAV。有人无人的区分&#xff0c;是看飞机能否一直需要人为操控。最简单的场景是&#xff0c;当飞机飞出视线之外时&#xff0c;人已经很难实时根据环境来…

微服务自动化管理【docker compose】

1.什么是docker-compose Docker-Compose项目是Docker官方的开源项目&#xff0c;负责实现对Docker容器集群的快速编排 通过编写docker-compose文件可对多个服务同时进行启动/停止/更新(可定义依赖&#xff0c;按顺序启动服务) docker-compose将所管理的容器分为3层结构&#…

Yii2下PHP远程调试PHP5.6/7.2与Xdebug2.5/2.7/3.0 在PHPSTORM下的差异化表现

学习起因&#xff1a;新人学YII2不知道远程调试(远程调试和控制台调试是两件事&#xff0c;同一个原理) 因为yii2框架&#xff0c;设计复杂度非常高&#xff0c;加上php代码的弱类型语言结构&#xff0c;在代码非常复杂的情况下&#xff0c;不采用调试的方式来看源码调用栈&am…

MPLS 虚拟专线 实验

目录 1.拓扑图 2.实验思路 3.主要配置 4.测试 5.实验总结 1.拓扑图 2.实验思路 IGP路由 MPLS Domain 配置MPLS VPN PE之间的MP-BGP邻居关系 CE端与PE端的路由交换 双向重发布&#xff0c;实现路由共享 3.主要配置 R6&#xff1a; *公网环境&#xff1a; [r6]ospf 1 r…

记录robosense RS-LIDAR-16使用过程2

一、安装并使用可视化工具RSView&#xff0c;官网提供了不同版本的安装包&#xff0c;根据个人环境下载解压。本人ubuntu18系统&#xff0c;修改权限&#xff1a;chmod ax run_rsview.sh;然后运行&#xff1a;./run_rsview.sh。该软件每次启动时都要运行./run_rsviewer.sh该软件…

Acwing 1214. 波动数列

题目链接&#xff1a;1214. 波动数列 - AcWing题库 标签&#xff1a;动态规划 &#xff08;字好丑...&#xff09; AC代码&#xff1a; #include<iostream> using namespace std;int f[1005][1005];const int MOD 100000007;//返回正余数 int get_mod(int a,int b) {…

不重复的随机数问题

前言 对于随机数的运用&#xff0c;在开发中经常会用到。有时需要生成不重复的定范围定总量的随机数&#xff0c;比如1~20&#xff0c;需要打乱的1~20中的10个数&#xff0c;那到底怎么做呢? 一、不重复的随机数 我们知道&#xff0c;直接用random会有重复的数字&#xff0…

电商物流云仓的原理是什么?

以云的速度和范围获得胜利  这是一个快速转型时期&#xff0c;封锁、就地避难订单和游览限制扰乱了美国经济的各个范畴&#xff0c;对供给链运营产生了严重影响。在如此动乱的时期&#xff0c;企业正越来越多地转向云优先战略&#xff0c;以使其供给链愈加矫捷和灵敏。  战…

【NI Multisim 14.0原理图文件管理——保存/备份文件及新建电路图页文件】

目录 序言 ⛄1.保存文件 ⛄2.备份文件 ⛄3.新建电路图页文件 序言 NI Multisim最突出的特点之一就是用户界面友好。它可以使电路设计者方便、快捷地使用虚拟元器件和仪器、仪表进行电路设计和仿真。 首先启动NI Multisim 14.0&#xff0c;打开如图所示的启动界面&#xff…

CTK Plugin Framework插件框架学习--事件监听

文章目录一、前言二、框架事件三、插件事件四、服务事件五、添加事件监听一、前言 CTK一共有三种事件可以监听&#xff1a; 框架事件插件事件服务事件 但是这些事件只有在变化时才能监听到&#xff0c;如果已经变化过后&#xff0c;进入一个稳定的状态&#xff0c;这时才去监…

归并排序详细说明及实现-python

算法思想&#xff1a; 设初始序列含有n个记录&#xff0c;则可看成n个有序的子序列&#xff0c;每个子序列长度为1 两两合并&#xff0c;得到&#xff08;n//2) 个长度为2&#xff08;n为奇数时&#xff0c;最后一个序列的长度为1&#xff09;的有序子序列 再两两合并&#xff…

【Flink系列】开发篇:1. Flink维表关联方案

数据流往往需要访问外部的数据源来丰富自己的信息&#xff0c;比如通过record中的ip地址查询ip数据库maxmind的GeoIP2 Databases得到ip对应的城市名称&#xff0c;城市经纬度&#xff0c;将这些作为新的字段添加到原来的record中。这就涉及到本篇的主题&#xff1a;维表关联。 …

分布式锁方案分析:看图说话(图+文)

1 缘起 曾经在看分布式锁的时候&#xff0c;还是处于了解阶段&#xff0c; 回头总结时&#xff0c;发现有很多细节没有探究到&#xff0c; 本文以-看图说话的方式分析不同的分布式锁方案&#xff0c; 分布式锁需要保证&#xff1a; &#xff08;1&#xff09;互斥性&#xff1…

【从零开始学习深度学习】46. 目标检测中锚框的概念、计算方法、样本锚框标注方式及如何选取预测边界框

本文主要介绍目标检测中常用到的锚框相关概念、计算方式、样本标注及如何选取预测边界框并输出的相关内容。 目录1. 锚框介绍1.1 生成多个锚框2. 交并比--Jaccard系数3. 标注训练集的锚框4. 输出预测边界框---非极大值抑制方法总结1. 锚框介绍 在目标检测算法中通常会在输入图…

Linux常用命令——xhost命令

在线Linux命令查询工具(http://www.lzltool.com/LinuxCommand) xhost 制哪些X客户端能够在X服务器上显示 补充说明 xhost命令是X服务器的访问控制工具&#xff0c;用来控制哪些X客户端能够在X服务器上显示。该命令必须从有显示连接的机器上运行。可以通过使用-host参数&…

​Topaz Photo AI 人工智能图像降噪锐化放大

Topaz Photo AI 是一款强大的基于人工智能技术的降噪、锐化及放大的工具。它不仅可以作为独立的软件使用&#xff0c;也可作为 Photoshop 的插件&#xff0c;以及能在 Lightroom Classic、Capture One 中调用。在 Lightroom Classic 中提供了两种工作流程&#xff0c;一种是直接…

while和do while的用法区别

前言在上一篇文章中&#xff0c;壹哥给大家讲解了循环的概念&#xff0c;并重点给大家讲解了for循环的使用。但在Java中&#xff0c;除了for循环之外&#xff0c;还有while、do-while、foreach等循环形式。今天小千就再用一篇文章&#xff0c;给大家讲解while循环的使用。本文带…

webshell 一句话木马

Webshell&#xff08;大马&#xff09;&#xff1a;webshell就是以asp、aspx、php、jsp或者cgi等网页形式存在的一种命令执行环境&#xff0c;也将其称为一种网页后门。黑客入侵一个网站后&#xff0c;通常会将 asp、aspx、php 或 jsp 后门文件与网站 web 服务器目录下正常的网…

基础算法(三)——二分查找

二分查找 介绍 一种复杂度为O(logn)O(logn)O(logn)级别的查找算法&#xff0c;需要被查找的数列具有某种单调性质&#xff0c;其本质其实是搜索一个符合check条件的区间。 二分分为两种&#xff1a; 整数二分浮点数二分 核心思想&#xff1a; 首先讨论整数二分&#xff1…

Django搭建个人博客Blog-Day02

配置文件的介绍&#xff1a;dev.py&#xff08;原来的setting.py文件&#xff09;# django的配置文件中的配置项是什么意思&#xff1f; import os # 导入模块# Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR os.path.dirname(os.path.d…