0


CI/CD详解 & Jenkins 介绍与实战

本文大纲概览:

  • CI/CD 概念与工作流程 详解
  • Jenkins安装、启动、初始化配置
  • 使用Jenkins部署github上的 xzll-im 微服务项目 - freestyle方式- push代码后自动部署- pipeline方式部署- pipeline + push 方式

本文实操过程中,相关工具版本信息如下:

  • centos版本: CentOS Linux release 7.9.2009 (Core)
  • jdk: jdk-11.0.22
  • maven: 3.8.8
  • git: 1.8.3.1
  • jenkins 2.252
  • docker: 26.1.4
  • docker-compose: v2.27.2
  • 其它项目中使用到的中间件版本请见docekr-compose.yml 中的镜像版本,戳这里

什么是 持续集成(CI)& 持续交付(CD)?

大白话: 对于CI/CD的理解,可能每个人都不一样(一千个人有一千个哈姆雷特!😂),我理解他其实就是一种更加自动化的工作模式,使得开发、测试、运维之间的沟通成本降低,从之前的手动编译、打包、构建、测试到现在的自动化、流程化去执行这些步骤,从而更加快速,及时发现问题,最终实现:加快软件迭代周期,提高交付速度与质量 的目的!

CI(持续集成) 介绍

CI全称: (Continuous Intergration)

持续集成的重点在于 ***

构建编译

*** 及 ***

测试

***(这里

更多的

指通过脚本和自动化项目来进行的

自动化测试

),开发人员每天要提交很多次代码到分支,在分支合并到主干前,需要通过编译和测试识别出问题。持续集成的流程就是通过自动化的构建(主要是构建编译、自动化测试)来验证,从而尽早地发现集成错误。

CI(持续集成)的工作流程

  1. CI初始化:包括但不限于(CI服务的安装&启动,脚本、任务定义与配置,webhook设置,凭证设置,系统配置,插件等等)
  2. 开发人员从代码库中获取最新代码(pull)。
  3. 开发人员在本地进行开发和测试。
  4. 开发人员将代码提交(commit & push)到代码仓库(github、 gitlib)
  5. 通过回调方式通知CI服务器,ci服务器自动拉取最新代码并触发构建任务。
  6. 构建(build)-> 自动化测试(test)-> 反馈结果(result)
  7. 将自动化测试的结果反馈给开发人员(钉钉邮件短信等方式),如果测试失败,开发人员会及时修复代码并重新提交
  8. 构建和测试成功后,代码可以部署到进一步的测试环境或生产环境中

集成工具

集成工具有很多种(我所接触的主要还是

jenkins

gitlib

),包括但不限于以下: * Jenkins **(常见)**:一个开源的自动化服务器,支持复杂的构建、测试和部署流水线。 * GitLab CI/CD **(常见)**:GitLab 内置的 CI/CD 工具,支持从代码提交到生产部署的全流程自动化。 * CircleCI:一个基于云的持续集成和持续交付平台,支持多种编程语言和构建环境。 * Travis CI:一个基于云的持续集成服务,特别适用于 GitHub 项目。 * Spinnaker:一个开源的持续交付平台,支持多云环境的自动化部署

持续集成的好处

  • 提高代码质量:通过频繁的自动化测试和代码质量检查,可以早期发现并修复错误。
  • 加快交付速度:自动化构建和测试减少了手动操作的时间,可以提高开发速度从而加快交付。
  • 提高团队协作效率:开发人员可以更快地得到反馈,后期与测试人员协作更加顺畅。
  • 总之概括起来就是一句话:省去人工操作,push后自动构建、测试(这里指自动化测试)、反馈,从而尽早的在开发环境发现代码问题并修复#### CI 流程图

下边是持续集成(CI) 的流程图: image.png

知道了CI , 那么CD又是指啥呢?接着看

CD(持续交付&持续部署) 介绍

CD 有两个意思 1. 一是 持续交付(Continuous Delivery) 2. 另一个是持续部署(Continuous Deployment)

说一句:其实做到持续交付就已经很不错了,持续部署听听就行了,别当真!为什么这么说? 往下看。

何为持续交付?

持续交付指的是将产品尽可能快的发布上线的过程。持续交付是在持续集成基础上的扩展,也就是说在成功通过dev环境的自动化部署与测试之后,为了尽快上线我们还需要

自动化发布

fat或者uat环境(如果需要的话),整个流程实现后,根据实际需要,可以人工控制是否发布

prod

环境。一般在公司都是开发环境(dev)、测试环境(fat)、预发布环境(uat)和正式生产环境(prod),如果代码在预发布环境测试通过,那么就可通过 手动方式 部署生产环境,从而尽可能的实现产品快速迭代上线。

持续交付的几个关键因素: - 自动化构建和测试: 与持续集成(CI)类似,持续交付(CD)依赖于自动化的构建和测试,以确保每次代码更改都能被快速验证。 - 自动化部署: 持续交付要求自动化部署流程,这意味着每次代码更改都可以自动部署到不同的环境中(如开发、测试、预生产)。 - 环境一致性: 确保所有环境(从开发到生产)的一致性,以减少部署问题。 - 持续反馈: 提供持续反馈,确保开发团队及时了解相应服务在不同环境中的状态和问题。 - 手动发布控制: 尽管大部分部署过程都是自动化的,但 持续交付 通常 保留手动发布的控制权。发布到生产环境的最终决定由相关人员评估,可以的话再通过手动的方式来发布生产环境

持续交付流程图

image.png

何为持续部署?

持续部署是持续交付的进一步扩展。在持续部署中,所有的代码更改在通过自动化测试和验证后,都会自动部署到生产环境中。与持续交付不同,持续部署不通过

手动发布

来发布生产环境,而是自动发布生产环境。一般来说,非生产环境的持续部署基本都能实现。但生产环境的持续部署并不是每个企业都能做到,主要原因是受限于各种系统功能依赖、自动化测试不完善等因素,自动化方式部署到生产,将可能造成严重生产事故。 所以实际我觉得没几个企业这样做。能做到持续交付就已经很不错了。生产环境的部署 一定要认为控制。持续部署 听听就行了,不要玩火呀! 哈哈!😂😂😂😂😂😂😂😂😂😂😂😂

持续部署的关键要素: - 自动化构建、测试和部署: 持续部署依赖于完全自动化的构建、测试和部署流程,以确保每次代码更改都能被快速、可靠地部署到生产环境中。 - 强大的精准的测试覆盖: 持续部署需要非常高的测试覆盖率,包括单元测试、集成测试、端到端测试等,以确保所有代码更改都能被全面验证。 - 快速回滚机制: 当新代码引入问题时,必须有快速回滚的机制,以确保生产环境的稳定性。 - 持续监控: 持续监控生产环境中的应用性能和健康状态,确保及时发现和解决问题

注意:

无论是持续集成、持续交付还是持续部署,如果要想实现,都离不开CI服务器!

ok到这里你对CI/CD有自己的理解了吗?下边我们来学习一个非常重要且常见功能丰富的CI/CD 工具 : Jenkins ! 想玩CI/CD以及再往大一点的DevOps? 那么首先玩转Jnekins是必不可少的。换句话说,其实Jenkins是CI/CD、DevOps 这些概念的 其中一个重要

“实现”


介绍完CI/CD 下边我们开始学习Jenkins

Jenkins 安装、启动、初始化

以下说明是我选择哪种方式安装jenkins的过程记录,这里也记录下来,做个备忘。

  • 说明1:为什么不使用docker安装jenkins? 其实我也想使用docker安装,但是当我从docker hub中找到对应的镜像进行下载时,发现要么是下载不下来镜像,要么是下载下来的镜像 运行时的jenkins版本过低,导致一些插件安装报错,使得我很恼火。- 下载不下来镜像: 到docker hub 去找到对应镜像 ,戳此进: jenkins 的 docker hubimage.pngimage.png执行docker pull 镜像 发现下载失败,都是超时。。。。- 版本过低插件安装不了: ,后来终于有两个镜像可以下载了 就是这个镜像:jenkins/jenkins:lts-jdk11jenkins/jenkins:latest镜像,但是却提示jenkins版本过低导致一些插件安装不了,报错如下:image.png因为这个搞了半天,其实最主要原因可能就是欺负我的虚拟机没开vpn,哎 手头紧,暂时先不开了毕竟有点小贵,所以就决定弃启用docker安装jenkins, 我用war或RPM也行呀,真是的,😄
  • 说明2:为什么安装jenkins 2.252版本?- 由于在使用jenkins过程中我需要一些最新插件,而 LTS(官方长期支持版本)版本缺少对最新插件的支持,所以这里弃用LTS版本而使用较新的版本来安装部署学习,我使用的是: 2.452 (生产环境还是建议使用LTS版本来安装启动jenkins)
  • 说明3:为什么选择war包安装jenkins?- 首先第一原因是因为上边的说明1才迫使我使用war安装jenkins,另外因为我是centos7,所以其实我本应该使用RPM软件包方式安装jenkins,对应的版本是redhat的 LTS Release 的 redhat-stable(已发布的LTS版本)来安装jenkins 下边的引导页面戳这里,image.png,但是因为遇到了一些问题主要还是网络问题(还是欺负我虚拟机没vpn 😂😂 再欺负我真要买Strong vpn了啊 哈哈),所以我不用此方式,如果网络好(能fq)可以使用,(安装指南戳这里)- 最终:我选择使用war包安装jenkins ,因为经过实践我发现此方式比较好用不用担心被q的问题,选择war安装的话点击下边这个LTS Release:war-stableimage.png然后找到我要安装的版本(注意在安装此版本之前,我安装过较低版本 (LTS版本的2.361)但是我发现有些插件不能用,必须高版本才行所以这里选择较高的一个版本 2.452,ok接下来开干

ps: 其实某些场合下,docker部署不一定是最优方案。不一定要执着于所有东西都往docker堆,当然如果是开发测试环境,当我没说。

下载war、启动并初始化 jenkins

有了上边的铺垫,接下来我们首先找到

2.452版本

的war包:

下载war包

image.png 之后使用命令下载war包:

bash wget https://mirrors.jenkins-ci.org/war/2.452/jenkins.war --no-check-certificate 

image.png

编写启动脚本 来启动jenkins

ok从上边截图可知下载成功,接下来编写jenkins启动脚本: image.png 完整jenkins启动脚本在这: ```bash

!/bin/bash

args=$1

注意修改jenkinswar包的目录

jenkinswarpath="/usr/local/soft_hzz/jenkins"

jenkins开放端口

jenkinshttpport="8079"

java安装路径

javahome="/usr/lib/jvm/java-11-openjdk-11.0.22.0.7-1.el79.x86_64"

日志文件路径

jenkinslogpath="/tmp/data/logs/jenkins.log"

function isRunning(){ local jenkinsPID=$(ps -ef | grep jenkins.war | grep -v grep | awk '{print $2}') if [ -z ${jenkinsPID} ]; then echo "0" else echo ${jenkinsPID} fi }

停止jenkins

function stop(){ local runFlag=$(isRunning) if [ ${runFlag} -eq "0" ]; then echo "Jenkins is already stopped." else kill -9 ${runFlag} echo "Stop Jenkins success." fi }

启动jenkins

function start(){ local runFlag=$(isRunning) echo "${runFlag}" if [ ${runFlag} -eq "0" ]; then # nohup ${javahome}/bin/java -jar ${jenkinswarpath}/jenkins.war --httpPort=${jenkinshttpport} > ${jenkinslog_path} 2>&1 &

# 对jenkins内存大小进行限制 否则总是超内存 被系统kill
    nohup ${java_home}/bin/java -Xms512m -Xmx2g -jar ${jenkins_war_path}/jenkins.war --httpPort=${jenkins_http_port} > ${jenkins_log_path} 2>&1 &
    if [ $? -eq 0 ]; then
        echo "Start Jenkins success."
        exit
    else
        echo "Start Jenkins fail."
    fi
else
    echo "Jenkins is running now."
fi

}

重启jenkins

function restart(){ local runFlag=$(isRunning) if [ ${runFlag} -eq "0" ]; then echo "Jenkins is already stopped." exit else stop start echo "Restart Jenkins success." fi }

根据输入的参数执行不同的动作

参数不能为空

if [ -z ${args} ]; then echo "Arg can not be null." exit

参数个数必须为1个

elif [ $# -ne 1 ]; then echo "Only one arg is required: start|stop|restart"

参数为start时启动jenkins

elif [ ${args} = "start" ]; then start

参数为stop时停止jenkins

elif [ ${args} = "stop" ]; then stop

参数为restart时重启jenkins

elif [ ${args} = "restart" ]; then restart else echo "One of following args is required: start|stop|restart" exit 0 fi ``` 接下来启动: image.png

初始化jenkins

好,现在我们通过 172.30.128.65:8079访问jenkins,首次访问会出现下边这个解锁jenkins的页面,按提示找到密码并填进去点击继续就行了:

设置初始密码

将启动日志中的密码复制: image.png 填入下边的管理员密码中: image.png

安装jenkins推荐的插件

点击继续,之后,jenkins会推荐你安装一些插件,这里建议都安装上以免后续还得再手动安装,如下: image.png 插件有点多需要等待一会: image.png

在这里替换插件源(注意 : 替换后一定要重启jenkins) image.png

创建管理账号

之后提示你创建个管理员账号: image.png 然后填写上你的jenkins地址: image.png

完成后查看安装的插件

看到下边这个,代表 初始化工作就完成了: image.png 在这里你可以看到你初始化时候安装的那些插件: image.png

一些插件介绍:

| 插件名 | 作用 | | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Pipeline | 流水线部署项目 | | Role-based Authorization Strategy | 提供了一种基于角色(Role)的用户权限管理策略,支持创建global角色、Project角色、Slave角色,以及给用户分配这些角色。这款插件是最常用的Jenkins权限策略和管理插件 | | Git | 支持使用Github、GitLab、Gerrit等系统管理代码仓库,创建普通job时会用到 | | Gitee | Gitee Jenkins Plugin 是Gitee基于 GitLab Plugin 开发的 Jenkins 插件。用于配置 Jenkins 触发器,接受Gitee平台发送的 WebHook 触发 Jenkins 进行自动化持续集成或持续部署,并可将构建状态反馈回Gitee平台。 | | Git Parameter | 可用于把git的tag branch当作构建参数传进来,方便使用branch构建 | | Extended Choice Parameter | 参数化构建 | | Maven Integration | 这个插件为Maven 2 / 3项目提供了高级集成功能 | | SonarQube Scanner | 代码扫描 | | Email Extension | 扩展了发送告警邮件的控制力度。可以定义邮件触发器、邮件内容、收件人 | | Workspace Cleanup | 每次build之前删除workspace目录下指定的文件 | | Monitoring | 监控Jenkins节点的CPU、系统负载、平均响应时间和内存使用 | | Build Monitor View | 将Jenkins项目以一块看板的形式呈现 | | ThinBackup | 备份与恢复 | | jacoco | 单元测试覆盖率 | | Generic Webhook Trigger | webohook |

使用Jenkins部署项目

这里声明个前提:我使用的代码仓库是github,gitlib、gitee的操作略有不同。

全局工具配置

非pipeline的Java项目如果要构建成功,全局工具的环境需要配置好

  • 配置入口:Manage Jenkins->Global Tool Configuration
  • 配置方式:指定服务器上已经安装好的服务位置(不需要勾选自动安装)
  • 配置前提:服务器已经安装好jdk、maven、git

首先找到我的git、maven、jdk的安装路径,如下:

bash mvn -version which git echo $JAVA_HOME 

image.png 然后点击这个进行工具添加: image.png

添加git、maven、jdk

image.pngimage.png 添加后点击应用并保存。

方式一、 使用freestyle方式部署项目

新建freestyle类型的任务

首先我们需要建一个任务,点击新建item:

image.png

然后定义任务: image.png 简单描述一下此任务干的事情,以及勾选上github项目并填入url,如下: image.png

配置源码管理(这里使用ssh方式与github认证)

之后往下拉来到源码管理 填入仓库地址(ssh的话是git协议),之后点击添加,点击jenkins弹出认证设置 image.png 我这里选择ssh方式认证: image.png

之后可以填写你想要的认证方式(我这里使用ssh认证,也就是说把你github上公钥对应的私钥(私钥一般在你本地使用

cat ~/.ssh/id_rsa

命令查看),粘到下边的private key中) image.png 当然如果没有生成过或者删除了,那么使用下边方式重新生成,并将公钥粘到github,步骤如下:


## 注意在生成前最好是先删除一下旧的

## 删除公钥和私钥

rm -f ~/.ssh/id*rsa ~/.ssh/id*rsa.pub

## 清除之前的主机秘钥

rm -f ~/.ssh/known_hosts

## 重新生成

ssh-keygen -t rsa -b 4096 -C "[email protected]"

## 查看私钥

cat ~/.ssh/id_rsa

## 查看公钥

cat ~/.ssh/id_rsa.pub


## 测试与github的连接是否正常(在github配完公钥之后操作)

ssh -T git@github.com


image.png 将公钥粘到github: image.png

在将公钥配到github后可以使用命令

ssh -T [email protected]

来测试是否连接成功,如果输出: Hi xxx! You've successfully authenticated, but GitHub does not provide shell access. 则说明ssh配置没问题了。

选择

SSH Username with private key

认证方式(有好几种认证方式比如 用户名密码,access token, ssh等 我们这里使用ssh方式),并使用

cat ~/.ssh/id_rsa

找到私钥并粘到下图的private key中去: image.png

之后我们填入仓库地址,以及刚刚新加的认证方式,以及要部署的分支: image.png 然后在构建环境这里,选择jdk版本: image.png

编写你的shell脚本(用来定义你如何构建&启动等动作)

编写shell脚本,定义启动的一些动作: image.png shell脚本内容:


## !/bin/bash

## 使用freestyle方式启动xzll-im项目时的shell脚本,此脚本在 jenkins的 build steps处填写。

log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" }

exit*on*error() { if [ $? -ne 0 ]; then log "$1" exit 1 fi }

log ">>>>>>>>>>>> 开始部署 >>>>>>>>>>>>>"

## 确保 docker-compose 目录存在 不存在则创建

COMPOSE*DIR="/usr/local/soft*hzz/xzll-im/jar-file/jenkins*way*build*docker*compose/" if [ ! -d "$COMPOSE*DIR" ]; then log ">>>>>>>>>>>> 目录不存在,创建目录 $COMPOSE*DIR >>>>>>>>>>>>>" mkdir -p "$COMPOSE*DIR" || { log "Failed to create directory $COMPOSE*DIR"; exit 1; } fi

## 进入 docker-compose 目录

log ">>>>>>>>>>>> 进入到 docker-compose 目录中 >>>>>>>>>>>>>" cd "$COMPOSE*DIR" || { log "Failed to enter directory $COMPOSE*DIR"; exit 1; }

## 如果项目目录不存在,则执行 clone,否则执行 pull

if [ ! -d "xzll-im" ]; then log ">>>>>>>>>>>> 项目目录不存在,执行 git clone >>>>>>>>>>>>>" git clone [email protected]:598572/xzll-im.git || { log "Git clone failed"; exit 1; } else log ">>>>>>>>>>>> 项目目录已存在,进入目录并执行 git pull >>>>>>>>>>>>>" cd xzll-im/ || { log "Failed to enter directory"; exit 1; } git pull || { log "Git pull failed"; exit 1; } cd .. fi

## 进入项目根目录

log ">>>>>>>>>>>> 进入项目根目录 >>>>>>>>>>>>>" cd xzll-im/ || { log "Failed to enter project directory"; exit 1; }

git fetch

git checkout jenkins*build*20240709

## 开始打包

log ">>>>>>>>>>>> 开始打包 >>>>>>>>>>>>>"

mvn clean package -P prod || { log "Maven build failed"; exit 1; }

log ">>>>>>>>>>>> 打包完成 >>>>>>>>>>>>>"

## 确保 Docker 构建上下文包含所有 JAR 文件

declare -A JAR_FILES=( ["im-gateway/target/im-gateway.jar"]="im-gateway/src/main/resources" ["im-connect/im-connect-service/target/im-connect-service.jar"]="im-connect/im-connect-service/src/main/resources" ["im-auth/target/im-auth.jar"]="im-auth/src/main/resources" ["im-business/im-business-service/target/im-business-service.jar"]="im-business/im-business-service/src/main/resources" ["im-console/im-console-service/target/im-console-service.jar"]="im-console/im-console-service/src/main/resources" )

for JAR*FILE in "${!JAR*FILES[@]}"; do TARGET*DIR="${JAR*FILES[$JAR*FILE]}" log ">>>>>>>>>>>> 复制 $JAR*FILE 到 $TARGET*DIR >>>>>>>>>>>>>" cp "$JAR*FILE" "$TARGET*DIR" || { log "Failed to copy $JAR*FILE to $TARGET_DIR"; exit 1; } done

cp docker-compose.yml ../

## 返回 docker-compose 目录

log ">>>>>>>>>>>> 返回到 docker-compose 目录 >>>>>>>>>>>>>" cd .. || { log "Failed to return to docker-compose directory"; exit 1; }

## 停止所有 docker-compose 运行的容器

log ">>>>>>>>>>>> 停止所有 docker-compose 运行的容器 >>>>>>>>>>>>>" docker-compose down || { log "Docker-compose down failed"; exit 1; }

## 构建镜像并启动容器

log ">>>>>>>>>>>> 构建镜像并启动容器 >>>>>>>>>>>>>" docker-compose up -d --build || { log "Docker-compose up failed"; exit 1; }

log ">>>>>>>>>>>> 部署结束 >>>>>>>>>>>>>"

## 清理 Docker 相关的垃圾

log ">>>>>>>>>>>> 清理 Docker 相关的垃圾 >>>>>>>>>>>>>" docker system prune -f --volumes || { log "Docker system prune failed"; exit 1; }

log ">>>>>>>>>>>> 清理完成 >>>>>>>>>>>>>" ```

#### 部署xzll-im项目

之后我们在这里点击build now开始构建并启动: ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/0cb79261cdd6481b89445fcb66f9c72a~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&x-expires=1721736303&x-signature=aHKHiCPuc%2FFUwZL%2FL23bh6AGteo%3D) 部署结果:

![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/8763576d2d9f43c883733847ce6120e8~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&x-expires=1721736303&x-signature=oxb73%2B6BiKhsiT2tvmZy4qJluDY%3D) 看到

Finished: SUCCESS

说明构建成功了(注意构建成功不等于微服务相关项目启动成功哦) ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/d8f92931bd2b46509c3cc85efd14a50a~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&x-expires=1721736303&x-signature=d6GhS7FbFB800N4530uGGkw%2BCuA%3D) 看一下启动情况(可知都正常启动了): ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/5e44921ccf7342eab1eba9f2a1e89342~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&x-expires=1721736303&x-signature=Cde%2B5ZIzWj4X9WpSO6CGdt6Uf58%3D) 当然最好看下各个服务的日志,这样才能确保真的启动成功(以im-connect服务为例): ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/46ad266bd5b845f882f5c7409e3ccbe1~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&x-expires=1721736303&x-signature=hM1aZ%2FQg6y6V8JNX7s0suIOt9z8%3D)

以上就是使用freestyle方式部署github项目的流程。挺简单的,但是大部分场景下不使用此方式,需要手动服务多的话比较费时费力。

### **方式二、** push代码后自动部署

一般在dev环境(测试环境一般不需要push即部署,因为那样影响测试稳定性)可能需要每次push后都需要让最新代码生效(也就是希望每次push后部署一遍,而如果这个工作靠人去完成的话服务多的话将会很累很烦,所以jenkins提供了个回调接口,也就是在github中配上jenkins的回调地址,当有某些事件时(一般是push事件)那么就回调jenkins 然后jenkins去进行自动部署)下边我们就看下如何 在push后让jenkins自动部署?

整个流程简单梳理为以下步骤:

1. 首先是配置github和jenkins (详情见下边)
2. 开发者push代码到github仓库
3. github通过此项目设置的webhook 告知(回调)jenkins接口,哎,有push事件了啊,你看你该怎么处理。
4. jenkins收到事件,进行处理(也就是部署项目)

#### 在github设置webhook

webhook的url其实就是 jenkins提供的

回调接口

的地址

进入项目,找到setting , 找到webhooks 并点击 add webhook 如下: ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/8a6b4611654741cc93cf54530ee3434d~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&x-expires=1721736303&x-signature=tZmhkuN5QycJm9iAPCJ7jarh8sY%3D)

> **注意:** 由于我的虚拟机是在局域网,github在外网访问不到我的虚拟机ip, 所以需要做一下 **内网穿透**,我这里使用**内网穿透**工具为 :**灵曜**, 一个好用、配置简单的内网穿透工具, 戳此进官网 http://www.http01.cn/

##### 内网穿透配置:

首先安装客户端(linux版本):

直粘贴脚本然后新建个目录执行就行,脚本如下: ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/7191347b361a445bbdbde5b5a064ff19~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&x-expires=1721736303&x-signature=VHVnKdPs46x0p7kNweq%2Fkn4ndqk%3D) 执行脚本 如下: ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/37c125eaafeb4dfebb2217b7b9d27f8e~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&x-expires=1721736303&x-signature=pxCfpdThc8lR2nz8%2F%2FibjnzrORs%3D) 完事你会在客户端这里看到你机器的信息: ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/3bf5542371a94b0ebf1f11073ca4ccaa~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&x-expires=1721736303&x-signature=OZgRCpVOiPZJZL6QGRQ6V6gWE%2Bw%3D) 之后编辑你的隧道:

> 暂时我先配成8079端口,也就是说通过此隧道只能访问jenkins服务(8079是jenkins端口),后续搞个nginx自己转发一下就更好了。

![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/dd09ac4ad0874beea22228558b9c3cf2~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&x-expires=1721736303&x-signature=ejjH%2FXZJ1qU9mVtReoaD4j236i8%3D) 配置之后你可以看到分配给你的公网域名以及过期时间等等信息: ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/5dbf0d3362804e6891819931fbdbf8d3~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&x-expires=1721736303&x-signature=UXfchWIBgQKMb1xfz1BsHz6%2B4dk%3D)

> 注意:(灵曜支持域名绑定,也就是说可以将你的腾讯云,阿里云域名绑定到你的隧道,并且可以设置https ,从而实现https访问方式访问你的局域网上的机器, 这里我为了简便就不做绑定了也不做https了 ,而是使用http 方式)

ok现在我们就将此公网域名配到github。

##### 配置webhook 以及触发回调的事件(这里为push代码时)

在github配置webhook地址:(注意接口url 是 

github-webhook

,这是固定的) ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/33601b2a8ada41eca7a6e7e50bf0929f~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&x-expires=1721736303&x-signature=nazzVjv3w7Zw1lEhbtV7kQe5rf4%3D) 设置好webhook后,点击add webhook,就可以看到已经添加的webhook了,注意,一定要保证图标是小对勾✅ 时说明github能访问通jenkins ,如果是红色叹号说明不行这时需要排查你的jenkins是否启动成功以及内网穿透是否好使,(当然,也可以从下边提示语知道成功与否) ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/8bf28575fa7045a0bb02e6bbb55aa70a~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&x-expires=1721736303&x-signature=Mg6mDwsT8qJFlW1KVPPLBz7mqas%3D)

之后我们还需要在github干一件事,就是生成access token ,从而让jenkins访问到github 服务(注意access token和 ssh方式不同,他可以更细粒度的控制用户的操作权限)。

接下来生成access token : ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/7c13212e2cc34d23863d199b0bc521e5~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&x-expires=1721736303&x-signature=0I%2F4MxYuokdtvE0eXcDJbYWVSuo%3D) 起个名字并设置此access token的相关权限: ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/64ff5b4064e24492807c18c67f4ca40e~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&x-expires=1721736303&x-signature=cQapds%2BOS%2BNVGuaVLCrirQMOXQI%3D) 之后点击最底部的生成,就看到下边的界面了:

> (注意一定要粘贴保存起来最好是你本地防止遗忘,因为下次再进来就不展示这个token了)

![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/ef8aa57e702449e6aeb0fc3d2cf54b89~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&x-expires=1721736303&x-signature=zEOs8WT%2BpQCKP3de7RqIK%2FiVzxA%3D)

ok到这一步,github设置好了,接下来就是设置jenkins了

#### 配置jenkins

##### 在jenkins 配置github server信息:

在jenkins的System config 添加github服务器设置:

注意想要配置这一步,你一定要安装以下插件: ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/bdf88e1a886f466db3808a00f1e70b31~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&x-expires=1721736303&x-signature=wNd5cW74nhL5WZ%2Fh516mWX04rEo%3D) 配置github server: ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/fc637f36dda54306bfe6a05900793bf0~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&x-expires=1721736303&x-signature=ABwthkntT1eTtQCosrwaNdhsBdA%3D)

##### 新增access token凭证

具体如下截图: ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/def0baf5e036470b8d321492b1dac4df~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&x-expires=1721736303&x-signature=OEAba54HJpc%2BmtyuSdeOOfY80II%3D) 选择刚创建的凭证并 **连接测试**![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/302afc7ae1a645aa8182b9fbc904a218~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&x-expires=1721736303&x-signature=6aCgsHHT%2BLIWY8b8iOoJVj6CQ3I%3D)

##### 修改 xzll-im-freestyle-project 项目的

触发器

构建环境


修改

xzll-im-freestyle-project

项目对应的配置,改动点如下: ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/d06e3f327c844278802ec81c2cecde3b~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&x-expires=1721736303&x-signature=u6Ah2Jdamor9GLhaGVXV7jcGdNE%3D) 到此github和jenkins相关的配置就配完了,点击应用。接下来我们push代码到github仓库,试试能不能触发jenkins自动部署!

#### push代码测试一下jenkins能不能自动部署

##### 随便改点东西,push上去:

![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/76afbe37e6c9432dadecb4349ef7bb3a~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&x-expires=1721736303&x-signature=pd7HdHO47ROQVTEzDPIVNGkyMSc%3D)

##### 观察日志,收到github回调通知

查看jenkins日志发现 收到了github的回调,如下: ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/0ab155f178fe44eda1e6fabd088d7272~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&x-expires=1721736303&x-signature=LFVGzgSSjjiED%2BuQ%2F63dpHBqJD0%3D)

##### 观察并验证启动结果

查看jenkins,可以看到32号任务正在执行: ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/5239782f157a459892e450b3cc87ea11~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&x-expires=1721736303&x-signature=SUwxZq1IliDfGtOavQbRJ%2BS9Ekc%3D)

看一下控制台的日志: ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/b779cfa9f58f4a288e1d5c74a3044b6b~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&x-expires=1721736303&x-signature=IszfeYez9O%2FuHFOpQGWpdasu3ls%3D)![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/eb9403a4c03c459db3590cf02ce95433~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&x-expires=1721736303&x-signature=rFBegNmrFRRbT81f2Ik0feiqQ70%3D)

看一下各容器的状态以及随便找一个服务看看日志: ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/11dd6e0ffd3d4642966b1fece66340ee~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&x-expires=1721736303&x-signature=a2G%2BICjKD%2F2XeJO%2BmuJkzbaqMKs%3D) 可以看出,各容器启动正常,日志也正常都起来了。

ok到这里,就实现了 **通过push 触发jenkins自动构建** 的目的了。当然按照CI的概念来说,你还需要在部署后自动运行自动化测试脚本,以及将测试的结果通知给开发人员以便进行问题修复(如果有的话)。

### **方式三、** pipleine构建

首先你要确保这一堆pipeline插件一键安装了,想使用pipeline功能,相关插件是不可少的。 ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/7f2632579de44af9a990b9f5c6050f53~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&x-expires=1721736303&x-signature=5O8gr%2BM5WrAYUA1DWSznVVTbux8%3D)

官方中文文档: https://www.jenkins.io/zh/doc/book/pipeline/

#### pipeline简介与使用方式

##### pipeline是什么?

注:pipeline使用中文可以理解为流水线、管道。

Pipeline 是Jenkins 2.X 的最核心的特性,帮助Jenkins 实现从CI 到 CD 与 DevOps的转变。 Pipeline 是一组插件,让jenkins 可以实现持续交付管道的落地和实施。持续交付管道是将软件从版本控制阶段到交付给用户/客户的完整过程的自动化表现。

> 大白话说其实Pipeline就是一个:**逻辑上的管道,在该管道中 你可以通过脚本 定义一系列的动作,pipeline会根据你的定义,自动化的完成整个构建、测试、交付等过程,从而实现(CD)持续交付的目的。**

##### 如何创建pipeline?

创建并定义pipeline有两种方式(这里我们简单描述下这两种方式 ,下边会进行实战演示),如下: 1. 直接

在 Jenkins Web 界面输入脚本

。 3. 编写 

Jenkinsfile

 文件并将文件存放到项目根目录。

> **何为Jenkinsfile?** 对Jenkins 流水线的定义可以被写在一个文本文件中 (此文件称为Jenkinsfile),该文件可以放在项目的根目录下,从而将 流水线的定义作为应用程序的一部分,像其他代码一样进行版本控制和代码审查。 

##### 在哪里配置pipeline?

1. 将流水线定义放在名为 ```Jenkinsfile``` 的文件中,存储在项目的根目录。使用 Jenkins 的 “Pipeline from SCM” 功能从版本控制系统中读取 ```Jenkinsfile``` 并执行流水线。
2. 直接在 Jenkins 的 Web 界面中编写和配置流水线脚本。在创建或配置一个 Pipeline 项目时,可以在 “Pipeline” 部分选择 “Pipeline script” 并直接输入脚本。

##### pipeline 的两种书写方式

分别是: 1. **Declarative Pipeline(声明式流水线)** 1. **Scripted Pipeline(脚本化流水线)**

###### 声明式流水线(Declarative Pipeline)

声明式流水线通过结构化、简单化的方式来定义流水线。它使用起来更为简单直观,使得新用户更容易上手。

**声明式流水线 

示例

(语法看不懂没关系,下边会有语法介绍):**

```groovy pipeline { agent any

stages {
stage('构建') {
steps {
echo '构建阶段...'
}
}
stage('测试') {
steps {
echo '测试阶段...'
}
}
stage('交付') {
steps {
echo '交付阶段...'
}
}
}


} ```

###### 脚本化流水线(Scripted Pipeline)

脚本化流水线提供了更为灵活和强大的语法,适用于需要复杂逻辑的场景。它完全基于 Groovy 脚本,可以使用 Groovy 的所有特性。

**脚本化流水线 

示例

:**

groovy node { stage('构建') { echo '构建中...' } stage('测试') { echo '测试中...' } stage('交付') { echo '交付中...' } }


###### 两者对比

Jenkinsfile能使用两种语法进行编写 - Declarative Pipeline声明式和Scripted Pipeline脚本化,两者都支持建立连续输送的Pipeline。这两种语法对比如下:


- **共同点:** 两者都是pipeline代码的持久实现,都能够使用pipeline内置的插件或者插件提供的steps,两者都可以利用共享库扩展。
- **区别:** 两者不同之处在于语法和灵活性。Declarative pipeline对用户来说,语法更严格,有固定的组织结构,更容易生成代码段,使其成为用户更理想的选择。

但是Scripted pipeline更加灵活,因为Groovy本身只能对结构和语法进行限制,对于更复杂的pipeline来说,用户可以根据自己的业务进行灵活的实现和扩展

**建议选择哪种语法?** 通常建议使用Declarative Pipeline的方式进行编写,从jenkins社区的动向来看,很明显这种语法结构也会是未来的趋势。声明式流水线比 Jenkins 脚本化流水线的特性: - 相比脚本化的流水线语法,它提供更丰富的语法特性 - 是为了使编写和读取流水线代码更容易而设计的

注:**在下边实战时,有关pipeline的脚本也是基于Declarative Pipeline(声明式流水线)的方式进行编写。**

##### pipeline语法

声明式流水线 的基本语法和表达式遵循 groovy语法,但是有以下

例外

: - **声明式pipeline** : 必须包含在固定格式的pipeline{} 块内,比如: 

pipeline { /* insert Declarative Pipeline here */ }

 - 每个声明语句必须独立一行, 行尾无需使用分号 - 块只能由阶段(stages{})、指令、步骤 (steps{})或赋值语句组成 - 属性引用语句被视为无参数方法调用, 如input() - **agent** :指定在哪个节点上执行流水线。可以是任意节点(

agent any

),特定标签的节点(

agent { label 'my-label' }

),或 Docker 容器(

agent { docker { image 'maven:3-alpine' } }

)。 - **stages** : 定义流水线的不同阶段,每个阶段包含多个步骤。 - **steps** : 每个阶段中执行的具体操作,如构建、测试和部署等。 - **post** :在流水线的各个阶段结束后执行的操作,例如清理、发送通知等 

语法很多,上边只列了一些比较重要的。

> 以上是常用的一些语法,,更详细的语法请参见官方文档: 英文版戳这里 , 中文版戳这里,中文版本翻译的有点那啥,将就看吧,英文好的直接看英文版官方文档。

##### 声明式pipeline 语法demo

由于本文准备使用声明式语法来构建JenkinsFile 所以在实战之前,写个简单的demo来熟悉下,声明式 pipeline内容 如下: 

// Jenkinsfile (Declarative Pipeline) pipeline { agent any stages { stage('Build') { steps { sh 'make' echo "hello world" script { def browsers = ['chrome', 'firefox'] for (int i = 0; i < browsers.size(); ++i) { echo "Testing the ${browsers[i]} browser" } } } } stage('Test'){ steps { sh 'make check' junit 'reports/**/*.xml' } } stage('Deploy') { steps { sh 'make publish' } } } }

 下边是解释:


- pipeline是声明式流水线的一种特定语法,他定义了包含执行整个流水线的所有内容和指令的 "block" 。
- agent 是声明式流水线的一种特定语法,指示 Jenkins 为整个流水线分配一个执行器(在 Jenkins 环境中的任何可用代理/节点上)和工作区。一般用作于指定在哪个节点上构建,如果不指定就写any表示任意节点。
- 定义 "Build" 、 "Test" 、 "Deploy" 三个阶段,每个阶段内部执行不同的步骤。
- stage 是一个描述 stage of this Pipeline的语法块。stage 块定义了在整个流水线的执行任务的概念性地不同的子集(比如 "Build", "Test" 和 "Deploy" 阶段), 它被许多插件用于可视化 或Jenkins流水线目前的 状态/进展,stage 块是可选的。
- steps 是声明式流水线的一种特定语法,它描述了在这个 stage 中要运行的步骤。
- sh 是一个执行给定的shell命令的流水线。
- echo 写一个简单的字符串到控制台输出。
- junit 是另一个聚合测试报告的流水线。
- 注意stage括号的值表示阶段名称,值内容不是固定的,根据需要自定义即可。

> 在有了基本的认识后,接下来就是对我的xzll-im进行 
> ```
> Jenkins pipeline
> ```
> 实战了。

---

#### 使用pipeline的方式,部署我的xzll-im项目

> **注意:本实战演示中使用的是
> ```
> 声明式流水线(Declarative Pipeline)
> ```
> 方式编写的pipeline脚本,且 
> ```
> web控制台方式
> ```
>  和 
> ```
> 项目根目录创建JenkinsFile方式
> ```
>  都会演示。**

##### 在Jenkins web页面配置声明式流水线脚本

首先创建个pipeline类型的任务: ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/de02ba09763a4dfda2f10fee9c86adbf~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&amp;x-expires=1721736303&amp;x-signature=CSCq%2FNkUW18wC5Yms5Uy1FVj0bQ%3D)

然后点击配置,如下: ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/fb57d096958540399298f8fd0c0d8040~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&amp;x-expires=1721736303&amp;x-signature=YNIKCHDybJiUUhSfEAbf892Wkss%3D) 进入配置页面后,拉到最下边,在定义这个栏目中,选择 Pipeline Script

> 注意,这里有两种类型,一个是 我们现在选择的 Pipeline script,一个是Pipeline script from SCM。
> 
> **Pipeline script** :代表就从下边的脚本输入框中寻找 pipeline脚本并执行
> 
> **Pipeline script from SCM**: 则代表从项目根目录中寻找 JenkinsFile中的内容作为 pipeline脚本,当是此模式时 ,无需在jenkins web中配置脚本了。

因为本小节演示的是

jenkins web控制台

配置 

声明式pipeline

脚本,所以在这里就选择 

Pipeline script

了,如下: ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/fae0ce3f18c04430867ef268db560738~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&amp;x-expires=1721736303&amp;x-signature=RkaIr92WP98zwc034u068TOAW9s%3D)

声明式脚本内容是我提前写好的(其实就是将方式一的脚本 改一下(

但增加了参数选择,从而在构建时可以选择分支

),改成遵循声明式pipeline语法的shell,本质上主流程还是不变的),声明式pipeline脚本如下:(

每个步骤都有注释,这里不过多解释了,详情看注释好了

) ```groovy

pipeline { agent any

parameters {
choice(
name: 'GIT_BRANCH',
choices: ['main', 'dev01', 'jenkins_build_20240709', 'docker_compose_way_bak','group_chat_dev_20240623'],
description: '选择Git分支' // 选择Git分支
)
}

environment {
COMPOSE_DIR = "/usr/local/soft_hzz/xzll-im/jar-file/jenkins_way_build_docker_compose/" // Docker Compose目录
GIT_REPO = "git@github.com:598572/xzll-im.git" // Git仓库地址
GIT_BRANCH = "${params.GIT_BRANCH}" // 选择的Git分支
}

stages {
stage('Prepare Environment') {
steps {
script {
log("开始部署") // 日志记录

            if (!fileExists(COMPOSE_DIR)) {
                log("目录不存在,创建目录 $COMPOSE_DIR")
                sh "mkdir -p $COMPOSE_DIR" // 创建Docker Compose目录
                exit_on_error("Failed to create directory $COMPOSE_DIR")
            }

            log("进入到 docker-compose 目录中")
            dir(COMPOSE_DIR) {} // 进入Docker Compose目录
        }
    }
}

stage('Clone or Update Repo') {
    steps {
        script {
            dir(COMPOSE_DIR) {
                if (!fileExists('xzll-im')) {
                    log("项目目录不存在,执行 git clone")
                    sh "git clone $GIT_REPO" // 克隆Git仓库
                    exit_on_error("Git clone failed")
                } else {
                    log("项目目录已存在,进入目录并执行 git pull")
                    dir('xzll-im') {
                        sh "git pull" // 更新Git仓库
                        exit_on_error("Git pull failed")
                    }
                }
            }
        }
    }
}

stage('Checkout Branch') {
    steps {
        script {
            dir("$COMPOSE_DIR/xzll-im") {
                log("进入项目根目录")
                sh "git fetch" // 拉取最新的分支信息
                sh "git checkout $GIT_BRANCH" // 切换到选择的分支
                exit_on_error("Failed to checkout branch")
            }
        }
    }
}

stage('Build Project') {
    steps {
        script {
            dir("$COMPOSE_DIR/xzll-im") {
                log("开始打包")
                sh "mvn clean package -P test" // 使用Maven打包项目
                exit_on_error("Maven build failed")
                log("打包完成")
            }
        }
    }
}

stage('Copy JAR Files') {
    steps {
        script {
            def jarFiles = [
                'im-gateway/target/im-gateway.jar': 'im-gateway/src/main/resources',
                'im-connect/im-connect-service/target/im-connect-service.jar': 'im-connect/im-connect-service/src/main/resources',
                'im-auth/target/im-auth.jar': 'im-auth/src/main/resources',
                'im-business/im-business-service/target/im-business-service.jar': 'im-business/im-business-service/src/main/resources',
                'im-console/im-console-service/target/im-console-service.jar': 'im-console/im-console-service/src/main/resources'
            ]

            dir("$COMPOSE_DIR/xzll-im") {
                jarFiles.each { jar, targetDir ->
                    log("复制 $jar 到 $targetDir")
                    sh "cp $jar $targetDir" // 复制JAR文件到相应目录
                    exit_on_error("Failed to copy $jar to $targetDir")
                }
                sh "cp docker-compose.yml ../" // 复制docker-compose.yml文件
            }
        }
    }
}

stage('Deploy with Docker Compose') {
    steps {
        script {
            dir(COMPOSE_DIR) {
                log("返回到 docker-compose 目录")
                sh "docker-compose down" // 停止并移除Docker容器
                exit_on_error("Docker-compose down failed")

                log("构建镜像并启动容器")
                sh "docker-compose up -d --build" // 构建镜像并启动容器
                exit_on_error("Docker-compose up failed")
            }
        }
    }
}

stage('Clean Up') {
    steps {
        script {
            log("清理 Docker 相关的垃圾")
            sh "docker system prune -f --volumes" // 清理Docker垃圾
            exit_on_error("Docker system prune failed")
            log("清理完成")
        }
    }
}

}

post {
always {
script {
log("部署结束") // 部署结束的日志
}
}
success {
script {
log("构建成功") // 构建成功的日志
}
emailext (
subject: "Jenkins 构建成功通知: ${currentBuild.fullDisplayName}",
body: """Jenkins 构建成功通知:
项目: ${env.JOB_NAME}
构建编号: ${env.BUILD_NUMBER}
构建URL: ${env.BUILD_URL}""",
to: 'h163361631@163.com' // 构建成功发送邮件通知
)
}
failure {
script {
log("构建失败") // 构建失败的日志
}
emailext (
subject: "Jenkins 构建失败通知: ${currentBuild.fullDisplayName}",
body: """Jenkins 构建失败通知:
项目: ${env.JOB_NAME}
构建编号: ${env.BUILD_NUMBER}
构建URL: ${env.BUILD_URL}""",
to: 'h163361631@163.com' // 构建失败发送邮件通知
)
}
}


}

def log(message) { echo "[${new Date().format('yyyy-MM-dd HH:mm:ss')}] ${message}" // 日志记录函数 }

def exit*on*error(message) { 
 if (currentBuild.result == 'FAILURE') { error(message) // 构建失败时退出并记录错误信息 } } ```

> 提示:发邮件的话需要安装个插件: ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/afc7a73f17e54a65aea0906786225200~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&amp;x-expires=1721736303&amp;x-signature=Pc2Endr3iCBXTyWb46kTlI%2F%2FcwU%3D)

配完pipeline后,来试一把,首先我们点击build with parameters 然后选择你要部署的分支,我这里是:jenkins*build*20240709,之后点击build: ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/e010964f243140538217d426fb6be49f~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&amp;x-expires=1721736303&amp;x-signature=XGQ4VCGxn1DX8jhy3AuYC%2B9g5kg%3D) 随后jenkins就开始构建了,找到控制台日志,可以看到已经部署成功(任务编号是13) ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/fb4770a46de14b16b59b0a148cc4eea2~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&amp;x-expires=1721736303&amp;x-signature=bhA3FHDufRnqTcAGGtDf4oDs5mI%3D)![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/6662474c196f444cab122f10047d56c1~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&amp;x-expires=1721736303&amp;x-signature=IDG0I4HXFihtfcVtrmagKz6GFfo%3D) 构建成功后会发送邮件,如下: ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/5301537c7a4c45e4b9ebe10769e08332~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&amp;x-expires=1721736303&amp;x-signature=TXU7IGOKLT90YqC1YFujxxnMQC0%3D) 你可以直观的查看整个管道的步骤,用时等等,如下: ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/54018f821d1e40da975a0a18e066390f~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&amp;x-expires=1721736303&amp;x-signature=ifmWUJ5oUqhrTtoGA5gunfHFzQI%3D)![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/2544809e5d234e92ac9f33d7cfb4f413~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&amp;x-expires=1721736303&amp;x-signature=iqj%2FFBDomOJqdnrDYfJAJ2OnxmQ%3D) 看下docker容器和日志发现,服务都启动成功了: ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/9ac7e442a49b481092d8c734ba64b4f4~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&amp;x-expires=1721736303&amp;x-signature=8jeN1qz%2BoDeapUSoQjge7ZwjSBk%3D)

接下来我们看下pipeline 的第二种方式

##### 在项目根目录的JenkinsFile 文件中编写声明式流水线脚本的方式启动构建任务

首先我们创建一个jenkins 任务,命名为: xzll-im-pipeline-build-by-Jenkinsfile,如下: ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/e66d6a4832554e6db9ac929c5601ef82~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&amp;x-expires=1721736303&amp;x-signature=9xq%2Bg2%2BINkx5ykJ8Om2Eu22fNIo%3D)

之后我们点击配置: ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/f6dfb093d3b140cc9910c3489a09f534~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&amp;x-expires=1721736303&amp;x-signature=GH0IkoEDzPIt3G3df9DHOfhyHKM%3D)![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/def85824dd6e40e3a5b102abebcff4e5~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&amp;x-expires=1721736303&amp;x-signature=7iNJ0MJOvgXjTVA%2FlRDWBunkiaY%3D)

之后我们在项目根目录创建Jenkinsfile文件,并将上边的脚本粘到此文件中,并提交到代码仓库,如下: ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/c43354e8d6de489ba33094a76f42daf4~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&amp;x-expires=1721736303&amp;x-signature=%2BeWzcLTBMjdy6bu%2BkI7hM2KOaZ8%3D)

然后选择你想要部署的分支进行部署

> (注意:第一次时可能不展示build with parameters 还是 build now 那么这时你点击下budil now 再给他停掉,刷新下就展示 build with parameters 构建类型了 ),如下:

![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/dc6cdaadbc6a4e3d9f9b9ff1e42c8e31~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&amp;x-expires=1721736303&amp;x-signature=Hnp7inFIfj5W3yUtGI5gMehHJmc%3D)

看下控制台打印的部署日志、构建过程视图、邮件、以及docker容器启动情况,如下: ![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/a063ee02b1d745d4a9541fcce5964aad~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&amp;x-expires=1721736303&amp;x-signature=yljwB5gB4KiJ2RzRAh1pzspbSS8%3D)![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/f1733212ce38496dae60b986867d0a4b~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&amp;x-expires=1721736303&amp;x-signature=4LhMpWePelFkggobJyR5QNcV2sY%3D)![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/84c35b187ebb4dd5871ac07c95c4d7f7~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&amp;x-expires=1721736303&amp;x-signature=Mz%2FI4uB6o2%2Bxgrlwsy4%2BTMRHsnU%3D)![image.png](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/6824a55b8eaf49f380e50aeaed516f4d~tplv-73owjymdk6-watermark.image?rk3s=f64ab15b&amp;x-expires=1721736303&amp;x-signature=GSItgBDOLfZwrcE5DMNuRugoOu0%3D)

ok到这里使用pipeline方式部署项目的实战演示就结束了,在这两种方式中(两种方式指的是 

jenkins web配置pipeline脚本

项目根目录创建并编写Jenkinsfile文件

```
),我们都是手动build触发任务的,如果想做到push代码即部署?好办,参考方式2 配一个 构建触发器就好啦! 下边我们试试。

pipeline + push

由于现在是push就提交,所以没发选择了只能是在push时指定,所以把choice选择参数这个注掉,然后push到仓库,如下: image.png

之后我发现Jenkins 已经收到了github的回调,并且开始执行23号部署任务: image.pngimage.png

部署结果【成功部署,以及启动docker容器和发通知邮件】,如下: image.pngimage.pngimage.png

至此,本文就结束了。

别看Jenkins是个工具,但是他很重要,东西也挺多的,想用好的话也得下点功夫研究。 到此,你get了什么是CI/CD 以及Jenkins的几种构建方式了吗??

标签: ci/cd jenkins 运维

本文转载自: https://blog.csdn.net/hzzdecsdn/article/details/140481270
版权归原作者 蝎子莱莱爱打怪 所有, 如有侵权,请联系我们删除。

“CI/CD详解 & Jenkins 介绍与实战”的评论:

还没有评论