Jenkins备份及回滚方式

PS:备份脚本存放位置(使用时将脚本放置环境服务包下)注意权限问题

在使用前备份脚本和回滚脚本需要根据实际的服务名称进行修改,并创建备份目录

使用SSH Pubishers执行脚本

执行脚本后,备份文件存放位置(以服务名称为文件,服务加时间戳为文件版本)

根据构建时间给予备份文件

回滚jar

备份脚本

复制代码
#!/bin/bash
set -e  # 出错立即退出,避免静默失败

# ========== 备份配置项(根据实际修改) ==========
APP_NAME="admin"          # 应用名称
ONLINE_APP_DIR="/home/work/app/service/xxx/"       # 线上应用包目录
BACKUP_DIR="/home/work/app/backup/xxx/"    # 备份目录
RETENTION_DAYS=0                 # 备份保留天数
AUDIT_LOG="/home/work/soft/logs/backup_audit.log"  # 备份审计日志

# ========== 核心逻辑 ==========
# 1. 生成精确到秒的时间戳
TIMESTAMP=$(date +%Y%m%d%H%M%S)
# 2. 定义文件路径
ONLINE_APP_PATH="${ONLINE_APP_DIR}/${APP_NAME}.jar"
BACKUP_APP_PATH="${BACKUP_DIR}/${APP_NAME}-${TIMESTAMP}.jar"

# 3. 校验线上包是否存在
if [ ! -f "${ONLINE_APP_PATH}" ]; then
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: 线上包 ${ONLINE_APP_PATH} 不存在,备份失败!" >> ${AUDIT_LOG}
    echo "ERROR: 线上包不存在,备份失败!"
    exit 1
fi

# 4. 执行备份(-p 保留文件属性:权限、时间、属主)
echo "[$(date +'%Y-%m-%d %H:%M:%S')] INFO: 开始备份 ${ONLINE_APP_PATH} -> ${BACKUP_APP_PATH}" >> ${AUDIT_LOG}
cp -p ${ONLINE_APP_PATH} ${BACKUP_APP_PATH}


# 5. 校验备份是否成功(对比文件大小)
ONLINE_SIZE=$(du -b ${ONLINE_APP_PATH} | awk '{print $1}')
BACKUP_SIZE=$(du -b ${BACKUP_APP_PATH} | awk '{print $1}')
if [ "${ONLINE_SIZE}" != "${BACKUP_SIZE}" ]; then
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: 备份包大小不一致,备份失败!" >> ${AUDIT_LOG}
    rm -f ${BACKUP_APP_PATH}  # 删除损坏的备份包
    exit 1
fi

# 6. 清理过期备份
echo "[$(date +'%Y-%m-%d %H:%M:%S')] INFO: 清理${RETENTION_DAYS}天前的备份..." >> ${AUDIT_LOG}
find ${BACKUP_DIR} -name "${APP_NAME}-*.jar" -mtime +${RETENTION_DAYS} -delete >> ${AUDIT_LOG} 2>&1

# 7. 记录审计日志
echo "[$(date +'%Y-%m-%d %H:%M:%S')] SUCCESS: 备份成功,备份包路径:${BACKUP_APP_PATH}" >> ${AUDIT_LOG}

# 8. 输出成功信息(供Jenkins日志查看)
echo "备份成功!"
echo "备份包路径:${BACKUP_APP_PATH}"
echo "当前备份列表(按时间倒序):"
ls -lh ${BACKUP_DIR}/${APP_NAME}-*.jar | sort -k9r

exit 0

回滚脚本

复制代码
#!/bin/bash
set -e  # 出错立即退出,避免静默失败

# ========== 备份配置项(根据实际修改) ==========
APP_NAME="admin"          # 应用名称
ONLINE_APP_DIR="/home/work/app/service/xxx/"       # 线上应用包目录
BACKUP_DIR="/home/work/app/backup/xxx/"    # 备份目录
RETENTION_DAYS=0                 # 备份保留天数
AUDIT_LOG="/home/work/soft/logs/backup_audit.log"  # 备份审计日志

# ========== 核心逻辑 ==========
# 1. 生成精确到秒的时间戳
TIMESTAMP=$(date +%Y%m%d%H%M%S)
# 2. 定义文件路径
ONLINE_APP_PATH="${ONLINE_APP_DIR}/${APP_NAME}.jar"
BACKUP_APP_PATH="${BACKUP_DIR}/${APP_NAME}-${TIMESTAMP}.jar"

# 3. 校验线上包是否存在
if [ ! -f "${ONLINE_APP_PATH}" ]; then
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: 线上包 ${ONLINE_APP_PATH} 不存在,备份失败!" >> ${AUDIT_LOG}
    echo "ERROR: 线上包不存在,备份失败!"
    exit 1
fi

# 4. 执行备份(-p 保留文件属性:权限、时间、属主)
echo "[$(date +'%Y-%m-%d %H:%M:%S')] INFO: 开始备份 ${ONLINE_APP_PATH} -> ${BACKUP_APP_PATH}" >> ${AUDIT_LOG}
cp -p ${ONLINE_APP_PATH} ${BACKUP_APP_PATH}


# 5. 校验备份是否成功(对比文件大小)
ONLINE_SIZE=$(du -b ${ONLINE_APP_PATH} | awk '{print $1}')
BACKUP_SIZE=$(du -b ${BACKUP_APP_PATH} | awk '{print $1}')
if [ "${ONLINE_SIZE}" != "${BACKUP_SIZE}" ]; then
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: 备份包大小不一致,备份失败!" >> ${AUDIT_LOG}
    rm -f ${BACKUP_APP_PATH}  # 删除损坏的备份包
    exit 1
fi

# 6. 清理过期备份
echo "[$(date +'%Y-%m-%d %H:%M:%S')] INFO: 清理${RETENTION_DAYS}天前的备份..." >> ${AUDIT_LOG}
find ${BACKUP_DIR} -name "${APP_NAME}-*.jar" -mtime +${RETENTION_DAYS} -delete >> ${AUDIT_LOG} 2>&1

# 7. 记录审计日志
echo "[$(date +'%Y-%m-%d %H:%M:%S')] SUCCESS: 备份成功,备份包路径:${BACKUP_APP_PATH}" >> ${AUDIT_LOG}

# 8. 输出成功信息(供Jenkins日志查看)
echo "备份成功!"
echo "备份包路径:${BACKUP_APP_PATH}"
echo "当前备份列表(按时间倒序):"
ls -lh ${BACKUP_DIR}/${APP_NAME}-*.jar | sort -k9r

exit 0
[root@rocky9-0 scripts]# cat rollback_service.sh 
#!/bin/bash
set -e  # 出错立即退出,避免静默失败

# ========== 回滚配置项(和备份脚本完全对齐) ==========
APP_NAME="XXX"          # 应用名称
ONLINE_APP_DIR="/home/lyszwork/app/service/XXX/"       # 线上应用包目录
BACKUP_DIR="/home/lyszwork/app/backup/XXX"    # 备份目录
AUDIT_LOG="/home/lyszwork/soft/logs/rollback_service.log"  # 复用备份审计日志

# 【核心配置】应用启停命令(
STOP_APP_CMD="sh /home/lyszwork/app/service/common-service-center/deploy.sh stop"
START_APP_CMD="sh /home/lyszwork/app/service/common-service-center/deploy.sh start"

# ========== 核心回滚逻辑 ==========
# 1. 前置校验:检查备份目录是否存在
if [ ! -d "${BACKUP_DIR}" ]; then
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: 备份目录 ${BACKUP_DIR} 不存在!" >> ${AUDIT_LOG}
    echo "ERROR: 备份目录不存在,无法回滚!"
    exit 1
fi

# 2. 列出所有备份包(按时间倒序),筛选上一个版本
# 获取备份包列表(排除当前行),按时间戳降序排列
BACKUP_LIST=($(ls ${BACKUP_DIR}/${APP_NAME}-*.jar 2>/dev/null | sort -r))
if [ ${#BACKUP_LIST[@]} -eq 0 ]; then
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: 未找到任何备份包!" >> ${AUDIT_LOG}
    echo "ERROR: 无备份包可回滚!"
    exit 1
fi

# 选择"上一个版本"(列表第一个即为最新备份,也就是要回滚的目标版本)
TARGET_BACKUP=${BACKUP_LIST[0]}
echo "[$(date +'%Y-%m-%d %H:%M:%S')] INFO: 选定回滚版本:${TARGET_BACKUP}" >> ${AUDIT_LOG}
echo "✅ 选定回滚版本:${TARGET_BACKUP}"

# 3. 备份当前线上包(防止回滚失败)
CURRENT_TIMESTAMP=$(date +%Y%m%d%H%M%S)
BACKUP_BEFORE_ROLLBACK="${BACKUP_DIR}/${APP_NAME}-current-before-rollback-${CURRENT_TIMESTAMP}.jar"
echo "[$(date +'%Y-%m-%d %H:%M:%S')] INFO: 备份当前线上包到 ${BACKUP_BEFORE_ROLLBACK}" >> ${AUDIT_LOG}
cp -p ${ONLINE_APP_DIR}/${APP_NAME}.jar ${BACKUP_BEFORE_ROLLBACK} 2>/dev/null || {
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] WARNING: 当前线上包不存在,直接使用备份包覆盖!" >> ${AUDIT_LOG}
}

# 4. 停止应用(避免Jar包被占用)
echo "[$(date +'%Y-%m-%d %H:%M:%S')] INFO: 停止应用 ${APP_NAME}..." >> ${AUDIT_LOG}
echo "🔴 停止应用中..."
${STOP_APP_CMD} || {
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] WARNING: 应用停止命令执行失败(可能应用已停止)" >> ${AUDIT_LOG}
    echo "⚠️  应用停止命令执行失败(可能应用已停止),继续回滚..."
}

# 5. 执行回滚:替换线上Jar包
echo "[$(date +'%Y-%m-%d %H:%M:%S')] INFO: 开始回滚,替换线上包..." >> ${AUDIT_LOG}
echo "🔄 执行回滚替换Jar包..."
cp -p ${TARGET_BACKUP} ${ONLINE_APP_DIR}/${APP_NAME}.jar

# 校验回滚是否成功(对比文件大小)
BACKUP_SIZE=$(du -b ${TARGET_BACKUP} | awk '{print $1}')
ROLLBACK_SIZE=$(du -b ${ONLINE_APP_DIR}/${APP_NAME}.jar | awk '{print $1}')
if [ "${BACKUP_SIZE}" != "${ROLLBACK_SIZE}" ]; then
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: 回滚包大小不一致,回滚失败!" >> ${AUDIT_LOG}
    # 回滚失败:恢复之前备份的当前包
    cp -p ${BACKUP_BEFORE_ROLLBACK} ${ONLINE_APP_DIR}/${APP_NAME}.jar 2>/dev/null
    rm -f ${BACKUP_BEFORE_ROLLBACK}
    echo "❌ 回滚失败,已恢复原线上包!"
    exit 1
fi

# 6. 启动应用
echo "[$(date +'%Y-%m-%d %H:%M:%S')] INFO: 启动应用 ${APP_NAME}..." >> ${AUDIT_LOG}
echo "🟢 启动应用中..."
${START_APP_CMD} || {
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: 应用启动失败!" >> ${AUDIT_LOG}
    echo "❌ 应用启动失败,请手动检查!"
    exit 1
}

# 7. 记录成功日志
echo "[$(date +'%Y-%m-%d %H:%M:%S')] SUCCESS: 回滚完成!目标版本:${TARGET_BACKUP}" >> ${AUDIT_LOG}
echo -e "\n✅ 回滚成功!"
echo "📌 回滚版本:${TARGET_BACKUP}"
echo "📌 线上包路径:${ONLINE_APP_DIR}/${APP_NAME}.jar"
echo "📌 请检查应用日志,确认服务正常运行!"

exit 0
相关推荐
2401_8734794010 分钟前
断网时如何实时判断IP归属?嵌入本地离线库,保障风控不中断
运维·服务器·网络
守城小轩18 分钟前
基于Chrome140的Yahoo自动化(关键词浏览)——需求分析&环境搭建(一)
运维·自动化·chrome devtools·浏览器自动化·指纹浏览器·浏览器开发
handler0141 分钟前
Linux 内核剖析:进程优先级、上下文切换与 O(1) 调度算法
linux·运维·c语言·开发语言·c++·笔记·算法
日取其半万世不竭3 小时前
LVM 逻辑卷管理:不停机扩容磁盘的正确方式
运维·服务器
优化Henry3 小时前
TDD-LTE站点Rilink=3链路故障处理案例---BBU侧C口“有发光、无收光”的排查与恢复
运维·网络·信息与通信·tdd
浪客灿心3 小时前
Linux网络传输层协议
linux·运维·网络
V搜xhliang02463 小时前
OpenClaw科研全场景用法:从文献到实验室的完整自动化方案
运维·开发语言·人工智能·python·算法·microsoft·自动化
遇见火星4 小时前
Nginx限流配置:防止接口被刷,服务器稳如泰山
运维·服务器·nginx
计算机安禾4 小时前
【Linux从入门到精通】第49篇:服务器故障排查终极指南——思路决定出路
linux·运维·服务器
古月-一个C++方向的小白4 小时前
Linux——初识文件
linux·运维·服务器