Jenkins + SpringBoot + 钉钉 一键打包部署项目

安装插件

除了安装 Jenkins 推荐的一些插件,还需要安装如下插件:

  • Maven Integration
  • Maven Info
  • Publish Over SSH
  • Extended Choice Parameter
  • Git Parameter

远程服务器配置

目录及脚本

在远程服务器上,需要创建 Java 项目部署的目录。每个公司制定的目录规范不同,例如固定在/work/projects目录下,创建每个项目的部署目录。并且,每个项目独立一个子目录。例如说:

$ pwd
/work/projects/app-demo

$ ls
backup      build      app-demo.jar      shell

app-demo 目录,会放置一个项目的所有。

在每个子目录下,固定分成如下文件/目录:

  • app-demo.jar:项目的 jar 包
  • build 目录:Jenkins 构建完项目后的新 jar 包,会上传到 build 目录下,避免对原 jar 包覆盖,导致无法正常关闭 Java 服务
  • backup 目录:对历史 jar 包的备份目录。每次使用新的 jar 启动服务时,会将老的 jar 移到 backup 目录下备份
  • shell 目录:脚本目录。目前只有 deploy.sh 脚本

整个deploy.sh脚本,有接近 200 行不到,核心代码如下:

#!/bin/bash
set -e

# 基础
# export JAVA_HOME=/work/programs/jdk/jdk1.8.0_181
# export PATH=PATH=$PATH:$JAVA_HOME/bin
# export CLASSPATH=$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

DATE=$(date +%Y%m%d%H%M)
# 基础路径
BASE_PATH=/work/projects/lab-41-demo01
# 编译后 jar 的地址。部署时,Jenkins 会上传 jar 包到该目录下
SOURCE_PATH=$BASE_PATH/build
# 服务名称。同时约定部署服务的 jar 包名字也为它。
SERVER_NAME=lab-41-demo01
# 环境
PROFILES_ACTIVE=prod
# 健康检查 URL
HEALTH_CHECK_URL=http://127.0.0.1:8078/actuator/health/

# heapError 存放路径
HEAP_ERROR_PATH=$BASE_PATH/heapError
# JVM 参数
JAVA_OPS="-Xms1024m -Xmx1024m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$HEAP_ERROR_PATH"
# JavaAgent 参数。可用于配置 SkyWalking 等链路追踪
JAVA_AGENT=

# 备份
function backup() {
    // ... 省略代码
}

# 最新构建代码 移动到项目环境
function transfer() {
    // ... 省略代码
}

# 停止
function stop() {
    // ... 省略代码
}

# 启动
function start() {
    // ... 省略代码
}

# 健康检查
function healthCheck() {
    // ... 省略代码
}

# 部署
function deploy() {
    cd $BASE_PATH
    # 备份原 jar
    backup
    # 停止 Java 服务
    stop
    # 部署新 jar
    transfer
    # 启动 Java 服务
    start
    # 健康检查
    healthCheck
}

deploy

在开头,我们定义了一堆变量。在结尾,我们可以看到对deploy()方法,进行项目的部署。整个步骤,分为 5 步,分别对应 5 个方法。我们逐个方法来看看。

backup

backup()方法,将原 jar 包备份到 backup 目录下。代码如下:

function backup() {
    # 如果不存在,则无需备份
    if [ ! -f "$BASE_PATH/$SERVER_NAME.jar" ]; then
        echo "[backup] $BASE_PATH/$SERVER_NAME.jar 不存在,跳过备份"
    # 如果存在,则备份到 backup 目录下,使用时间作为后缀
    else
        echo "[backup] 开始备份 $SERVER_NAME ..."
        cp $BASE_PATH/$SERVER_NAME.jar $BASE_PATH/backup/$SERVER_NAME-$DATE.jar
        echo "[backup] 备份 $SERVER_NAME 完成"
    fi
}

stop

stop()方法,将原 jar 包对应的 Java 进程,进行优雅关闭。代码如下:

function stop() {
    echo "[stop] 开始停止 $BASE_PATH/$SERVER_NAME"
    PID=$(ps -ef | grep $BASE_PATH/$SERVER_NAME | grep -v "grep" | awk '{print $2}')
    # 如果 Java 服务启动中,则进行关闭
    if [ -n "$PID" ]; then
        # 正常关闭
        echo "[stop] $BASE_PATH/$SERVER_NAME 运行中,开始 kill [$PID]"
        kill -15 $PID
        # 等待最大 60 秒,直到关闭完成。
        for ((i = 0; i < 60; i++))
            do  
                sleep 1
                PID=$(ps -ef | grep $BASE_PATH/$SERVER_NAME | grep -v "grep" | awk '{print $2}')
                if [ -n "$PID" ]; then
                    echo -e ".\c"
                else
                    echo '[stop] 停止 $BASE_PATH/$SERVER_NAME 成功'
                    break
                fi
      done

        # 如果正常关闭失败,那么进行强制 kill -9 进行关闭
        if [ -n "$PID" ]; then
            echo "[stop] $BASE_PATH/$SERVER_NAME 失败,强制 kill -9 $PID"
            kill -9 $PID
        fi
    # 如果 Java 服务未启动,则无需关闭
    else
        echo "[stop] $BASE_PATH/$SERVER_NAME 未启动,无需停止"
    fi
}
  • 首先,获得到 Java 服务对应的 PID 进程编号
  • 然后,先kill -15对应进程,尝试正常关闭 Java 服务。考虑到整个关闭是一个过程,所以我们需要等待一段时间,直到 Java 服务正常关闭。这里定义的 60 秒,如果需要更短或者更长,可以自行修改
  • 最后,万一 Java 服务无法正常关闭,则kill -9对应进程,强制关闭 Java 服务

友情提示:如果不希望强制关闭 Java 服务,可以考虑此处进行exit 1,异常退出部署,然后人工介入,进行问题的排查

transfer

transfer()方法,将 build 目录的新 jar 包,“覆盖”到老的 jar 包上。代码如下:

function transfer() {
    echo "[transfer] 开始转移 $SERVER_NAME.jar"

    # 删除原 jar 包
    if [ ! -f "$BASE_PATH/$SERVER_NAME.jar" ]; then
        echo "[transfer] $BASE_PATH/$SERVER_NAME.jar 不存在,跳过删除"
    else
        echo "[transfer] 移除 $BASE_PATH/$SERVER_NAME.jar 完成"
        rm $BASE_PATH/$SERVER_NAME.jar
    fi

    # 复制新 jar 包
    echo "[transfer] 从 $SOURCE_PATH 中获取 $SERVER_NAME.jar 并迁移至 $BASE_PATH ...."
    cp $SOURCE_PATH/$SERVER_NAME.jar $BASE_PATH

    echo "[transfer] 转移 $SERVER_NAME.jar 完成"
}

这里,我们并不是直接覆盖,因为cp命令覆盖时,系统会提示是否尽心覆盖,需要手动输入 y 指令,显然无法满足我们自动化部署的需要

start

start()方法,使用新的 jar 包,启动 Java 服务。代码如下:

function start() {
    # 开启启动前,打印启动参数
    echo "[start] 开始启动 $BASE_PATH/$SERVER_NAME"
    echo "[start] JAVA_OPS: $JAVA_OPS"
    echo "[start] JAVA_AGENT: $JAVA_AGENT"
    echo "[start] PROFILES: $PROFILES_ACTIVE"

    # 开始启动
    BUILD_ID=dontKillMe nohup java -server $JAVA_OPS $JAVA_AGENT -jar $BASE_PATH/$SERVER_NAME.jar --spring.profiles.active=$PROFILES_ACTIVE &
    echo "[start] 启动 $BASE_PATH/$SERVER_NAME 完成"
}

比较简单,核心就是通过java -jar命令,通过 jar 包来启动 Java 服务。

healthCheck

healthCheck()方法,通过健康检查 URL ,判断 Java 服务是否启动成功。代码如下:

function healthCheck() {
    # 如果配置健康检查,则进行健康检查
    if [ -n "$HEALTH_CHECK_URL" ]; then
        # 健康检查最大 60 秒,直到健康检查通过
        echo "[healthCheck] 开始通过 $HEALTH_CHECK_URL 地址,进行健康检查";
        for ((i = 0; i < 60; i++))
            do
                # 请求健康检查地址,只获取状态码。
                result=`curl -I -m 10 -o /dev/null -s -w %{http_code} $HEALTH_CHECK_URL || echo "000"`
                # 如果状态码为 200,则说明健康检查通过
                if [ "$result" == "200" ]; then
                    echo "[healthCheck] 健康检查通过";
                    break
                # 如果状态码非 200,则说明未通过。sleep 1 秒后,继续重试
                else
                    echo -e ".\c"
                    sleep 1
                fi
            done

        # 健康检查未通过,则异常退出 shell 脚本,不继续部署。
        if [ ! "$result" == "200" ]; then
            echo "[healthCheck] 健康检查不通过,可能部署失败。查看日志,自行判断是否启动成功";
            tail -n 10 nohup.out
            exit 1;
        # 健康检查通过,打印最后 10 行日志,可能部署的人想看下日志。
        else
            tail -n 10 nohup.out
        fi
    # 如果未配置健康检查,则 slepp 60 秒,人工看日志是否部署成功。
    else
        echo "[healthCheck] HEALTH_CHECK_URL 未配置,开始 sleep 60 秒";
        sleep 60
        echo "[healthCheck] sleep 60 秒完成,查看日志,自行判断是否启动成功";
        tail -n 50 nohup.out
    fi
}

和 Java 服务的关闭一样,Java 服务的启动也是一个过程。这里,我们提供了两种策略:

1)通过健康检查 URL,自动判断应用是否启动成功。通过Spring Boot Actuator提供的 health 端点,判断请求返回的状态码是否为 200。如果是,则说明应用健康,启动完成
2)未配置健康检查 URL 的情况下,我们通过 sleep 60 秒,然后查看日志,人工判断是否启动成功

Jenkins 部署任务配置

从 Jenkins 首页开始,点击「新建Item」按钮,进入 Jenkins 任务创建界面。输入任务名,并选择构建一个 Maven 项目

详细配置

(1)General

比较简单,只需要配置下描述即可

(2)Maven Info Plugin Configuration

  • Discard old builds 配置项:设置保留的构建。因为我们会不断的重新构建项目,如果不进行设置,Jenkins 所在服务器的磁盘可能会不够用
  • This project is parameterized 配置项:参数化构建。这里,我们使用 Git Parameter 插件,创建了参数名为BRANCH,值为 Git 项目的 Branch/Tag。如此,我们在后续的项目构建中,可以选择构建的 Git 项目的分支/标签

(3)源码管理

  • 选择 Git,从而选择 Git 仓库
  • Repositories 配置项:设置使用的 Git 仓库
  • Branches to build 配置项:设置使用的 Git 分支/标签。这里,我们使用「Maven Info Plugin Configuration」配置的构建参数BRANCH

(4)构建触发器

暂时不需要配置,可无视

(5)构建环境

暂时不需要配置,可无视

(6)Pre Steps

暂时不需要配置,可无视

(7)Build

  • Root POM 配置项:设置根 pom.xml 配置文件。一般情况下,设置 pom.xml 即可
  • Goals and options 配置项:设置 Maven 构建命令
    • 这里,因为我们只想构建app-demo/app-demo01子 Maven 模块,所以使用-pl app-demo/app-demo01参数
    • 如果要构建整个项目,可以考虑使用clean package -Dmaven.test.skip=true命令

(8)Post Steps

暂时不需要配置,可无视

(9)构建设置

暂时不需要配置,可无视

(10)构建后操作

点击「增加构建后操作步骤」按钮,选择「Send build artifacts over SSH」选项,配置将 Maven 构建出来的 jar 包,通过 SSH 发送到远程服务器,并执行相应脚本,进行启动 Java 服务

  • Name 配置项:选择部署的远程服务器。这里,我们选择「远程服务器配置」的服务器
  • Transfer Set Sources files 配置项:设置传输的文件。这里,我们输入app-demo/app-demo01/target/*.jar地址,表示传输的是app-demo/app-demo01子 Maven 模块构建出来的 jar 包
  • 如果是使用clean install -Dmaven.test.skip=true命令时,则此处配置target/*.jar即可
  • Remove prefix 配置项:设置传输的文件,需要移除的前缀。这里,我们输入app-demo/app-demo01/target/地址,表示传输到远程时,文件名仅为*.jar的名字
  • Remote directory 配置项:传输到远程服务器的目录。这里,我们输入/work/projects/app-demo01/build地址,表示传输到远程服务器的app-demo01项目的 build 目录
  • Exec command 配置项:设置传输完文件后,执行的 Shell 命令。这里,我们输入cd /work/projects/app-demo01/shell && ./deploy.sh命令,表示执行部署脚本,进行启动 Java 服务
  • Exec in pty 配置项:必须勾选上,表示模拟一个终端执行脚本。如果不勾选上它,执行命令会超时。该配置项,需要点击其所在表单的「高级」按钮,才能展示出来
  • Add Server 按钮:如果要部署到更多的远程服务器,部署多个节点,可以点击,进行配置
  • 点击下面的「高级」按钮,将「Fail the build if an error occurs」选项选择上,通过这个选项,我们在执行 Shell 命令发生错误时,可以将部署任务的每一次部署,标记为 Failure 失败

至此,我们已经完成 Jenkins 部署任务的配置,点击最下面「保存」按钮,进行配置的保存

邮件通知

Jenkins 支持配置邮件通知,在构建成功(Success)、构建失败(Fail)、构建不稳定(Unstable)时,发送相应的邮件。

全局的邮箱配置

(1)从 Jenkins 首页开始,按照「Manage Jenkins -> Configure System」的顺序,进入「配置」界面,然后下拉到「邮件通知」位置,配置发送通知的邮箱

  • SMTP服务器:smtp.163.com
  • 用户默认邮件后缀:@163.com
  • 用户名:myname@163.com
  • 使用SSL协议:打钩
  • SMTP端口:465
  • 字符集:UTF-8
  • 测试接收邮箱:10086@qq.com

(2)不过要注意,一些邮箱服务,要求使用 SMTP 认证的用户名和发件邮箱保持一致,例如说网易 163 邮箱。因此,我们上拉到「Jenkins Location」位置,配置发件邮箱

Jenkins URL:https://jk.appblog.cn
系统管理员邮件地址:myname@163.com

(3)配置完成后,点击「邮件通知」位置的「Test configuration」按钮,测试发送邮箱的功能。如果测试通过,在界面上我们会看到 "Email was successfully sent" 提示。同时,我们打开收件邮箱,会看到测试邮件

(4)测试通过后,记得点击「保存」按钮

部署任务的邮箱配置

在「Jenkins 部署任务配置」的基础上,我们修改邮件配置。一共有两处配置项

(1)构建设置 -> E-mail Notification

  • Recipients:收件人
  • Send e-mail for every unstable build:当构建不稳定时,发送邮件(可打钩)
  • Send separate e-mails to individuals who broke the build:是否构建失败、不稳定时,只发给构建人
  • Send e-mail for each failed module:当构建失败时,发送邮件(可打钩)

这里主要配置构建失败、构建不稳定情况下的邮箱通知配置

(2)构建后操作

点击「增加构建后操作步骤」按钮,选择「Editable Email Notification」选项,配置构建成功情况下的邮箱通知配置。

  • Project Recipient List 配置项:配置收件人列表,每行一个
  • 其它配置项,我们可以暂时不配置,如有需要,可以自行配置。另外,上面的$DEFAULT_RECIPIENTS$DEFAULT_REPLYTO等变量,是由Extended E-mail Notification插件提供,可以按照「Manage Jenkins -> Configure System」的顺序,进入「配置」界面,然后下拉到「Extended E-mail Notification」位置,进行配置

钉钉通知

Jenkins 支持配置钉钉通知,在构建成功(Success)、构建失败(Fail)、构建不稳定(Unstable)时,发送相应的通知

安装插件

默认情况下,提供钉钉通知的 Jenkins 插件Dingding Notification Plugin并未安装,所以我们需要进行安装

创建钉钉群机器人

注意:Jenkins目前配置的钉钉通知方式,暂时不支持钉钉群机器人的“加密”安全方式,所以请使用“IP地址(段)”的安全设置,配置外网地址白名单

部署任务的钉钉配置

在「Jenkins 部署任务配置」的基础上,我们修改钉钉配置。仅仅修改一处配置项即可

(1)构建后操作

点击「增加构建后操作步骤」按钮,选择「钉钉通知器配置」选项,配置构建成功情况下的钉钉通知配置

  • Jenkins URL
  • 钉钉access token
  • 在启动构建时通知
  • 构建成功时通知
  • 构建失败时通知
  • 构建中断时通知

(2)简单测试

配置完成后,记得点击「保存」按钮!然后,可以进行一次部署测试,看看钉钉通知的效果

版权声明:
作者:Joe.Ye
链接:https://www.appblog.cn/index.php/2023/04/01/jenkins-springboot-dingtalk-one-click-packaging-deployment-project/
来源:APP全栈技术分享
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
打赏
海报
Jenkins + SpringBoot + 钉钉 一键打包部署项目
安装插件 除了安装 Jenkins 推荐的一些插件,还需要安装如下插件: Maven Integration Maven Info Publish Over SSH Extended Choice Parameter Git Paramete……
<<上一篇
下一篇>>
文章目录
关闭
目 录