前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >打造企业级自动化运维平台系列(七):Jenkis 部署 Springboot 应用实践

打造企业级自动化运维平台系列(七):Jenkis 部署 Springboot 应用实践

作者头像
民工哥
发布2024-01-18 16:52:19
2160
发布2024-01-18 16:52:19
举报

Jenkins 自动化部署 SpringBoot

准备

本文所有的部署都是在CentOS 7上完成,软件安装都采用的是Docker,如果你想跟着这个教程搭建,需要准备一下环境:

  • 2台CentOS 7 的电脑 / 虚拟机:没有物理机的,可以使用虚拟机的方式来搭建,本文就是采用的虚拟机来配置;

以下两台测试机器的IP和功能点

  • 192.168.1.253 安装Jenkins、GitLab
  • 192.168.1.237 运行打包后的项目
  • Docker 安装:服务编排采用的docker-compose
  • JDK安装:参考前面的文章
  • Maven安装:参考前面的文章
软件安装

由于是工具类的软件,为了减少对机器的侵入, Jenkins 和代码仓库 GitLab的安装都是采用的Docker的方式,所以请提前安装好Docker。

Jenkins

准备挂载目录,用于持久化数据

代码语言:javascript
复制
mkdir -p /var/jenkins/datachmod 777 /var/jenkins/datacd /var/jenkins/data

查看Docker的组ID

重要!这个步骤很重要,因为后续Jenkins使用的是宿主机的 Docker ,所以在启动的时候,就需要做好Docker的映射以及权限组ID的配置;

代码语言:javascript
复制
cat /etc/group | grep docker

每台电脑都会有所差异,下面是我两台虚拟机对应的ID;

记住你装Jenkins那一台的ID,在下个步骤配置docker-compose时,需要在group_add中配置上对应的ID;这里务必要配置正确,否则后面在Jenkins容器中使用Docker命令时,会报权限不足的错误。

准备docker-compose-jenkins.yml配置文件

代码语言:javascript
复制
vim docker-compose-jenkins.yml  

#添加以下配置
version: '2'
services:
  jenkins:
    container_name: 'jenkins'
    image: 'jenkins/jenkins'
    restart: always
    environment:
      TZ: 'Asia/Shanghai'
    ports:
      - '8880:8080'
      - '50000:50000'
    group_add:
      - 994
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /usr/bin/docker:/usr/bin/docker
      - /var/jenkins/data:/var/jenkins_home
      - /usr/local/apache-maven-3.8.6:/usr/local/apache-maven-3.8.6

启动

代码语言:javascript
复制
# 启动docker-compose -f docker-compose-jenkins.yml up -d# 查看容器docker ps | grep jenkins

初始化:容器启动,大约等1分钟之后,就可以来初始化Jenkins了,安装推荐插件:参考之前的文章去选择。默认也可以。

  • 安装插件

后续还需要用到一些插件,这里提前安装一下。安装入口:系统管理-->插件管理-->可选插件。注意!所有插件在重启之后才会生效

  • 汉化插件
  • Maven插件 本文演示的下项目是通过Maven管理,搜索Maven Integration安装Maven相关插件
  • Git 插件
  • GitLab插件
  • SSH 插件 用于将文件上传到远端服务器
  • webhook
全局配置

主要是配置一些基础的环境,比如Maven、Git、JDK等工具,便于后续构建的时候,能够直接使用这些全局的基础配置。

Maven配置:这里的Maven是容器启动时,映射的宿主机的包,如果你是下载的其他的版本或者映射的其他路径,请根据实际情况调整;

  • Maven优化

可以通过配置 MAVEN_OPTS 避免编译复杂项目时出现内存泄漏等问题。

  • JDK配置

Docker安装的Jenkins容器自带了JDK,所以这里只需要拿到容器内的JDK路径,配置上即可;获取当时如下:

代码语言:javascript
复制
# 进去容器docker exec -it jenkins /bin/bash# 输出JDK的环境变量echo $JAVA_HOME
  • SSH Server配置

这里配置的是远端服务器的信息(也就是代码最终运行的服务器信息);

Gitlab

GitLab 是一个用于仓库管理系统的开源项目,使用 Git 作为代码管理工具,并在此基础上搭建起来的Web服务。

准备docker-compose

代码语言:javascript
复制
version: '2'
services:
    gitlab:
      container_name: 'gitlab-ce-zh'
      image: 'twang2218/gitlab-ce-zh'
      restart: unless-stopped
      hostname: 'gitlab'
      environment:
        TZ: 'Asia/Shanghai'
        GITLAB_OMNIBUS_CONFIG: |
          external_url 'http://192.168.1.253:880'
      ports:
        - '880:880'
        - '8443:443'
        - '2212:22'
      volumes:
        - /var/gitlab/etc:/etc/gitlab
        - /var/gitlab/log:/var/log/gitlab
        - /var/gitlab/data:/var/opt/gitlab

其中external_url中的IP为你本地机器的IP;地址的端口和容器映射的端口要保持一致,否则将无法访问。

启动

代码语言:javascript
复制
docker-compose -f docker-compose-gitlab.yml up -ddocker ps | grep gitlab

状态变成healthy,说明服务已经正常。

访问上一步的external_url(本机:http://192.168.1.253:880)设置管理员密码。

设置完之后,就使用root和你新设置的密码,登录即可进入gitlab的主页。

配置Jenkins、GitLab关联

由于后续Jenkins需要自动在Gitlab中获取最新的代码,因此,需要提前配置身份认证令牌。

GitLab令牌
代码语言:javascript
复制
hYw-Qy6KxGFsdzGA96Ux

每次创建的都会不一样;而且,这个令牌只会显示一次,之后就不会再显示了,所以请保存好;否则就只能重新生成了;

Jenkins配置GitLab的凭据

将前面步骤生成的GitLab令牌配置成Jenkins的全局凭据,以方便后续的使用。

选择管理凭据

点击Jenkins

点击全局凭据

点击添加凭据

输入Token:选择GitLab API token,然后输入前一步在GitLab中创建好的token

创建成功:点击Create按钮即可创建凭据

Jenkins配置GitLab的基础信息
构建Maven项目
准备项目

本教程使用的源码:https://github.com/vehang/ehang-spring-boot

  • 本地GitLab创建一个项目,源码创建了一个jenkins分支,推送到本地Gitlab仓库。
准备脚本

此脚本的作用就是将Jenkins传到运行服务器的Jar包给跑起来;下面只是一个最基础的脚本,个人可以根据实际的使用过程,再进行调整;

代码语言:javascript
复制
#!/bin/sh
 
# JDK的环境变量
export JAVA_HOME=/usr/local/jdk-11.0.14
export PATH=$JAVA_HOME/bin:$PATH
 
# 基础路径,由参数传入
# 多模块的时候,需要在路径中使用*统配一下多模块
# 比如/opt/ehang-spring-boot是多模块,下面由module1和module2
# 那么执行shell的时候使用:sh restart.sh /opt/ehang-spring-boot/\*  注意这里的*需要转义一下
JAR_BATH=$1
echo "基础路径:"$JAR_BATH
JAR_PATH=${JAR_BATH}/target/*.jar
 
# 获取所有的JAR 开始遍历
for JAR_FILE in $JAR_PATH
do
if [ -f $JAR_FILE ]
then
  echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
  echo "JAR路径:"$JAR_FILE
  JAR_FILE_MD5=${JAR_FILE}.md5
 
  # 用于标记是否需要重启的标识
  RESTART=false
 
  # 判断MD5文件是否存在,存在就校验MD5值
  if [ -f $JAR_FILE_MD5 ]; then
    # 校验MD5
    md5sum --status -c $JAR_FILE_MD5
    # = 0表示校验成功 =1 表示校验失败
    if [ $? = 1 ];then
      echo "MD5校验失败,安装包已经更新!"
      RESTART=true
    else
      echo "安装包没有更新!"
    fi
  else
    echo "没有MD5值,说明是第一次启动"
    RESTART=true
  fi
 
  # 获取进程号
  PROCESS_ID=`ps -ef | grep $JAR_FILE | grep -v grep | awk '{print $2}'`
  # 如果不需要重启,但是进程号没有,说明当前jar没有启动,同样也需要启动一下
  if [ $RESTART == false ] && [ ${#PROCESS_ID} == 0 ] ;then
     echo "没有发现进程,说明服务未启动,需要启动服务"
     RESTART=true
  fi
 
  # 如果是需要启动
  if [ $RESTART == true ]; then
      # kill掉原有的进程
      ps -ef | grep $JAR_FILE | grep -v grep | awk '{print $2}' | xargs kill -9
 
      #如果出现Jenins Job执行完之后,进程被jenkins杀死,可尝试放开此配置项
      #BUILD_ID=dontKillMe
      #启动Jar
      nohup java -jar $JAR_FILE  > ${JAR_FILE}.log 2>&1 &
      # =0 启动成功 =1 启动失败
      if [ $? == 0 ];then
          echo "restart success!!! process id:" `ps -ef | grep $JAR_FILE | grep -v grep | awk '{print $2}'`
      else
          echo "启动失败!"
      fi
 
      # 将最新的MD5值写入到缓存文件
      echo `md5sum $JAR_FILE` > $JAR_FILE_MD5
  fi
  echo "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  echo ""
fi
done

脚本细节,注释已经写的很清楚了;简单说一下脚本的流程:

  • 执行脚本传入单模块/多模块的路径
    • 注意:多模块的时候,需要使用*通配一下各个模块,执行命令的时候,需要通过*转义一下;详情见下图
  • 遍历目录中target目录下的所有jar包
  • 校验MD5,MD5没有或者对不上,说明更新了,否则对应包没有更新
  • 当不需要更新时,校验进程是否存在,如果进程不存在,同样需要启动
  • 启动jar
  • 将最新的MD5值缓存起来
Jenkins创建Maven任务

创建Maven任务

Maven任务配置

设置gitlab凭据,选择前面步骤配置的凭据。

设置GitLab项目地址:首次配置,这里需要先添加Git仓库的凭据信息,步骤如下:

配置构建命令

代码语言:javascript
复制
clean package  -DskipTests=true

注意这里本身就是使用的Maven构建,所以命令不需要在前面加上mvn

构建完后上传文件

上传脚本:在上传Jar包之前,我们需要将项目的启动/重启脚本传到服务器,方便后续jar上传完之后,就能直接执行了。

代码语言:javascript
复制
Transfer Set Source files  #表示要传输的文件/文件规则
Remove prefix  #要去掉文件的前缀,比如以上配置,默认文件路径是:script/jenkins/abc.sh,在这里配置script/jenkins/就只会将abc.sh拷贝到远端目录,否则,script/jenkins/abc.sh 完整的拷贝过去。
Remote directory  #拷贝的远端路径,如果不配置,就是有SSH Server中配置的路径,我ssh server配置的远端路径为/opt/jenkins/package
Exec command  #拷贝完之后,执行的脚本

上传Jar包:由于项目是多模块的,打包之后,每个模块都会打出一个jar包,分别放在各个模块的target目录下;我们需要作的就是将所有模块的Jar都拷贝到服务器并启动;

上传成功之后,会在/opt/jenkins/package目录下看到所有的包信息:

拷贝完之后,将执行shell脚本,单模块和多模块执行的命令仅仅为参数上的区别:

单模块:以spring-boot-001-hello-world/target/spring-boot-001-hello-world-0.0.1-SNAPSHOT.jar为单模块的包进行测试,执行的重启脚本为:

代码语言:javascript
复制
sh /opt/jenkins/package/jenkins_restart.sh /opt/jenkins/package/spring-boot-001-hello-world

其中参数/opt/jenkins/package/spring-boot-001-hello-world为单模块的根目录

多模块:多模块仅仅只是路径不同而已

代码语言:javascript
复制
sh /opt/jenkins/package/jenkins_restart.sh /opt/jenkins/package/*

其中/opt/jenkins/package/*用于指明/opt/jenkins/package路径下的所有子模块Jar包都重启;其中*表示通配。

注意:由于这里执行了shell脚本,所以配置的时候,一定要在高级选项中将Exec in pty勾选上,否则shell命令执行不会终止,直到超时结束,如下日志:

代码语言:javascript
复制
....
SSH: Connecting with configuration [centos_server] ...
SSH: Disconnecting configuration [centos_server] ...
ERROR: Exception when publishing, exception message [Exec timed out or was interrupted after 120,000 ms]
Build step 'Send files or execute commands over SSH' changed build result to UNSTABLE
Finished: UNSTABLE

开启控制台的输出日志:初次配置的时候,容易出现异常情况,为了方便排查问题,可以勾上下图左侧的选项,输出远端服务器执行日志;下图右侧中的日志就是远端执行shell脚本的输出;不勾选将不会有这些日志。

手动构建

选择项目,点击“立即构建”即可开始,执行完如果是绿色,说明构建成功,红色表示失败。

自动构建

Jenkins任务开启监听:前面的手动构建已经完成了,我们最终的目的是希望能够做到代码一提交,就自动构建并发布。

Jenkins中开启Gitlab的监听,并设置一个token(可以不设置)

配置好之后,得到了以下的信息:

  • 钩子地址:http://192.168.1.253:8880/project/ehang-spring-boot
  • token
    • 97a6a4c1601cebe83241a08a67fd3755
    • token是为了安全性,也可以不设置,根据个人的需要来定

GitLab配置钩子

找到项目之后,按着上图的步骤,将jenkins的地址、token以及触发条件配置好后,点击添加按钮;

自动触发事件

下面就来通过git提交一段代码,看能否自动触发 https://img-blog.csdnimg.cn/img_convert/3c49134400fafb8f3301d2a4e99efe72.gif 动图中可以看到,当代码成功push2秒之后,Jenkins就已经自动开始构建任务了。执行完之后,查看Jenkins的日志与Linux的服务进程,服务已经正常启动。

Jenkins 自动部署 SpringBoot 多模块应用

上面写的jenkins_restart.sh脚本,在多模块部署的时候,没办法检测到未更新的模块。假如一个项目,分了10个小模块,类似于下图:

本次修改,只是模块①修复了1个Bug,其他9个都没有变动,那么编译打包整个项目之后,也只需要更新模块①即可,其他的9个模块完全可以不做任何操作,要做到这一需求,就需要在这10个模块中找出那些模块更新了,那些没有更新;上篇文章中采用的方案是:计算 jar 包的MD5,如果MD5值一样,说明没有更新。

下面就一起来把之前的那个教程再完善一下!

问题复现

MD5 判断文件是否改变,这思路似乎没有任何问题;代码既然没做任何改变,所有文件结构目录也相同,那按理说打出来的Jar包的MD5值应该是一样的,但为什么会有问题呢?为了验证这个问题,对项目连续打两次包,分别得到两个相同大小的a.jarb.jar;然后做了MD5计算,发现确实不一样:

然后Beyound对两个包进行比较,发现除了修改时间不同,文件内容也都是一摸一样的;

原因:Zip在压缩的时候,会将将文件的access time写入到压缩包中,压缩包里面虽然保存的文件内容虽然是一致的,但由于时间不同,导致最终压缩包的MD5值也就不一致;因此,jar 包所面临的问题就属于类似的情况。

解决方案

既然知道包里面的文件都是一样的,只是由于压缩带来的问题,我们完全可以换个思路来解决,将Jar包解压之后,判断各个文件是否发生变化,同样也能够校验出来,过程如下:

1.先直接校验Jar的MD5

如果Jar都没有重新编译打包,那不用说,MD5值肯定相同;

2.使用unzip命令解压Jar包

如果直接校验Jar没通过,就继续以解压校验文件详情的方式进行校验;

代码语言:javascript
复制
unzip app.jar -d /tmp/jar_unzip_tmp
3.通过find命令查找解压目录下的所有文件并计算MD5值
代码语言:javascript
复制
find /tmp/jar_unzip_tmp -type f -print | xargs md5sum > ./jar_files
# 上面的这条命令等价于下面这个for循环
#for file in `find /tmp/jar_unzip_tmp`
#do
#  if [ -f $file ];then
#    echo $file
#    `md5sum $file >> ./jar_files`
#  fi
#done

得到的jar_files;左侧表示文件的MD5值,右侧为文件的路径;如果文件内容发生变化,左侧MD5就会不同,如果是结构/目录发生变化,右侧的详细路径就会不一样;

4.计算详情列表(jar_files)对应的MD5值

如果代码发生变化、目录结构发生变化,得到的文件详情列表就是产生差异,那根据详情列表得到的MD5值也就不同了

  • 没有或者与前一次不一样MD5文件 说明发生变化,需要更新重启;Docker的方式,需要构建镜像上传
  • MD5校验一致 未发生变化,跳过
Jenkins 多模块自动构建

本文的主要目的是:优化多模块的自动化构建,能感知变化,只自动部署已经修改的模块;

通过上面的原因分析以及解决方案梳理,需要调整一下相关的脚本;

以下的内容是基于上面内容的改进:SSH的方式主要是修改jenkins_restart.sh脚本

把这个脚本的修改带入到前文的对应的地方,就能正常使用了;如果还没有看过前文,麻烦稍微花点时间阅读一下,再继续往下看;

SSH方式优化

主要的修改是在jenkins_restart.sh脚本上,当Jar被传到运行服务,执行jenkins_restart.sh脚本启动各个模块的时候,解压检测,变化的就重启,没变的就跳过。

代码语言:javascript
复制
#!/bin/sh

# JDK的环境变量
export JAVA_HOME=/usr/local/jdk-11.0.14
export PATH=$JAVA_HOME/bin:$PATH

# 基础路径,由参数传入
# 多模块的时候,需要在路径中使用*统配一下多模块
# 比如/opt/ehang-spring-boot是多模块,下面由module1和module2
# 那么执行shell的时候使用:sh restart.sh /opt/ehang-spring-boot/\*  注意这里的*需要转义一下
JAR_BATH=$1
echo "基础路径:"$JAR_BATH
JAR_PATH=${JAR_BATH}/target/*.jar

# jar_check_md5 通过jar的md5值直接检测
# jar_unzip_check_md5 通过对jar包解压 校验文件详情的MD5
# check_md5 汇总上面两个方法的校验

# 直接通过jar校验
jar_check_md5() {
  # jar 包的路径
  JAR_FILE=$1
  if [ ! -f $JAR_FILE ]; then
    # 如果校验的jar不存在 返回失败
    return 1
  fi

  JAR_MD5_FILE=${JAR_FILE}.md5
  echo "Jenkins Docker镜像构建校验 JAR的MD5文件:"$JAR_MD5_FILE
  if [ -f $JAR_MD5_FILE ]; then
    md5sum --status -c $JAR_MD5_FILE
    RE=$?
    md5sum $JAR_FILE > $JAR_MD5_FILE
    return $RE
  else
    md5sum $JAR_FILE > $JAR_MD5_FILE
  fi

  return 1
}

# 将Jar解压之后校验
jar_unzip_check_md5() {
  # jar 包的路径
  UNZIP_JAR_FILE=$1
  if [ ! -f $UNZIP_JAR_FILE ]; then
    # 如果校验的jar不存在 返回失败
    return 1
  fi

  # jar的名称
  UNZIP_JAR_FILE_NAME=`basename -s .jar $UNZIP_JAR_FILE`
  echo "Jenkins Docker镜像构建校验 JAR包名称:"$UNZIP_JAR_FILE_NAME
  # jar所在的路径
  UNZIP_JAR_FILE_BASE_PATH=${UNZIP_JAR_FILE%/${UNZIP_JAR_FILE_NAME}*}
  echo "Jenkins Docker镜像构建校验 JAR包路径:"$UNZIP_JAR_FILE_BASE_PATH
  # 解压的临时目录
  JAR_FILE_UNZIP_PATH=${UNZIP_JAR_FILE_BASE_PATH}/jar_unzip_tmp
  echo "Jenkins Docker镜像构建校验 解压路径:"$JAR_FILE_UNZIP_PATH

  # 用于缓存解压后文件详情的目录
  UNZIP_JAR_FILE_LIST=${UNZIP_JAR_FILE_BASE_PATH}/${UNZIP_JAR_FILE_NAME}.files
  echo "Jenkins Docker镜像构建校验 jar文件详情路径:"$UNZIP_JAR_FILE_LIST
  # 缓存解压后文件详情的MD5
  UNZIP_JAR_FILE_LIST_MD5=${UNZIP_JAR_FILE_BASE_PATH}/${UNZIP_JAR_FILE_NAME}.files.md5
  echo "Jenkins Docker镜像构建校验 jar文件详情MD5校验路径:"$UNZIP_JAR_FILE_LIST

  rm -rf $JAR_FILE_UNZIP_PATH
  mkdir -p $JAR_FILE_UNZIP_PATH
  # 解压文件到临时目录
  unzip $UNZIP_JAR_FILE -d $JAR_FILE_UNZIP_PATH
  # 遍历解压目录,计算每个文件的MD5值及路径 输出到详情列表文件中
  find $JAR_FILE_UNZIP_PATH -type f -print | xargs md5sum > $UNZIP_JAR_FILE_LIST
  rm -rf $JAR_FILE_UNZIP_PATH

  if [ ! -f $UNZIP_JAR_FILE_LIST_MD5 ]; then
    # 如果校验文件不存在 直接返回校验失败
    md5sum $UNZIP_JAR_FILE_LIST > $UNZIP_JAR_FILE_LIST_MD5
    return 1
  fi

  # 根据上一次生成的MD5校验
  md5sum --status -c $UNZIP_JAR_FILE_LIST_MD5
  RE=$?
  # 生成最新的文件列表的MD5
  md5sum $UNZIP_JAR_FILE_LIST > $UNZIP_JAR_FILE_LIST_MD5
  # 返回校验结果
  return $RE
}

check_md5() {
  # jar 包的路径
  JAR_FILE=$1
  if [ -f $JAR_FILE ]; then
    # 直接通过jar校验
    jar_check_md5 $JAR_FILE
    if [ $? = 0 ];then
      echo "Jenkins Docker镜像构建校验 通过Jar的MD5校验成功"
      return 0
    else
      echo "Jenkins Docker镜像构建校验 通过Jar的MD5校验失败"
    fi

    # 通过解压jar 校验是否更新
    jar_unzip_check_md5 $JAR_FILE
    if [ $? = 0 ];then
      echo "Jenkins Docker镜像构建校验 通过解压的MD5校验成功"
      return 0
    else
      echo "Jenkins Docker镜像构建校验 通过解压的MD5校验失败"
    fi
  fi
  return 1
}

# 获取所有的JAR 开始遍历
for JAR_FILE in $JAR_PATH
do
if [ -f $JAR_FILE ]
then
  echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
  echo "JAR路径:"$JAR_FILE

  APP_UPDATE=false
  check_md5 $JAR_FILE
  if [ $? = 0 ];then
    echo "Jenkins Docker镜像构建校验lib!成功,没有发生变化"$JAR_FILE
  else
    APP_UPDATE=true
    echo "Jenkins Docker镜像构建校验lib!失败,已经更新"$JAR_FILE
  fi

  # 获取进程号 判断当前服务是否启动;如果Jar没变,但是服务未启动,也需要执行启动脚本
  PROCESS_ID=`ps -ef | grep $JAR_FILE | grep -v grep | awk '{print $2}'`
  # 如果不需要重启,但是进程号没有,说明当前jar没有启动,同样也需要启动一下
  if [ $APP_UPDATE == false ] && [ ${#PROCESS_ID} == 0 ] ;then
     echo "没有发现进程,说明服务未启动,需要启动服务"
     APP_UPDATE=true
  fi

  # 如果是需要启动
  if [ $APP_UPDATE == true ]; then
      # kill掉原有的进程
      ps -ef | grep $JAR_FILE | grep -v grep | awk '{print $2}' | xargs kill -9

      #如果出现Jenins Job执行完之后,进程被jenkins杀死,可尝试放开此配置项
      #BUILD_ID=dontKillMe
      #启动Jar
      nohup java -jar $JAR_FILE > ${JAR_FILE}.log 2>&1 &
      # =0 启动成功 =1 启动失败
      if [ $? == 0 ];then
          echo "restart success!!! process id:" `ps -ef | grep $JAR_FILE | grep -v grep | awk '{print $2}'`
      else
          echo "启动失败!"
      fi
  fi
  echo "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  echo ""
fi
done

稍微有点点长,这里分段来说明一下,详细的细节,可以查看对应的注释。

公共方法:直接通过Jar的MD5值检测

代码语言:javascript
复制
# 直接通过jar校验
jar_check_md5() {
  # jar 包的路径
  JAR_FILE=$1
  if [ ! -f $JAR_FILE ]; then
    # 如果校验的jar不存在 返回失败
    return 1
  fi
 
  JAR_MD5_FILE=${JAR_FILE}.md5
  echo "Jenkins Docker镜像构建校验 JAR的MD5文件:"$JAR_MD5_FILE
  if [ -f $JAR_MD5_FILE ]; then
    md5sum --status -c $JAR_MD5_FILE
    RE=$?
    md5sum $JAR_FILE > $JAR_MD5_FILE
    return $RE
  else
    md5sum $JAR_FILE > $JAR_MD5_FILE
  fi
  return 1
}

公共方法:通过解压Jar,根据文件详情的MD5值检验是否改变

代码语言:javascript
复制
# 将Jar解压之后校验
jar_unzip_check_md5() {
  # jar 包的路径
  UNZIP_JAR_FILE=$1
  if [ ! -f $UNZIP_JAR_FILE ]; then
    # 如果校验的jar不存在 返回失败
    return 1
  fi
 
  # jar的名称
  UNZIP_JAR_FILE_NAME=`basename -s .jar $UNZIP_JAR_FILE`
  echo "Jenkins Docker镜像构建校验 JAR包名称:"$UNZIP_JAR_FILE_NAME
  # jar所在的路径
  UNZIP_JAR_FILE_BASE_PATH=${UNZIP_JAR_FILE%/${UNZIP_JAR_FILE_NAME}*}
  echo "Jenkins Docker镜像构建校验 JAR包路径:"$UNZIP_JAR_FILE_BASE_PATH
  # 解压的临时目录
  JAR_FILE_UNZIP_PATH=${UNZIP_JAR_FILE_BASE_PATH}/jar_unzip_tmp
  echo "Jenkins Docker镜像构建校验 解压路径:"$JAR_FILE_UNZIP_PATH
 
  # 用于缓存解压后文件详情的目录
  UNZIP_JAR_FILE_LIST=${UNZIP_JAR_FILE_BASE_PATH}/${UNZIP_JAR_FILE_NAME}.files
  echo "Jenkins Docker镜像构建校验 jar文件详情路径:"$UNZIP_JAR_FILE_LIST
  # 缓存解压后文件详情的MD5
  UNZIP_JAR_FILE_LIST_MD5=${UNZIP_JAR_FILE_BASE_PATH}/${UNZIP_JAR_FILE_NAME}.files.md5
  echo "Jenkins Docker镜像构建校验 jar文件详情MD5校验路径:"$UNZIP_JAR_FILE_LIST
 
  rm -rf $JAR_FILE_UNZIP_PATH
  mkdir -p $JAR_FILE_UNZIP_PATH
  # 解压文件到临时目录
  unzip $UNZIP_JAR_FILE -d $JAR_FILE_UNZIP_PATH
  # 遍历解压目录,计算每个文件的MD5值及路径 输出到详情列表文件中
  find $JAR_FILE_UNZIP_PATH -type f -print | xargs md5sum > $UNZIP_JAR_FILE_LIST
  rm -rf $JAR_FILE_UNZIP_PATH
 
  if [ ! -f $UNZIP_JAR_FILE_LIST_MD5 ]; then
    # 如果校验文件不存在 直接返回校验失败
    md5sum $UNZIP_JAR_FILE_LIST > $UNZIP_JAR_FILE_LIST_MD5
    return 1
  fi
 
  # 根据上一次生成的MD5校验
  md5sum --status -c $UNZIP_JAR_FILE_LIST_MD5
  RE=$?
  # 生成最新的文件列表的MD5
  md5sum $UNZIP_JAR_FILE_LIST > $UNZIP_JAR_FILE_LIST_MD5
  # 返回校验结果
  return $RE
}

公共方法:check_md5

代码语言:javascript
复制
check_md5() {
  # jar 包的路径
  JAR_FILE=$1
  if [ -f $JAR_FILE ]; then
    # 直接通过jar校验
    jar_check_md5 $JAR_FILE
    if [ $? = 0 ];then
      echo "Jenkins Docker镜像构建校验 通过Jar的MD5校验成功"
      return 0
    else
      echo "Jenkins Docker镜像构建校验 通过Jar的MD5校验失败"
    fi
 
    # 通过解压jar 校验是否更新
    jar_unzip_check_md5 $JAR_FILE
    if [ $? = 0 ];then
      echo "Jenkins Docker镜像构建校验 通过解压的MD5校验成功"
      return 0
    else
      echo "Jenkins Docker镜像构建校验 通过解压的MD5校验失败"
    fi
  fi
 
  return 1
}

判断Jar是否更新

代码语言:javascript
复制
check_md5 $JAR_FILE
if [ $? = 0 ];then
  echo "Jenkins Docker镜像构建校验lib!成功,没有发生变化"$JAR_FILE
else
  APP_UPDATE=true
  echo "Jenkins Docker镜像构建校验lib!失败,已经更新"$JAR_FILE
fi

判断进程是否存在

代码语言:javascript
复制
PROCESS_ID=`ps -ef | grep $JAR_FILE | grep -v grep | awk '{print $2}'`
# 如果不需要重启,但是进程号没有,说明当前jar没有启动,同样也需要启动一下
if [ $RESTART == false ] && [ ${#PROCESS_ID} == 0 ] ;then
   echo "没有发现进程,说明服务未启动,需要启动服务"
   RESTART=true
fi

剩下的就是重启的逻辑了。

测试

至此,多模块优化就已经弄好了,文中是根据个人的小项目在做演示,思路在文中已经说清楚了,大家可以根据自己实际的业务需求,进行适当调整,以满足自己实际的项目需求。

参考文章:https://blog.csdn.net/a2285786446/article /details/130981868 https://blog.csdn.net/lililidahaoren /article/details/126590979

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2024-01-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 民工哥技术之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Jenkins 自动化部署 SpringBoot
    • 准备
      • 软件安装
        • 全局配置
          • Gitlab
            • 构建Maven项目
            • Jenkins 自动部署 SpringBoot 多模块应用
              • 问题复现
                • 解决方案
                  • Jenkins 多模块自动构建
                  相关产品与服务
                  容器服务
                  腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档