9.5 KiB
生产一键部署脚本设计文档
1. 背景
当前仓库已经存在生产环境部署脚本 bin/prod/deploy_release.sh 和 Java 管理脚本 bin/prod/restart_java.sh。但这套脚本依赖固定的 /home/webapp 目录结构、独立启停脚本以及安装好的 Nginx,不符合本次“在脚本同目录直接完成发布”的目标。
本次需要设计一份新的生产一键部署脚本,直接放在发布目录内执行。该目录中同时存在:
- 部署脚本本身
- 1 个发布 zip
backend/目录frontend/目录
发布 zip 内固定包含 1 个后端 jar 和 1 个前端 dist.zip。脚本执行时需要完成旧版本备份、新版本替换、后端重启和前端解压部署。
2. 已确认约束
- 交付形态必须是单脚本,自包含,不拆分独立重启脚本
- Java 可执行路径直接写在脚本内常量中,不通过命令行参数或外部配置文件传入
- 发布包从脚本同目录读取
- 发布包内必须且只能包含 1 个后端
jar和 1 个前端dist.zip - 旧版后端
jar与旧版前端dist目录必须通过“原地重命名 + 时间戳”的方式保留 - 后端启动参数固定沿用当前生产约束:
--spring.profiles.active=pro --server.port=63310 - 不增加兼容性、补丁性、兜底性或回滚性方案
- 方案必须保持最短路径实现,并可完成全链路逻辑验证
3. 当前资产与现状
3.1 现有生产脚本
bin/prod/deploy_release.sh 已具备以下能力:
- 解压发布包
- 校验包内
jar和dist.zip - 备份旧版后端与前端
- 替换产物
- 调用独立 Java 管理脚本完成重启
但该脚本默认依赖 /home/webapp 固定目录、restart_java.sh 外部脚本和 Nginx 管理流程,超出了本次需求边界。
3.2 现有 Java 管理逻辑
- 使用 PID 文件记录后端进程
- 通过
-Dloan.pricing.home标记识别托管进程 - 停止时先
TERM再按需KILL - 启动后等待端口
63310监听成功
这部分逻辑可以作为新单脚本中的后端启停参考,但最终不再拆成第二个脚本文件。
4. 方案对比
方案一:单脚本自包含部署
做法:
- 新增一份单独的部署脚本
- 在脚本顶部写死
JAVA_BIN、端口、日志路径和目录约定 - 执行时自动读取脚本同目录发布包
- 将解包、备份、替换、启停全部内联到同一文件
优点:
- 与本次“一起写在一个脚本里”的目标完全一致
- 发布目录内即可直接执行,路径最短
- 不依赖独立重启脚本或外部配置文件
- 用户只需维护一个脚本文件
缺点:
- 后续如果要单独管理
start、stop、status,需要再扩展脚本
方案二:保留现有双脚本结构,只调整入口
做法:
- 保留部署脚本和重启脚本两份文件
- 让部署脚本在同目录发布模式下调用重启脚本
优点:
- 可复用现有结构,改动相对少
缺点:
- 不满足“写在一起”的明确要求
- 交付物仍有两个脚本,使用路径不够直接
方案三:极简覆盖式脚本
做法:
- 不维护 PID 文件
- 直接按文件名覆盖
- 使用宽泛的 Java 进程匹配方式停止旧进程
优点:
- 脚本最短
缺点:
- 容易误伤其他 Java 进程
- 状态不可控
- 不满足全链路可验证要求
5. 设计结论
采用方案一:单脚本自包含部署。
最终交付为 1 份新的生产一键部署脚本,负责在脚本同目录完成完整发布链路。脚本以当前仓库已有生产脚本为参考,但不保留 Nginx 管理、根目录安装和双脚本调用等超出本次范围的设计。
6. 脚本结构设计
6.1 目录约定
脚本执行目录固定为脚本所在目录。目录内约定如下:
deploy_release.sh或本次确定的新脚本文件- 1 个发布 zip
backend/frontend/
脚本不依赖仓库根目录运行,也不依赖外部工作目录传参。
6.2 脚本内固定配置
脚本顶部固定声明以下配置项:
JAVA_BINBACKEND_PORT=63310SPRING_PROFILE=proJAVA_OPTSBACKEND_PID_FILE=backend/backend.pidBACKEND_LOG_FILE=backend/backend-console.logBACKEND_JAR_TARGET=backend/ruoyi-admin.jarFRONTEND_DIST_DIR=frontend/distFRONTEND_DIST_ARCHIVE=frontend/dist.zip
其中 JAVA_BIN 由维护者直接修改脚本内常量,不再设计其他配置入口。
6.3 执行流程
脚本执行顺序固定如下:
- 定位脚本所在目录
- 校验
backend/与frontend/目录存在,不存在则直接失败 - 在脚本同目录查找唯一一个发布 zip
- 解压发布 zip 到临时目录
- 校验临时目录内必须且只能找到 1 个
jar和 1 个dist.zip - 将
backend/目录下现有jar重命名为带时间戳的备份文件 - 将
frontend/dist重命名为dist-时间戳 - 停止当前脚本托管的旧后端进程
- 将新
jar移入backend/ruoyi-admin.jar - 将新
dist.zip移入frontend/dist.zip - 删除当前
frontend/dist - 解压新
frontend/dist.zip到frontend/dist/ - 启动新的后端
jar - 等待端口
63310监听成功 - 输出部署完成信息
7. 后端启停设计
7.1 进程识别规则
为避免误杀机器上的其他 Java 进程,脚本只管理自己启动的后端实例。
识别规则如下:
- 启动时附加标记参数:
-Dloan.pricing.home=<脚本目录> - 优先读取
backend/backend.pid - 如果 PID 文件失效,则使用
pgrep -f按以下组合特征识别:-Dloan.pricing.home=<脚本目录>backend/ruoyi-admin.jar
只有同时满足托管标记和目标 jar 特征的进程,才允许被停止。
7.2 停止流程
停止逻辑如下:
- 收集当前托管进程 PID
- 如无托管进程,则清理失效 PID 文件并直接继续部署
- 对托管进程发送
TERM - 等待最多 30 秒
- 若仍存在残留进程,则发送
KILL - 删除
backend/backend.pid
7.3 启动流程
启动逻辑如下:
- 校验
JAVA_BIN可执行 - 校验
backend/ruoyi-admin.jar存在 - 使用
nohup后台启动 - 写入
backend/backend.pid - 日志输出到
backend/backend-console.log - 使用固定参数启动:
-Dloan.pricing.home=<脚本目录>--spring.profiles.active=pro--server.port=63310
- 轮询端口监听状态,最长等待 30 秒
8. 备份与替换设计
8.1 后端备份
如果 backend/ 目录中存在旧版 jar,则将其原地重命名为:
原文件名.YYYYMMDDHHMMSS.bak
不新增独立备份目录,避免引入额外结构。
8.2 前端备份
如果 frontend/dist 目录存在,则将其原地重命名为:
dist-YYYYMMDDHHMMSS
如果 frontend/dist.zip 已存在,则允许被新版本覆盖,不再为历史 dist.zip 单独追加备份规则。本次备份目标仅聚焦于用户明确提出的旧 jar 和旧前端 dist。
8.3 新产物替换
替换规则如下:
- 后端统一落到
backend/ruoyi-admin.jar - 前端压缩包统一落到
frontend/dist.zip - 前端静态资源统一解压到
frontend/dist/
该规则确保部署目录在每次发布后保持稳定结构,便于后续维护。
9. 失败处理设计
本次失败处理仅保留必要的强校验,不增加回滚或兼容分支。
以下场景直接失败退出:
- 脚本同目录下没有发布 zip
- 脚本同目录下存在多个发布 zip
- 解压后
jar数量不是 1 - 解压后
dist.zip数量不是 1 JAVA_BIN不可执行- 新
jar无法写入目标位置 dist.zip解压失败- 后端 30 秒内未监听
63310
脚本退出时需要清理临时解压目录,避免残留中间文件。
10. 交付文件设计
本次设计对应的交付物限定为以下内容:
- 1 个生产一键部署脚本
- 1 份设计文档
- 1 份实施记录
建议脚本路径为:
保留 bin/prod/deploy_release.sh 不动,可以避免影响现有 /home/webapp 部署方式;新需求使用独立脚本承载,边界更清晰。
11. 验证设计
本次验证只覆盖该单脚本的一键部署链路,必须包含以下检查:
- 执行
sh -n校验脚本语法 - 校验同目录只有 1 个发布 zip 时可继续执行
- 校验没有 zip 或存在多个 zip 时直接失败
- 校验发布包内必须正好有 1 个
jar和 1 个dist.zip - 校验旧
jar被改名为带时间戳备份文件 - 校验旧
frontend/dist被改名为带时间戳目录 - 校验新
jar最终位于backend/ruoyi-admin.jar - 校验新
dist.zip最终位于frontend/dist.zip - 校验前端资源成功解压到
frontend/dist/ - 校验后端进程成功启动并监听
63310 - 校验
backend/backend.pid和backend/backend-console.log被正确生成
12. 非目标
本次明确不包含以下内容:
- 不接入 Nginx 启停或重载
- 不处理 Java 安装
- 不生成独立的后端重启脚本
- 不增加回滚脚本
- 不新增命令行参数模式
- 不新增外部配置文件
- 不兼容多实例或多应用部署场景