feat: 添加自动化部署方案(Docker + 远程服务器两套方案)
- 新增 deploy/docker/:Docker 本机模拟部署,含 Dockerfile、docker-compose、deploy.sh 一键脚本 - 新增 deploy/remote/:远程服务器部署,含 SSH 自动上传、重启、回滚脚本 - 新增 deploy/README.md:完整使用手册,含现状分析、落地调整工作清单、命令速查 - 新增 build.sh/start.sh:本地构建和启动脚本(含飞书通知) - 新增前端 .env.docker 环境配置,API 指向测试服务器 - 前端 package.json 新增 build-docker 命令 - 更新 .gitignore:排除 IDE 配置、SQL 数据、Docker 敏感文件 - 前端 UI 样式优化(多个页面组件) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
403
deploy/README.md
Normal file
403
deploy/README.md
Normal file
@@ -0,0 +1,403 @@
|
||||
# SmartClean 自动化部署使用手册
|
||||
|
||||
## 概述
|
||||
|
||||
本项目提供两套独立的自动化部署方案,可同时使用、互不干扰:
|
||||
|
||||
| 方案 | 目录 | 适用场景 | 依赖 |
|
||||
|------|------|---------|------|
|
||||
| **远程服务器部署** | `deploy/remote/` | 部署到 182 测试/生产服务器 | SSH 免密登录 |
|
||||
| **Docker 本机模拟** | `deploy/docker/` | 本机模拟完整生产环境 | Docker Desktop |
|
||||
|
||||
---
|
||||
|
||||
## 现状分析
|
||||
|
||||
### 当前部署方式
|
||||
|
||||
| 环节 | 现状 | 问题 |
|
||||
|------|------|------|
|
||||
| **构建** | 本地执行 `build.sh`,手动触发 | 已自动化,含飞书通知 |
|
||||
| **上传** | 手动 SCP 或 FTP 上传到 182 服务器 | 无标准化流程,依赖个人操作习惯 |
|
||||
| **部署** | SSH 登录服务器,手动替换文件、重启服务 | 步骤多、易出错、无操作记录 |
|
||||
| **回滚** | 无备份机制,出问题需手动找旧版本 | 无法快速回滚,故障恢复时间长 |
|
||||
| **通知** | 构建结果有飞书通知,部署结果无通知 | 团队无法感知部署状态 |
|
||||
| **环境一致性** | 服务器环境手动搭建维护 | 本地与服务器环境可能不一致 |
|
||||
|
||||
### 现有脚本
|
||||
|
||||
| 脚本 | 用途 | 覆盖范围 |
|
||||
|------|------|---------|
|
||||
| `build.sh` | 本地构建(Maven + npm),支持分模块构建,含飞书通知 | 仅构建,不含部署 |
|
||||
| `start.sh` | 本地启动开发环境(mvn spring-boot:run + npm run dev) | 仅本地开发,非生产部署 |
|
||||
|
||||
### 现有流程 vs 新方案对比
|
||||
|
||||
```
|
||||
现有流程(5 步手动操作,约 10-15 分钟):
|
||||
┌──────────┐ 手动 ┌──────────┐ 手动 ┌──────────┐ 手动 ┌──────────┐
|
||||
│ build.sh │ ───────→ │ SCP 上传 │ ───────→ │ SSH 替换 │ ───────→ │ 手动重启 │
|
||||
│ 本地构建 │ │ 到服务器 │ │ 文件 │ │ 服务 │
|
||||
└──────────┘ └──────────┘ └──────────┘ └──────────┘
|
||||
✅ 已自动化 ❌ 手动 ❌ 手动 ❌ 手动
|
||||
✅ 有飞书通知 ❌ 无记录 ❌ 无备份 ❌ 无健康检查
|
||||
|
||||
方案一 — 远程部署(1 条命令,全自动):
|
||||
┌──────────────────────────────────────────────────────────────────────┐
|
||||
│ deploy/remote/deploy.sh web │
|
||||
│ 构建 → 备份 → 上传 → 重启 → 健康检查 → 飞书通知(失败自动回滚) │
|
||||
└──────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
方案二 — Docker 部署(1 条命令,全自动):
|
||||
┌──────────────────────────────────────────────────────────────────────┐
|
||||
│ deploy/docker/deploy.sh web │
|
||||
│ 镜像构建 → 容器替换 → 健康检查 → 飞书通知(失败自动回滚) │
|
||||
└──────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 新方案解决的问题
|
||||
|
||||
| 现状痛点 | 方案一(远程部署) | 方案二(Docker) |
|
||||
|----------|------------------|-----------------|
|
||||
| 手动上传、易传错 | SCP 自动传输,路径固定 | 不需要传输,镜像自包含 |
|
||||
| 无备份,无法回滚 | 每次部署自动备份,一键回滚 | 基于镜像 tag 回滚 |
|
||||
| 部署步骤多、易遗漏 | 一条命令完成全部步骤 | 一条命令完成全部步骤 |
|
||||
| 团队不知道谁部署了什么 | 飞书通知含版本/分支/操作人 | 飞书通知含版本/分支 |
|
||||
| 部署后不确认是否成功 | 自动健康检查,失败自动回滚 | 自动健康检查,失败自动回滚 |
|
||||
| 新人不知道怎么部署 | 看文档执行一条命令即可 | 一键启动完整环境 |
|
||||
|
||||
---
|
||||
|
||||
## 落地调整工作清单
|
||||
|
||||
### 方案一(远程部署)落地前需要做的事
|
||||
|
||||
#### 一次性准备工作
|
||||
|
||||
| # | 任务 | 说明 | 负责人 | 耗时预估 |
|
||||
|---|------|------|--------|---------|
|
||||
| 1 | **配置 SSH 免密登录** | 本机生成密钥,`ssh-copy-id` 到 182 服务器 | 开发者 | 5 分钟 |
|
||||
| 2 | **确认服务器目录结构** | 登录 182 确认 Tomcat 实际安装路径、Nginx 配置路径、Task JAR 存放路径 | 开发者 | 10 分钟 |
|
||||
| 3 | **修改 config.sh** | 将 `TOMCAT_HOME`、`NGINX_HTML` 等路径改为服务器实际路径 | 开发者 | 5 分钟 |
|
||||
| 4 | **执行 setup 初始化** | `deploy/remote/deploy.sh setup` 创建标准目录 + 上传重启脚本 | 开发者 | 2 分钟 |
|
||||
| 5 | **调整重启脚本** | 根据服务器实际情况微调 `restart-web.sh` / `restart-task.sh`(如 Tomcat 启停方式、Task 服务的 JVM 参数) | 开发者 | 15 分钟 |
|
||||
| 6 | **首次全量部署测试** | 执行 `deploy/remote/deploy.sh` 验证全流程跑通 | 开发者 | 10 分钟 |
|
||||
|
||||
#### 需确认的服务器信息
|
||||
|
||||
在落地之前,请先 SSH 到 182 服务器确认以下信息,并更新到 `config.sh`:
|
||||
|
||||
```bash
|
||||
# 登录服务器后执行以下命令,记录输出
|
||||
|
||||
# 1. Tomcat 安装路径
|
||||
find / -name "catalina.sh" -type f 2>/dev/null
|
||||
# 将结果的父目录的父目录填入 TOMCAT_HOME
|
||||
|
||||
# 2. Nginx 前端文件路径
|
||||
nginx -T 2>/dev/null | grep "root "
|
||||
# 将 root 路径填入 NGINX_HTML
|
||||
|
||||
# 3. Task 服务当前运行方式
|
||||
ps -ef | grep "intellectual-task"
|
||||
# 确认 JAR 名称、启动参数,更新 TASK_JAR_NAME 和 TASK_JVM_OPTS
|
||||
|
||||
# 4. 当前 WAR 包位置
|
||||
find / -name "ROOT.war" -type f 2>/dev/null
|
||||
|
||||
# 5. Java 版本
|
||||
java -version
|
||||
```
|
||||
|
||||
### 方案二(Docker 本机模拟)落地前需要做的事
|
||||
|
||||
| # | 任务 | 说明 | 负责人 | 耗时预估 |
|
||||
|---|------|------|--------|---------|
|
||||
| 1 | **安装 Docker Desktop** | 如未安装,从官网下载安装 | 开发者 | 10 分钟 |
|
||||
| 2 | **确认端口无冲突** | 确保 8180/18095/18097/3307/6380 未被占用,如有冲突在 `.env` 中调整 | 开发者 | 2 分钟 |
|
||||
| 3 | **检查 SQL 初始化脚本** | 确认 `sql/` 目录下有完整的建库建表 SQL(Docker MySQL 首次启动会自动导入) | 开发者 | 5 分钟 |
|
||||
| 4 | **首次全量部署测试** | 执行 `deploy/docker/deploy.sh`,首次需下载基础镜像 + 编译,耗时较长 | 开发者 | 20-30 分钟 |
|
||||
| 5 | **验证前端 API 代理** | 确认 Nginx 的 `/api/` 反代规则与前端实际请求路径匹配(当前前端直接请求后端,无 `/api` 前缀,可能需要调整 `nginx.conf`) | 开发者 | 10 分钟 |
|
||||
|
||||
#### 可能需要的代码调整
|
||||
|
||||
| 调整项 | 原因 | 影响范围 |
|
||||
|--------|------|---------|
|
||||
| **前端 .env.docker**(可选) | Docker 环境中前端通过 Nginx 反代访问后端,API 地址可能需要调整 | 新增一个 `.env.docker` 文件 |
|
||||
| **nginx.conf 反代路径** | 当前前端直接调用后端接口(无 `/api` 前缀),需确认 Nginx `location /api/` 的 rewrite 规则与前端请求路径一致 | `deploy/docker/conf/nginx.conf` |
|
||||
| **application-docker.yml 补全** | 当前只覆盖了数据源和 Redis,如果后端有其他外部依赖(如 OSS、短信等),需补充配置或 mock | `deploy/docker/conf/application-docker.yml` |
|
||||
|
||||
---
|
||||
|
||||
## 方案一:远程服务器部署(无 Docker)
|
||||
|
||||
> 本地构建 → SCP 上传 → 远程重启 → 健康检查 → 失败自动回滚 → 飞书通知
|
||||
|
||||
### 前置条件
|
||||
|
||||
1. 本机已安装 Java 8、Maven、Node.js 16+
|
||||
2. SSH 免密登录到目标服务器
|
||||
|
||||
```bash
|
||||
# 配置 SSH 免密(一次性)
|
||||
ssh-keygen -t ed25519
|
||||
ssh-copy-id root@192.168.1.182
|
||||
|
||||
# 验证
|
||||
ssh root@192.168.1.182 "echo ok"
|
||||
```
|
||||
|
||||
### 首次使用
|
||||
|
||||
```bash
|
||||
# 1. 根据实际环境修改配置
|
||||
vi deploy/remote/config.sh
|
||||
|
||||
# 2. 初始化服务器目录结构 + 上传管理脚本
|
||||
deploy/remote/deploy.sh setup
|
||||
```
|
||||
|
||||
### 日常使用
|
||||
|
||||
```bash
|
||||
# ===== 部署 =====
|
||||
|
||||
# 全量部署(前端 + 后端全部)
|
||||
deploy/remote/deploy.sh
|
||||
|
||||
# 只改了后端 Web 代码
|
||||
deploy/remote/deploy.sh web
|
||||
|
||||
# 只改了 Task 服务代码
|
||||
deploy/remote/deploy.sh task
|
||||
|
||||
# 后端都改了
|
||||
deploy/remote/deploy.sh backend
|
||||
|
||||
# 只改了前端(生产包)
|
||||
deploy/remote/deploy.sh front
|
||||
|
||||
# 前端测试环境包
|
||||
deploy/remote/deploy.sh front-test
|
||||
|
||||
# ===== 回滚 =====
|
||||
|
||||
# 回滚到上一版本
|
||||
deploy/remote/deploy.sh rollback
|
||||
# 或
|
||||
deploy/remote/rollback.sh
|
||||
|
||||
# ===== 状态查看 =====
|
||||
|
||||
# 查看服务器服务状态
|
||||
deploy/remote/deploy.sh status
|
||||
```
|
||||
|
||||
### 配置说明
|
||||
|
||||
编辑 `deploy/remote/config.sh`:
|
||||
|
||||
```bash
|
||||
# 服务器地址(根据实际修改)
|
||||
DEPLOY_HOST="192.168.1.182"
|
||||
DEPLOY_USER="root"
|
||||
|
||||
# Tomcat 路径(根据服务器实际路径修改)
|
||||
TOMCAT_HOME="/opt/smartclean/web/tomcat"
|
||||
|
||||
# 备份保留数量
|
||||
MAX_BACKUPS=5
|
||||
|
||||
# 健康检查重试次数和间隔
|
||||
HEALTHCHECK_RETRIES=20
|
||||
HEALTHCHECK_INTERVAL=5
|
||||
```
|
||||
|
||||
### 部署流程
|
||||
|
||||
```
|
||||
1. 本地构建 → 调用 build.sh 生成 ROOT.war / task.jar / dist/
|
||||
2. 远程备份 → SSH 备份服务器当前版本到 backups/时间戳-hash/
|
||||
3. 上传产物 → SCP 传输到服务器对应目录
|
||||
4. 远程重启 → SSH 执行 restart-web.sh / restart-task.sh / restart-front.sh
|
||||
5. 健康检查 → 轮询接口,最多重试 20 次(每次间隔 5s)
|
||||
6. 结果通知 → 成功/失败/回滚 均推送飞书群
|
||||
```
|
||||
|
||||
### 服务器目录结构
|
||||
|
||||
```
|
||||
/opt/smartclean/
|
||||
├── web/tomcat/webapps/ROOT.war # Web 服务
|
||||
├── task/task.jar # Task 服务
|
||||
├── front/dist/ # 前端静态文件
|
||||
├── backups/ # 版本备份(自动保留最近 5 个)
|
||||
│ ├── 20260415-153000-a1b2c3d/
|
||||
│ └── 20260415-140000-d4e5f6a/
|
||||
└── scripts/ # 服务管理脚本
|
||||
├── restart-web.sh
|
||||
├── restart-task.sh
|
||||
└── restart-front.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 方案二:Docker 本机模拟
|
||||
|
||||
> Docker 镜像构建 → Compose 部署 → 健康检查 → 失败自动回滚 → 飞书通知
|
||||
|
||||
### 前置条件
|
||||
|
||||
1. 已安装 Docker Desktop 并启动
|
||||
|
||||
```bash
|
||||
# 验证
|
||||
docker --version
|
||||
docker compose version
|
||||
```
|
||||
|
||||
### 首次使用
|
||||
|
||||
```bash
|
||||
# 直接一键部署(首次会自动拉取基础镜像 + 构建 + 启动)
|
||||
deploy/docker/deploy.sh
|
||||
```
|
||||
|
||||
### 日常使用
|
||||
|
||||
```bash
|
||||
# ===== 部署 =====
|
||||
|
||||
# 全量部署
|
||||
deploy/docker/deploy.sh
|
||||
|
||||
# 只改了后端 Web 代码
|
||||
deploy/docker/deploy.sh web
|
||||
|
||||
# 只改了 Task 服务代码
|
||||
deploy/docker/deploy.sh task
|
||||
|
||||
# 只改了前端
|
||||
deploy/docker/deploy.sh front
|
||||
|
||||
# ===== 回滚 =====
|
||||
|
||||
# 回滚到上一版本(基于镜像 tag)
|
||||
deploy/docker/deploy.sh rollback
|
||||
# 或
|
||||
deploy/docker/rollback.sh
|
||||
|
||||
# ===== 运维 =====
|
||||
|
||||
# 查看容器状态
|
||||
deploy/docker/deploy.sh status
|
||||
|
||||
# 查看所有服务日志
|
||||
deploy/docker/deploy.sh logs
|
||||
|
||||
# 只看 Web 服务日志
|
||||
deploy/docker/deploy.sh logs web
|
||||
|
||||
# 停止所有容器(数据保留)
|
||||
deploy/docker/deploy.sh stop
|
||||
|
||||
# 停止并清理数据卷(慎用,会丢数据库数据)
|
||||
deploy/docker/deploy.sh clean
|
||||
```
|
||||
|
||||
### 端口映射
|
||||
|
||||
| 服务 | 容器内端口 | 宿主机端口 | 访问地址 |
|
||||
|------|-----------|-----------|---------|
|
||||
| 前端 (Nginx) | 80 | **8180** | http://localhost:8180 |
|
||||
| Web 后端 | 8095 | **18095** | http://localhost:18095 |
|
||||
| Task 后端 | 8097 | **18097** | http://localhost:18097 |
|
||||
| MySQL | 3306 | **3307** | localhost:3307 |
|
||||
| Redis | 6379 | **6380** | localhost:6380 |
|
||||
|
||||
> 端口可在 `deploy/docker/.env` 中自定义修改。
|
||||
|
||||
### 端口隔离说明
|
||||
|
||||
Docker 环境与本机开发环境完全独立:
|
||||
|
||||
```
|
||||
本机开发环境 Docker 模拟环境
|
||||
────────────── ──────────────
|
||||
前端 localhost:8079 前端 localhost:8180
|
||||
Web localhost:8095 Web localhost:18095
|
||||
MySQL localhost:3306 MySQL localhost:3307
|
||||
Redis localhost:6379 Redis localhost:6380
|
||||
```
|
||||
|
||||
两套可以同时运行,互不干扰。
|
||||
|
||||
### 连接 Docker 中的数据库调试
|
||||
|
||||
```bash
|
||||
# 用本机 MySQL 客户端连接 Docker 中的 MySQL
|
||||
mysql -h127.0.0.1 -P3307 -uroot -pkaixinjiuhao
|
||||
|
||||
# 用本机 Redis 客户端连接 Docker 中的 Redis
|
||||
redis-cli -h 127.0.0.1 -p 6380 -a kaixinjiuhao
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 两套方案对比
|
||||
|
||||
| 维度 | 远程服务器部署 | Docker 本机模拟 |
|
||||
|------|--------------|----------------|
|
||||
| **部署目标** | 192.168.1.182 远程服务器 | 本机 Docker 容器 |
|
||||
| **依赖** | SSH 免密登录 | Docker Desktop |
|
||||
| **构建方式** | 本机 mvn/npm 构建,上传产物 | Docker 多阶段构建(镜像内编译) |
|
||||
| **部署速度** | 快(只传几十 MB 产物) | 慢(首次构建镜像,后续有缓存) |
|
||||
| **环境一致性** | 依赖服务器已有环境 | 镜像自包含,完全一致 |
|
||||
| **回滚方式** | 文件级(还原备份的 WAR/JAR/dist) | 镜像级(切换 Docker 镜像 tag) |
|
||||
| **数据库** | 使用服务器上的 MySQL | 独立 MySQL 容器(数据隔离) |
|
||||
| **适合场景** | 日常发布到测试/生产 | 本机验证部署流程、新人搭环境 |
|
||||
|
||||
## 命令速查表
|
||||
|
||||
```bash
|
||||
# ==================== 远程部署 ====================
|
||||
deploy/remote/deploy.sh # 全量部署到远程服务器
|
||||
deploy/remote/deploy.sh web # 只部署 Web
|
||||
deploy/remote/deploy.sh task # 只部署 Task
|
||||
deploy/remote/deploy.sh front # 只部署前端
|
||||
deploy/remote/deploy.sh backend # 部署后端(web + task)
|
||||
deploy/remote/deploy.sh rollback # 回滚
|
||||
deploy/remote/deploy.sh status # 查看服务器状态
|
||||
deploy/remote/deploy.sh setup # 首次初始化服务器
|
||||
|
||||
# ==================== Docker 部署 ====================
|
||||
deploy/docker/deploy.sh # 全量部署到 Docker
|
||||
deploy/docker/deploy.sh web # 只部署 Web
|
||||
deploy/docker/deploy.sh task # 只部署 Task
|
||||
deploy/docker/deploy.sh front # 只部署前端
|
||||
deploy/docker/deploy.sh rollback # 回滚
|
||||
deploy/docker/deploy.sh status # 查看容器状态
|
||||
deploy/docker/deploy.sh logs [服务] # 查看日志
|
||||
deploy/docker/deploy.sh stop # 停止容器
|
||||
deploy/docker/deploy.sh clean # 停止并清理数据
|
||||
```
|
||||
|
||||
## 飞书通知
|
||||
|
||||
两套方案都集成了飞书 Webhook 通知,部署结果会自动推送到群里:
|
||||
|
||||
- ✅ **部署成功**:版本号、分支、提交信息、耗时
|
||||
- ❌ **部署失败**:自动回滚后通知,附失败原因
|
||||
- ⚠️ **手动回滚**:回滚版本号、操作人
|
||||
|
||||
Webhook 地址在各自的配置文件中修改:
|
||||
- 远程版:`deploy/remote/config.sh` → `FEISHU_WEBHOOK`
|
||||
- Docker 版:`deploy/docker/.env` → `FEISHU_WEBHOOK`
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **deploy/docker/.env 不要提交到 git**(含密码),已在 .gitignore 中排除
|
||||
2. **首次 Docker 构建较慢**(需下载基础镜像 + Maven 依赖),后续有缓存会快很多
|
||||
3. **远程部署前确认 config.sh 中的路径**与服务器实际一致,特别是 `TOMCAT_HOME`
|
||||
4. **回滚只保留最近 5 个版本**,超出自动清理(可在配置中调整 `MAX_BACKUPS`)
|
||||
5. **Docker 版 Task 服务**可能因缺少 MQTT/XXL-Job 而启动异常,这是正常的,不影响 Web 和前端
|
||||
4
deploy/docker/Dockerfile.front
Normal file
4
deploy/docker/Dockerfile.front
Normal file
@@ -0,0 +1,4 @@
|
||||
FROM nginx:1.24-alpine
|
||||
RUN rm -rf /usr/share/nginx/html/*
|
||||
COPY frontend/witcleansystem/dist /usr/share/nginx/html
|
||||
EXPOSE 80
|
||||
15
deploy/docker/Dockerfile.task
Normal file
15
deploy/docker/Dockerfile.task
Normal file
@@ -0,0 +1,15 @@
|
||||
FROM maven:3.8-openjdk-8 AS builder
|
||||
WORKDIR /src
|
||||
COPY backend/xiaoqu-intellectual-public/ xiaoqu-intellectual-public/
|
||||
COPY backend/xiaoqu-intellectual-task/ xiaoqu-intellectual-task/
|
||||
RUN cd xiaoqu-intellectual-public && mvn clean install -q -DskipTests \
|
||||
&& cd ../xiaoqu-intellectual-task && mvn clean package -q -DskipTests
|
||||
|
||||
FROM openjdk:8-jre-slim
|
||||
WORKDIR /app
|
||||
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* \
|
||||
&& mkdir -p /app/config /app/logs
|
||||
COPY --from=builder /src/xiaoqu-intellectual-task/target/*.jar app.jar
|
||||
EXPOSE 8097
|
||||
ENTRYPOINT ["java", "-jar", "app.jar", \
|
||||
"--spring.config.additional-location=/app/config/"]
|
||||
7
deploy/docker/Dockerfile.web
Normal file
7
deploy/docker/Dockerfile.web
Normal file
@@ -0,0 +1,7 @@
|
||||
FROM tomcat:8.5-jdk8-temurin
|
||||
RUN rm -rf /usr/local/tomcat/webapps/* \
|
||||
&& mkdir -p /app/config /app/logs \
|
||||
&& apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
|
||||
COPY backend/xiaoqu-intellectual-web/target/ROOT.war /usr/local/tomcat/webapps/
|
||||
ENV CATALINA_OPTS="-Dspring.config.additional-location=/app/config/ -Dspring.profiles.active=test,docker"
|
||||
EXPOSE 8080
|
||||
35
deploy/docker/conf/application-docker.yml
Normal file
35
deploy/docker/conf/application-docker.yml
Normal file
@@ -0,0 +1,35 @@
|
||||
server:
|
||||
port: 8095
|
||||
|
||||
redis:
|
||||
host: 100.93.0.28
|
||||
port: 6379
|
||||
password: kaixinjiuhao
|
||||
timeout: 30000
|
||||
pool:
|
||||
max-total: 200
|
||||
max-wait: -1
|
||||
max-idle: 8
|
||||
min-idle: 1
|
||||
timeout: 30000
|
||||
|
||||
spring:
|
||||
datasource:
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
db1:
|
||||
url: jdbc:mysql://100.93.0.28:3306/xiaoqu_comples_d?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&allowMultiQueries=true&allowPublicKeyRetrieval=true
|
||||
username: root
|
||||
password: kaixinjiuhao
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
db2:
|
||||
url: jdbc:mysql://100.93.0.28:3306/xiaoqu_intellectual_d?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&allowMultiQueries=true&allowPublicKeyRetrieval=true
|
||||
username: root
|
||||
password: kaixinjiuhao
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
|
||||
xxl:
|
||||
job:
|
||||
admin:
|
||||
addresses: ""
|
||||
executor:
|
||||
appname: xiaoqu-intellectual-task
|
||||
35
deploy/docker/conf/application-task-docker.yml
Normal file
35
deploy/docker/conf/application-task-docker.yml
Normal file
@@ -0,0 +1,35 @@
|
||||
server:
|
||||
port: 8097
|
||||
|
||||
redis:
|
||||
host: host.docker.internal
|
||||
port: 6379
|
||||
password: kaixinjiuhao
|
||||
|
||||
spring:
|
||||
mqtt:
|
||||
username: intellectual
|
||||
password: xiaoqu2022
|
||||
host-url: tcp://mqtt:1883
|
||||
client-id: xiaoqu-intellectual-task-docker
|
||||
timeout: 1000
|
||||
keepalive: 100
|
||||
datasource:
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
db1:
|
||||
url: jdbc:mysql://host.docker.internal:3306/xiaoqu_comples_d?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&allowMultiQueries=true&allowPublicKeyRetrieval=true
|
||||
username: root
|
||||
password: kaixinjiuhao
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
db2:
|
||||
url: jdbc:mysql://host.docker.internal:3306/xiaoqu_intellectual_d?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&allowMultiQueries=true&allowPublicKeyRetrieval=true
|
||||
username: root
|
||||
password: kaixinjiuhao
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
|
||||
xxl:
|
||||
job:
|
||||
admin:
|
||||
addresses: ""
|
||||
executor:
|
||||
appname: xiaoqu-intellectual-task
|
||||
28
deploy/docker/conf/nginx.conf
Normal file
28
deploy/docker/conf/nginx.conf
Normal file
@@ -0,0 +1,28 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
|
||||
# 静态资源缓存
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?|map)$ {
|
||||
root /usr/share/nginx/html;
|
||||
expires 7d;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# 前端 SPA — 静态文件存在则返回,不存在则转发到后端
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
try_files $uri $uri/ @backend;
|
||||
}
|
||||
|
||||
# 后端接口反代到本机 Docker 内的 Web 容器
|
||||
location @backend {
|
||||
proxy_pass http://web:8080;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_read_timeout 120s;
|
||||
}
|
||||
}
|
||||
355
deploy/docker/deploy.sh
Executable file
355
deploy/docker/deploy.sh
Executable file
@@ -0,0 +1,355 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# SmartClean 一键部署脚本(Docker 版 — 本机模拟)
|
||||
#
|
||||
# 用法:
|
||||
# ./deploy.sh # 构建并部署所有服务
|
||||
# ./deploy.sh web # 仅重建部署 Web 服务
|
||||
# ./deploy.sh task # 仅重建部署 Task 服务
|
||||
# ./deploy.sh front # 仅重建部署前端
|
||||
# ./deploy.sh rollback # 回滚到上一版本
|
||||
# ./deploy.sh status # 查看容器状态
|
||||
# ./deploy.sh logs [服务名] # 查看日志
|
||||
# ./deploy.sh stop # 停止所有容器
|
||||
# ./deploy.sh clean # 停止并清理(含数据卷)
|
||||
|
||||
set -e
|
||||
|
||||
DEPLOY_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
ROOT_DIR="$(dirname "$(dirname "$DEPLOY_DIR")")"
|
||||
source "$DEPLOY_DIR/.env"
|
||||
|
||||
# ===== 版本号 =====
|
||||
GIT_HASH=$(cd "$ROOT_DIR" && git rev-parse --short HEAD)
|
||||
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
|
||||
VERSION="${TIMESTAMP}-${GIT_HASH}"
|
||||
BRANCH=$(cd "$ROOT_DIR" && git rev-parse --abbrev-ref HEAD)
|
||||
COMMIT=$(cd "$ROOT_DIR" && git log -1 --format='%h %s')
|
||||
|
||||
BACKUP_FILE="$DEPLOY_DIR/.last-version"
|
||||
CURRENT_FILE="$DEPLOY_DIR/.current-version"
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
CYAN='\033[0;36m'
|
||||
NC='\033[0m'
|
||||
|
||||
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
|
||||
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||||
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||||
log_step() { echo -e "${CYAN}[STEP]${NC} $1"; }
|
||||
|
||||
DC="docker compose -f $DEPLOY_DIR/docker-compose.yml"
|
||||
|
||||
# ===== 飞书通知 =====
|
||||
notify_feishu() {
|
||||
local title="$1" content="$2" color="$3"
|
||||
curl -s -X POST "$FEISHU_WEBHOOK" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"msg_type\": \"interactive\",
|
||||
\"card\": {
|
||||
\"header\": {\"title\":{\"tag\":\"plain_text\",\"content\":\"$title\"},\"template\":\"$color\"},
|
||||
\"elements\": [{\"tag\":\"markdown\",\"content\":\"$content\"}]
|
||||
}
|
||||
}" > /dev/null 2>&1
|
||||
}
|
||||
|
||||
# ===== 检查 Docker =====
|
||||
check_docker() {
|
||||
if ! command -v docker &> /dev/null; then
|
||||
log_error "Docker 未安装,请先安装 Docker Desktop"
|
||||
exit 1
|
||||
fi
|
||||
if ! docker info > /dev/null 2>&1; then
|
||||
log_error "Docker 未启动,请先启动 Docker Desktop"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# ===== 备份当前版本号 =====
|
||||
backup_version() {
|
||||
if [ -f "$CURRENT_FILE" ]; then
|
||||
cp "$CURRENT_FILE" "$BACKUP_FILE"
|
||||
log_info "已备份当前版本: $(cat "$BACKUP_FILE")"
|
||||
fi
|
||||
}
|
||||
|
||||
# ===== 本地构建产物 =====
|
||||
build_local() {
|
||||
local target="${1:-all}"
|
||||
local start_time=$(date +%s)
|
||||
|
||||
cd "$ROOT_DIR"
|
||||
|
||||
case "$target" in
|
||||
web)
|
||||
log_step "本地构建 Web 服务..."
|
||||
bash build.sh web
|
||||
;;
|
||||
task)
|
||||
log_step "本地构建 Task 服务..."
|
||||
bash build.sh task
|
||||
;;
|
||||
front)
|
||||
log_step "本地构建前端 (docker 模式)..."
|
||||
cd "$ROOT_DIR/frontend/witcleansystem"
|
||||
npm run build-docker
|
||||
;;
|
||||
all)
|
||||
log_step "本地构建全部..."
|
||||
bash build.sh backend
|
||||
cd "$ROOT_DIR/frontend/witcleansystem"
|
||||
npm run build-docker
|
||||
;;
|
||||
esac
|
||||
|
||||
local elapsed=$(( $(date +%s) - start_time ))
|
||||
log_info "本地构建完成 (${elapsed}s)"
|
||||
}
|
||||
|
||||
# ===== 打包 Docker 镜像 =====
|
||||
build_images() {
|
||||
local target="${1:-all}"
|
||||
local start_time=$(date +%s)
|
||||
|
||||
cd "$DEPLOY_DIR"
|
||||
|
||||
case "$target" in
|
||||
web)
|
||||
log_step "打包 Web 镜像 ($VERSION)..."
|
||||
$DC build --no-cache web
|
||||
docker tag smartclean-web:latest smartclean-web:$VERSION 2>/dev/null || true
|
||||
;;
|
||||
task)
|
||||
log_step "打包 Task 镜像 ($VERSION)..."
|
||||
$DC build --no-cache task
|
||||
docker tag smartclean-task:latest smartclean-task:$VERSION 2>/dev/null || true
|
||||
;;
|
||||
front)
|
||||
log_step "打包前端镜像 ($VERSION)..."
|
||||
$DC build --no-cache frontend
|
||||
docker tag smartclean-front:latest smartclean-front:$VERSION 2>/dev/null || true
|
||||
;;
|
||||
all)
|
||||
log_step "打包全部镜像 ($VERSION)..."
|
||||
$DC build --no-cache web frontend
|
||||
docker tag smartclean-web:latest smartclean-web:$VERSION 2>/dev/null || true
|
||||
docker tag smartclean-front:latest smartclean-front:$VERSION 2>/dev/null || true
|
||||
;;
|
||||
esac
|
||||
|
||||
local elapsed=$(( $(date +%s) - start_time ))
|
||||
log_info "镜像打包完成 (${elapsed}s)"
|
||||
}
|
||||
|
||||
# ===== 部署服务 =====
|
||||
deploy_services() {
|
||||
local target="${1:-all}"
|
||||
|
||||
cd "$DEPLOY_DIR"
|
||||
|
||||
log_step "部署应用服务..."
|
||||
case "$target" in
|
||||
web)
|
||||
$DC down 2>/dev/null || true
|
||||
$DC up -d web frontend
|
||||
;;
|
||||
task)
|
||||
$DC up -d --no-deps task
|
||||
;;
|
||||
front)
|
||||
$DC down 2>/dev/null || true
|
||||
$DC up -d web frontend
|
||||
;;
|
||||
all)
|
||||
$DC down 2>/dev/null || true
|
||||
$DC up -d web frontend
|
||||
;;
|
||||
esac
|
||||
|
||||
log_info "容器已启动"
|
||||
}
|
||||
|
||||
# ===== 健康检查 =====
|
||||
healthcheck() {
|
||||
local target="${1:-all}"
|
||||
local max_retries=30
|
||||
local interval=3
|
||||
|
||||
log_step "健康检查..."
|
||||
|
||||
# Web 服务
|
||||
if [ "$target" = "all" ] || [ "$target" = "web" ]; then
|
||||
log_info " 检查 Web 服务 (http://localhost:$WEB_PORT)..."
|
||||
for i in $(seq 1 $max_retries); do
|
||||
if curl -sf -X POST "http://localhost:$WEB_PORT/dropDown/districtTree" > /dev/null 2>&1; then
|
||||
log_info " Web 服务健康 (第${i}次检查通过)"
|
||||
break
|
||||
fi
|
||||
if [ $i -eq $max_retries ]; then
|
||||
log_error " Web 服务健康检查失败"
|
||||
log_error " 查看日志: $DC logs web"
|
||||
return 1
|
||||
fi
|
||||
printf "."
|
||||
sleep $interval
|
||||
done
|
||||
fi
|
||||
|
||||
# 前端
|
||||
if [ "$target" = "all" ] || [ "$target" = "front" ]; then
|
||||
log_info " 检查前端服务 (http://localhost:$FRONT_PORT)..."
|
||||
for i in $(seq 1 15); do
|
||||
if curl -sf "http://localhost:$FRONT_PORT/" > /dev/null 2>&1; then
|
||||
log_info " 前端服务健康 (第${i}次检查通过)"
|
||||
break
|
||||
fi
|
||||
if [ $i -eq 15 ]; then
|
||||
log_error " 前端服务健康检查失败"
|
||||
return 1
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
fi
|
||||
|
||||
log_info "健康检查通过"
|
||||
return 0
|
||||
}
|
||||
|
||||
# ===== 回滚 =====
|
||||
rollback() {
|
||||
if [ ! -f "$BACKUP_FILE" ]; then
|
||||
log_error "没有可回滚的版本"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local old_version=$(cat "$BACKUP_FILE")
|
||||
log_warn "回滚到版本: $old_version"
|
||||
|
||||
local has_images=true
|
||||
docker image inspect smartclean-web:$old_version > /dev/null 2>&1 || has_images=false
|
||||
docker image inspect smartclean-front:$old_version > /dev/null 2>&1 || has_images=false
|
||||
|
||||
if [ "$has_images" = false ]; then
|
||||
log_error "旧版本镜像不存在 ($old_version),无法回滚"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export VERSION="$old_version"
|
||||
cd "$DEPLOY_DIR"
|
||||
$DC down 2>/dev/null || true
|
||||
$DC up -d web frontend
|
||||
|
||||
echo "$old_version" > "$CURRENT_FILE"
|
||||
log_info "回滚完成"
|
||||
|
||||
notify_feishu "⚠️ SmartClean 已回滚 (Docker)" \
|
||||
"**回滚版本:** $old_version\\n**触发原因:** 健康检查失败" \
|
||||
"yellow"
|
||||
}
|
||||
|
||||
# ===== 清理旧镜像 =====
|
||||
cleanup_images() {
|
||||
log_info "清理旧镜像(保留最近 5 个版本)..."
|
||||
for name in smartclean-web smartclean-task smartclean-front; do
|
||||
docker images "$name" --format "{{.Tag}}" | grep -v "latest" | sort -r | tail -n +6 | while read tag; do
|
||||
docker rmi "$name:$tag" 2>/dev/null && echo " 删除 $name:$tag"
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
# ===== 主流程 =====
|
||||
TARGET="${1:-all}"
|
||||
DEPLOY_START=$(date +%s)
|
||||
|
||||
case "$TARGET" in
|
||||
status)
|
||||
$DC ps
|
||||
exit 0
|
||||
;;
|
||||
logs)
|
||||
shift
|
||||
$DC logs -f $@
|
||||
exit 0
|
||||
;;
|
||||
stop)
|
||||
log_info "停止所有容器..."
|
||||
$DC down
|
||||
log_info "已停止"
|
||||
exit 0
|
||||
;;
|
||||
clean)
|
||||
log_warn "停止所有容器并清理数据卷..."
|
||||
$DC down -v --rmi all
|
||||
log_info "已清理"
|
||||
exit 0
|
||||
;;
|
||||
rollback)
|
||||
check_docker
|
||||
rollback
|
||||
exit 0
|
||||
;;
|
||||
all|web|task|front)
|
||||
;;
|
||||
*)
|
||||
echo "用法: $0 {all|web|task|front|rollback|status|logs|stop|clean}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo ""
|
||||
log_info "======================================"
|
||||
log_info " SmartClean 自动化部署 (Docker)"
|
||||
log_info " 版本: $VERSION"
|
||||
log_info " 分支: $BRANCH"
|
||||
log_info " 提交: $COMMIT"
|
||||
log_info " 目标: $TARGET"
|
||||
log_info "======================================"
|
||||
echo ""
|
||||
|
||||
# 1. 检查 Docker
|
||||
check_docker
|
||||
|
||||
# 2. 备份当前版本号
|
||||
backup_version
|
||||
|
||||
# 3. 本地构建产物(Maven + npm)
|
||||
build_local "$TARGET"
|
||||
|
||||
# 4. 打包 Docker 镜像(COPY 本地产物)
|
||||
build_images "$TARGET"
|
||||
|
||||
# 5. 部署容器
|
||||
deploy_services "$TARGET"
|
||||
|
||||
# 6. 健康检查
|
||||
if healthcheck "$TARGET"; then
|
||||
echo "$VERSION" > "$CURRENT_FILE"
|
||||
cleanup_images
|
||||
|
||||
ELAPSED=$(( $(date +%s) - DEPLOY_START ))
|
||||
|
||||
echo ""
|
||||
log_info "======================================"
|
||||
log_info " ✅ 部署成功!"
|
||||
log_info " 版本: $VERSION"
|
||||
log_info " 耗时: ${ELAPSED}s"
|
||||
log_info " 前端: http://localhost:$FRONT_PORT"
|
||||
log_info " Web: http://localhost:$WEB_PORT"
|
||||
log_info "======================================"
|
||||
|
||||
notify_feishu "✅ SmartClean 部署成功 (Docker)" \
|
||||
"**版本:** $VERSION\\n**分支:** $BRANCH\\n**提交:** $COMMIT\\n**目标:** $TARGET\\n**耗时:** ${ELAPSED}s\\n**前端:** http://localhost:$FRONT_PORT\\n**Web:** http://localhost:$WEB_PORT" \
|
||||
"green"
|
||||
else
|
||||
log_error "健康检查失败,自动回滚..."
|
||||
rollback
|
||||
|
||||
ELAPSED=$(( $(date +%s) - DEPLOY_START ))
|
||||
notify_feishu "❌ SmartClean 部署失败 (Docker,已回滚)" \
|
||||
"**版本:** $VERSION\\n**分支:** $BRANCH\\n**提交:** $COMMIT\\n**耗时:** ${ELAPSED}s\\n**状态:** 健康检查失败,已自动回滚" \
|
||||
"red"
|
||||
exit 1
|
||||
fi
|
||||
110
deploy/docker/docker-compose.yml
Normal file
110
deploy/docker/docker-compose.yml
Normal file
@@ -0,0 +1,110 @@
|
||||
services:
|
||||
# ==================== 基础设施(可选,默认使用宿主机 MySQL/Redis)====================
|
||||
# 如需独立数据库,取消注释以下 mysql 和 redis 服务
|
||||
# mysql:
|
||||
# image: mysql:5.7
|
||||
# platform: linux/amd64
|
||||
# container_name: smartclean-mysql
|
||||
# ports:
|
||||
# - "${MYSQL_PORT:-3307}:3306"
|
||||
# environment:
|
||||
# MYSQL_ROOT_PASSWORD: ${DB_PASSWORD:-kaixinjiuhao}
|
||||
# volumes:
|
||||
# - mysql_data:/var/lib/mysql
|
||||
# - ./init-sql:/docker-entrypoint-initdb.d
|
||||
# - ../../sql:/sql-source
|
||||
# command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
|
||||
# healthcheck:
|
||||
# test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
|
||||
# interval: 10s
|
||||
# timeout: 5s
|
||||
# retries: 10
|
||||
# start_period: 30s
|
||||
# networks:
|
||||
# - smartclean
|
||||
|
||||
# redis:
|
||||
# image: redis:6-alpine
|
||||
# container_name: smartclean-redis
|
||||
# ports:
|
||||
# - "${REDIS_PORT:-6380}:6379"
|
||||
# command: redis-server --requirepass ${REDIS_PASSWORD:-kaixinjiuhao}
|
||||
# volumes:
|
||||
# - redis_data:/data
|
||||
# healthcheck:
|
||||
# test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD:-kaixinjiuhao}", "ping"]
|
||||
# interval: 10s
|
||||
# retries: 3
|
||||
# networks:
|
||||
# - smartclean
|
||||
|
||||
# ==================== 应用服务 ====================
|
||||
web:
|
||||
image: smartclean-web:${VERSION:-latest}
|
||||
container_name: smartclean-web
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: deploy/docker/Dockerfile.web
|
||||
ports:
|
||||
- "${WEB_PORT:-18095}:8080"
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
volumes:
|
||||
- ./conf/application-docker.yml:/app/config/application-docker.yml
|
||||
- web_logs:/app/logs
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-sf", "http://localhost:8080/"]
|
||||
interval: 15s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 90s
|
||||
restart: on-failure:3
|
||||
networks:
|
||||
- smartclean
|
||||
|
||||
task:
|
||||
image: smartclean-task:${VERSION:-latest}
|
||||
container_name: smartclean-task
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: deploy/docker/Dockerfile.task
|
||||
ports:
|
||||
- "${TASK_PORT:-18097}:8097"
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
environment:
|
||||
SPRING_PROFILES_ACTIVE: docker
|
||||
volumes:
|
||||
- ./conf/application-task-docker.yml:/app/config/application-task-docker.yml
|
||||
- task_logs:/app/logs
|
||||
restart: on-failure:3
|
||||
networks:
|
||||
- smartclean
|
||||
|
||||
frontend:
|
||||
image: smartclean-front:${VERSION:-latest}
|
||||
container_name: smartclean-front
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: deploy/docker/Dockerfile.front
|
||||
ports:
|
||||
- "${FRONT_PORT:-8180}:80"
|
||||
depends_on:
|
||||
- web
|
||||
volumes:
|
||||
- ./conf/nginx.conf:/etc/nginx/conf.d/default.conf
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-sf", "http://localhost/"]
|
||||
interval: 10s
|
||||
retries: 3
|
||||
restart: on-failure:3
|
||||
networks:
|
||||
- smartclean
|
||||
|
||||
volumes:
|
||||
web_logs:
|
||||
task_logs:
|
||||
|
||||
networks:
|
||||
smartclean:
|
||||
driver: bridge
|
||||
3
deploy/docker/init-sql/00-create-databases.sql
Normal file
3
deploy/docker/init-sql/00-create-databases.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
-- 创建数据库(如不存在)
|
||||
CREATE DATABASE IF NOT EXISTS `xiaoqu_comples_d` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
CREATE DATABASE IF NOT EXISTS `xiaoqu_intellectual_d` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
5
deploy/docker/init-sql/01-import-intellectual.sh
Executable file
5
deploy/docker/init-sql/01-import-intellectual.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
# 导入 xiaoqu_intellectual_d 数据库
|
||||
echo "[INIT] Importing xiaoqu_intellectual_d..."
|
||||
mysql -uroot -p"$MYSQL_ROOT_PASSWORD" xiaoqu_intellectual_d < /sql-source/xiaoqu_intellectual_d.sql
|
||||
echo "[INIT] Done."
|
||||
4
deploy/docker/rollback.sh
Executable file
4
deploy/docker/rollback.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
# 快捷回滚入口
|
||||
DEPLOY_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
exec "$DEPLOY_DIR/deploy.sh" rollback
|
||||
44
deploy/remote/config.sh
Normal file
44
deploy/remote/config.sh
Normal file
@@ -0,0 +1,44 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# SmartClean 部署配置(无 Docker 版)
|
||||
# 根据实际服务器环境修改以下配置
|
||||
|
||||
# ===== 服务器配置 =====
|
||||
DEPLOY_HOST="192.168.1.182"
|
||||
DEPLOY_USER="root"
|
||||
DEPLOY_BASE="/opt/smartclean"
|
||||
|
||||
# ===== 服务器目录 =====
|
||||
REMOTE_WEB_DIR="$DEPLOY_BASE/web"
|
||||
REMOTE_TASK_DIR="$DEPLOY_BASE/task"
|
||||
REMOTE_FRONT_DIR="$DEPLOY_BASE/front"
|
||||
REMOTE_BACKUP_DIR="$DEPLOY_BASE/backups"
|
||||
REMOTE_SCRIPTS_DIR="$DEPLOY_BASE/scripts"
|
||||
|
||||
# ===== Tomcat 配置 =====
|
||||
TOMCAT_HOME="$REMOTE_WEB_DIR/tomcat"
|
||||
TOMCAT_WEBAPPS="$TOMCAT_HOME/webapps"
|
||||
|
||||
# ===== Nginx 配置 =====
|
||||
NGINX_HTML="$REMOTE_FRONT_DIR/dist"
|
||||
|
||||
# ===== Task 服务配置 =====
|
||||
TASK_JAR_NAME="xiaoqu-intellectual-task-0.0.1-SNAPSHOT.jar"
|
||||
TASK_PROFILE="prod"
|
||||
TASK_JVM_OPTS="-Xms256m -Xmx512m"
|
||||
|
||||
# ===== 本地构建产物路径 =====
|
||||
LOCAL_WAR="backend/xiaoqu-intellectual-web/target/ROOT.war"
|
||||
LOCAL_TASK_JAR="backend/xiaoqu-intellectual-task/target/$TASK_JAR_NAME"
|
||||
LOCAL_FRONT_DIST="frontend/witcleansystem/dist"
|
||||
|
||||
# ===== 备份保留数量 =====
|
||||
MAX_BACKUPS=5
|
||||
|
||||
# ===== 健康检查 =====
|
||||
HEALTHCHECK_URL="http://$DEPLOY_HOST:8095/dropDown/districtTree"
|
||||
HEALTHCHECK_RETRIES=20
|
||||
HEALTHCHECK_INTERVAL=5
|
||||
|
||||
# ===== 飞书通知 =====
|
||||
FEISHU_WEBHOOK="https://open.feishu.cn/open-apis/bot/v2/hook/5703e8cc-6998-46a6-af9d-8c5102cc8c1e"
|
||||
410
deploy/remote/deploy.sh
Executable file
410
deploy/remote/deploy.sh
Executable file
@@ -0,0 +1,410 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# SmartClean 一键部署脚本(无 Docker 版 — 部署到远程服务器)
|
||||
#
|
||||
# 用法:
|
||||
# ./deploy.sh # 构建并部署所有服务
|
||||
# ./deploy.sh web # 仅构建部署 Web 服务
|
||||
# ./deploy.sh task # 仅构建部署 Task 服务
|
||||
# ./deploy.sh front # 仅构建部署前端(生产包)
|
||||
# ./deploy.sh front-test # 构建测试环境前端并部署
|
||||
# ./deploy.sh backend # 构建部署后端(web + task)
|
||||
# ./deploy.sh rollback # 回滚到上一版本
|
||||
# ./deploy.sh setup # 首次初始化服务器目录
|
||||
# ./deploy.sh status # 查看服务器服务状态
|
||||
|
||||
set -e
|
||||
|
||||
DEPLOY_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
ROOT_DIR="$(dirname "$(dirname "$DEPLOY_DIR")")"
|
||||
source "$DEPLOY_DIR/config.sh"
|
||||
|
||||
# ===== 版本号 =====
|
||||
GIT_HASH=$(cd "$ROOT_DIR" && git rev-parse --short HEAD)
|
||||
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
|
||||
VERSION="${TIMESTAMP}-${GIT_HASH}"
|
||||
BRANCH=$(cd "$ROOT_DIR" && git rev-parse --abbrev-ref HEAD)
|
||||
COMMIT=$(cd "$ROOT_DIR" && git log -1 --format='%h %s')
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
CYAN='\033[0;36m'
|
||||
NC='\033[0m'
|
||||
|
||||
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
|
||||
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||||
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||||
log_step() { echo -e "${CYAN}[STEP]${NC} $1"; }
|
||||
|
||||
SSH_CMD="ssh $DEPLOY_USER@$DEPLOY_HOST"
|
||||
SCP_CMD="scp"
|
||||
|
||||
# ===== 飞书通知 =====
|
||||
notify_feishu() {
|
||||
local title="$1" content="$2" color="$3"
|
||||
curl -s -X POST "$FEISHU_WEBHOOK" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"msg_type\": \"interactive\",
|
||||
\"card\": {
|
||||
\"header\": {\"title\":{\"tag\":\"plain_text\",\"content\":\"$title\"},\"template\":\"$color\"},
|
||||
\"elements\": [{\"tag\":\"markdown\",\"content\":\"$content\"}]
|
||||
}
|
||||
}" > /dev/null 2>&1
|
||||
}
|
||||
|
||||
# ===== 检查 SSH 连接 =====
|
||||
check_ssh() {
|
||||
log_info "检查 SSH 连接 ($DEPLOY_USER@$DEPLOY_HOST)..."
|
||||
if ! $SSH_CMD "echo ok" > /dev/null 2>&1; then
|
||||
log_error "无法连接到 $DEPLOY_USER@$DEPLOY_HOST"
|
||||
log_error "请先配置 SSH 免密登录:"
|
||||
log_error " ssh-keygen -t ed25519"
|
||||
log_error " ssh-copy-id $DEPLOY_USER@$DEPLOY_HOST"
|
||||
exit 1
|
||||
fi
|
||||
log_info "SSH 连接正常"
|
||||
}
|
||||
|
||||
# ===== 首次初始化服务器 =====
|
||||
setup_server() {
|
||||
log_step "1/2 初始化服务器目录结构..."
|
||||
$SCP_CMD "$DEPLOY_DIR/scripts/setup.sh" "$DEPLOY_USER@$DEPLOY_HOST:/tmp/smartclean-setup.sh"
|
||||
$SSH_CMD "bash /tmp/smartclean-setup.sh && rm -f /tmp/smartclean-setup.sh"
|
||||
|
||||
log_step "2/2 上传管理脚本..."
|
||||
$SCP_CMD "$DEPLOY_DIR/scripts/restart-web.sh" "$DEPLOY_USER@$DEPLOY_HOST:$REMOTE_SCRIPTS_DIR/"
|
||||
$SCP_CMD "$DEPLOY_DIR/scripts/restart-task.sh" "$DEPLOY_USER@$DEPLOY_HOST:$REMOTE_SCRIPTS_DIR/"
|
||||
$SCP_CMD "$DEPLOY_DIR/scripts/restart-front.sh" "$DEPLOY_USER@$DEPLOY_HOST:$REMOTE_SCRIPTS_DIR/"
|
||||
$SSH_CMD "chmod +x $REMOTE_SCRIPTS_DIR/*.sh"
|
||||
|
||||
log_info "服务器初始化完成"
|
||||
}
|
||||
|
||||
# ===== 查看服务器状态 =====
|
||||
show_status() {
|
||||
log_info "服务器状态 ($DEPLOY_HOST):"
|
||||
$SSH_CMD bash <<'EOF'
|
||||
echo ""
|
||||
echo "===== Web 服务 (Tomcat) ====="
|
||||
TOMCAT_PID=$(ps -ef | grep "[c]atalina" | awk '{print $2}')
|
||||
if [ -n "$TOMCAT_PID" ]; then
|
||||
echo " 状态: 运行中 (PID=$TOMCAT_PID)"
|
||||
else
|
||||
echo " 状态: 未运行"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "===== Task 服务 ====="
|
||||
if [ -f /opt/smartclean/task/task.pid ]; then
|
||||
TASK_PID=$(cat /opt/smartclean/task/task.pid)
|
||||
if kill -0 "$TASK_PID" 2>/dev/null; then
|
||||
echo " 状态: 运行中 (PID=$TASK_PID)"
|
||||
else
|
||||
echo " 状态: 未运行 (PID 文件残留)"
|
||||
fi
|
||||
else
|
||||
echo " 状态: 未运行"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "===== Nginx ====="
|
||||
if nginx -t 2>/dev/null; then
|
||||
echo " 状态: 运行中"
|
||||
else
|
||||
echo " 状态: 异常"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "===== 备份列表 ====="
|
||||
ls -dt /opt/smartclean/backups/*/ 2>/dev/null | head -5 || echo " 无备份"
|
||||
echo ""
|
||||
EOF
|
||||
}
|
||||
|
||||
# ===== 本地构建 =====
|
||||
build_local() {
|
||||
local target="$1"
|
||||
local build_target="$target"
|
||||
|
||||
# 映射 deploy 参数到 build.sh 参数
|
||||
case "$target" in
|
||||
all) build_target="all" ;;
|
||||
web) build_target="web" ;;
|
||||
task) build_target="task" ;;
|
||||
backend) build_target="backend" ;;
|
||||
front) build_target="front" ;;
|
||||
front-test) build_target="front-test" ;;
|
||||
esac
|
||||
|
||||
log_step "本地构建 (目标: $build_target)..."
|
||||
cd "$ROOT_DIR"
|
||||
bash build.sh "$build_target"
|
||||
|
||||
# 验证产物
|
||||
case "$target" in
|
||||
web|backend|all)
|
||||
[ ! -f "$ROOT_DIR/$LOCAL_WAR" ] && log_error "产物不存在: $LOCAL_WAR" && exit 1
|
||||
log_info " ROOT.war: $(du -h "$ROOT_DIR/$LOCAL_WAR" | cut -f1)"
|
||||
;;&
|
||||
task|backend|all)
|
||||
[ ! -f "$ROOT_DIR/$LOCAL_TASK_JAR" ] && log_error "产物不存在: $LOCAL_TASK_JAR" && exit 1
|
||||
log_info " task.jar: $(du -h "$ROOT_DIR/$LOCAL_TASK_JAR" | cut -f1)"
|
||||
;;&
|
||||
front|front-test|all)
|
||||
[ ! -d "$ROOT_DIR/$LOCAL_FRONT_DIST" ] && log_error "产物不存在: $LOCAL_FRONT_DIST" && exit 1
|
||||
log_info " dist/: $(du -sh "$ROOT_DIR/$LOCAL_FRONT_DIST" | cut -f1)"
|
||||
;;
|
||||
esac
|
||||
|
||||
log_info "本地构建完成"
|
||||
}
|
||||
|
||||
# ===== 远程备份 =====
|
||||
backup_remote() {
|
||||
local target="$1"
|
||||
log_step "远程备份当前版本..."
|
||||
|
||||
$SSH_CMD bash <<BKEOF
|
||||
BACKUP="$REMOTE_BACKUP_DIR/$VERSION"
|
||||
mkdir -p "\$BACKUP"
|
||||
|
||||
case "$target" in
|
||||
web|backend|all)
|
||||
cp "$TOMCAT_WEBAPPS/ROOT.war" "\$BACKUP/" 2>/dev/null && echo " 备份 ROOT.war" || echo " ROOT.war 不存在,跳过"
|
||||
;;&
|
||||
task|backend|all)
|
||||
cp "$REMOTE_TASK_DIR/task.jar" "\$BACKUP/" 2>/dev/null && echo " 备份 task.jar" || echo " task.jar 不存在,跳过"
|
||||
;;&
|
||||
front|front-test|all)
|
||||
if [ -d "$REMOTE_FRONT_DIR/dist" ]; then
|
||||
cp -r "$REMOTE_FRONT_DIR/dist" "\$BACKUP/"
|
||||
echo " 备份 front/dist"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
# 清理过期备份
|
||||
cd "$REMOTE_BACKUP_DIR"
|
||||
TOTAL=\$(ls -dt */ 2>/dev/null | wc -l)
|
||||
if [ \$TOTAL -gt $MAX_BACKUPS ]; then
|
||||
ls -dt */ | tail -n +\$(($MAX_BACKUPS + 1)) | xargs rm -rf
|
||||
echo " 已清理过期备份,保留最近 $MAX_BACKUPS 个"
|
||||
fi
|
||||
BKEOF
|
||||
|
||||
log_info "远程备份完成"
|
||||
}
|
||||
|
||||
# ===== 上传产物 =====
|
||||
upload_artifacts() {
|
||||
local target="$1"
|
||||
log_step "上传构建产物..."
|
||||
|
||||
case "$target" in
|
||||
web|backend|all)
|
||||
log_info " 上传 ROOT.war..."
|
||||
$SCP_CMD "$ROOT_DIR/$LOCAL_WAR" "$DEPLOY_USER@$DEPLOY_HOST:$TOMCAT_WEBAPPS/ROOT.war"
|
||||
;;&
|
||||
task|backend|all)
|
||||
log_info " 上传 task.jar..."
|
||||
$SCP_CMD "$ROOT_DIR/$LOCAL_TASK_JAR" "$DEPLOY_USER@$DEPLOY_HOST:$REMOTE_TASK_DIR/task.jar"
|
||||
;;&
|
||||
front|front-test|all)
|
||||
log_info " 上传前端文件..."
|
||||
$SSH_CMD "rm -rf $REMOTE_FRONT_DIR/dist"
|
||||
$SCP_CMD -r "$ROOT_DIR/$LOCAL_FRONT_DIST" "$DEPLOY_USER@$DEPLOY_HOST:$REMOTE_FRONT_DIR/dist"
|
||||
;;
|
||||
esac
|
||||
|
||||
log_info "产物上传完成"
|
||||
}
|
||||
|
||||
# ===== 远程重启服务 =====
|
||||
restart_services() {
|
||||
local target="$1"
|
||||
log_step "远程重启服务..."
|
||||
|
||||
case "$target" in
|
||||
web|backend|all)
|
||||
log_info " 重启 Web 服务..."
|
||||
$SSH_CMD "bash $REMOTE_SCRIPTS_DIR/restart-web.sh"
|
||||
;;&
|
||||
task|backend|all)
|
||||
log_info " 重启 Task 服务..."
|
||||
$SSH_CMD "bash $REMOTE_SCRIPTS_DIR/restart-task.sh $TASK_PROFILE '$TASK_JVM_OPTS'"
|
||||
;;&
|
||||
front|front-test|all)
|
||||
log_info " 重新加载前端..."
|
||||
$SSH_CMD "bash $REMOTE_SCRIPTS_DIR/restart-front.sh"
|
||||
;;
|
||||
esac
|
||||
|
||||
log_info "服务重启完成"
|
||||
}
|
||||
|
||||
# ===== 健康检查 =====
|
||||
healthcheck() {
|
||||
local target="$1"
|
||||
log_step "健康检查..."
|
||||
|
||||
# Web 服务检查
|
||||
if [ "$target" = "all" ] || [ "$target" = "web" ] || [ "$target" = "backend" ]; then
|
||||
log_info " 检查 Web 服务 ($HEALTHCHECK_URL)..."
|
||||
for i in $(seq 1 $HEALTHCHECK_RETRIES); do
|
||||
if curl -sf "$HEALTHCHECK_URL" > /dev/null 2>&1; then
|
||||
log_info " Web 服务健康 (第${i}次检查通过)"
|
||||
break
|
||||
fi
|
||||
if [ $i -eq $HEALTHCHECK_RETRIES ]; then
|
||||
log_error " Web 服务健康检查失败 (${HEALTHCHECK_RETRIES}次重试)"
|
||||
return 1
|
||||
fi
|
||||
printf "."
|
||||
sleep $HEALTHCHECK_INTERVAL
|
||||
done
|
||||
fi
|
||||
|
||||
# 前端检查
|
||||
if [ "$target" = "all" ] || [ "$target" = "front" ] || [ "$target" = "front-test" ]; then
|
||||
log_info " 检查前端服务..."
|
||||
for i in $(seq 1 10); do
|
||||
if curl -sf "http://$DEPLOY_HOST/" > /dev/null 2>&1; then
|
||||
log_info " 前端服务健康"
|
||||
break
|
||||
fi
|
||||
if [ $i -eq 10 ]; then
|
||||
log_error " 前端服务健康检查失败"
|
||||
return 1
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
fi
|
||||
|
||||
log_info "健康检查通过"
|
||||
return 0
|
||||
}
|
||||
|
||||
# ===== 回滚 =====
|
||||
rollback() {
|
||||
log_warn "开始回滚..."
|
||||
|
||||
LATEST_BACKUP=$($SSH_CMD "ls -dt $REMOTE_BACKUP_DIR/*/ 2>/dev/null | head -1 | xargs basename 2>/dev/null")
|
||||
|
||||
if [ -z "$LATEST_BACKUP" ]; then
|
||||
log_error "没有可回滚的备份"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_warn "回滚到版本: $LATEST_BACKUP"
|
||||
|
||||
$SSH_CMD bash <<RBEOF
|
||||
BACKUP="$REMOTE_BACKUP_DIR/$LATEST_BACKUP"
|
||||
|
||||
if [ -f "\$BACKUP/ROOT.war" ]; then
|
||||
cp "\$BACKUP/ROOT.war" "$TOMCAT_WEBAPPS/ROOT.war"
|
||||
echo " 已还原 ROOT.war"
|
||||
fi
|
||||
|
||||
if [ -f "\$BACKUP/task.jar" ]; then
|
||||
cp "\$BACKUP/task.jar" "$REMOTE_TASK_DIR/task.jar"
|
||||
echo " 已还原 task.jar"
|
||||
fi
|
||||
|
||||
if [ -d "\$BACKUP/dist" ]; then
|
||||
rm -rf "$REMOTE_FRONT_DIR/dist"
|
||||
cp -r "\$BACKUP/dist" "$REMOTE_FRONT_DIR/dist"
|
||||
echo " 已还原 front/dist"
|
||||
fi
|
||||
RBEOF
|
||||
|
||||
restart_services "all"
|
||||
log_info "回滚完成 (版本: $LATEST_BACKUP)"
|
||||
|
||||
notify_feishu "⚠️ SmartClean 已回滚" \
|
||||
"**回滚版本:** $LATEST_BACKUP\\n**服务器:** $DEPLOY_HOST\\n**操作人:** $(whoami)@$(hostname)" \
|
||||
"yellow"
|
||||
}
|
||||
|
||||
# ===== 主流程 =====
|
||||
TARGET="${1:-all}"
|
||||
DEPLOY_START=$(date +%s)
|
||||
|
||||
case "$TARGET" in
|
||||
setup)
|
||||
check_ssh
|
||||
setup_server
|
||||
exit 0
|
||||
;;
|
||||
rollback)
|
||||
check_ssh
|
||||
rollback
|
||||
exit 0
|
||||
;;
|
||||
status)
|
||||
check_ssh
|
||||
show_status
|
||||
exit 0
|
||||
;;
|
||||
all|web|task|backend|front|front-test)
|
||||
;;
|
||||
*)
|
||||
echo "用法: $0 {all|web|task|backend|front|front-test|rollback|setup|status}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo ""
|
||||
log_info "======================================"
|
||||
log_info " SmartClean 自动化部署 (远程服务器)"
|
||||
log_info " 版本: $VERSION"
|
||||
log_info " 分支: $BRANCH"
|
||||
log_info " 提交: $COMMIT"
|
||||
log_info " 目标: $TARGET"
|
||||
log_info " 服务器: $DEPLOY_USER@$DEPLOY_HOST"
|
||||
log_info "======================================"
|
||||
echo ""
|
||||
|
||||
# 1. 检查连接
|
||||
check_ssh
|
||||
|
||||
# 2. 本地构建
|
||||
build_local "$TARGET"
|
||||
|
||||
# 3. 远程备份
|
||||
backup_remote "$TARGET"
|
||||
|
||||
# 4. 上传产物
|
||||
upload_artifacts "$TARGET"
|
||||
|
||||
# 5. 重启服务
|
||||
restart_services "$TARGET"
|
||||
|
||||
# 6. 健康检查
|
||||
if healthcheck "$TARGET"; then
|
||||
ELAPSED=$(( $(date +%s) - DEPLOY_START ))
|
||||
|
||||
echo ""
|
||||
log_info "======================================"
|
||||
log_info " ✅ 部署成功!"
|
||||
log_info " 版本: $VERSION"
|
||||
log_info " 耗时: ${ELAPSED}s"
|
||||
log_info " 前端: http://$DEPLOY_HOST"
|
||||
log_info " Web: http://$DEPLOY_HOST:8095"
|
||||
log_info " Task: http://$DEPLOY_HOST:8097"
|
||||
log_info "======================================"
|
||||
|
||||
notify_feishu "✅ SmartClean 部署成功" \
|
||||
"**版本:** $VERSION\\n**分支:** $BRANCH\\n**提交:** $COMMIT\\n**目标:** $TARGET\\n**服务器:** $DEPLOY_HOST\\n**耗时:** ${ELAPSED}s\\n**操作人:** $(whoami)@$(hostname)" \
|
||||
"green"
|
||||
else
|
||||
log_error "健康检查失败,自动回滚..."
|
||||
rollback
|
||||
|
||||
ELAPSED=$(( $(date +%s) - DEPLOY_START ))
|
||||
notify_feishu "❌ SmartClean 部署失败(已回滚)" \
|
||||
"**版本:** $VERSION\\n**分支:** $BRANCH\\n**提交:** $COMMIT\\n**服务器:** $DEPLOY_HOST\\n**耗时:** ${ELAPSED}s\\n**状态:** 健康检查失败,已自动回滚" \
|
||||
"red"
|
||||
exit 1
|
||||
fi
|
||||
4
deploy/remote/rollback.sh
Executable file
4
deploy/remote/rollback.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
# 快捷回滚入口
|
||||
DEPLOY_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
exec "$DEPLOY_DIR/deploy.sh" rollback
|
||||
15
deploy/remote/scripts/restart-front.sh
Executable file
15
deploy/remote/scripts/restart-front.sh
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# 重新加载前端(Nginx reload)
|
||||
|
||||
echo "[INFO] 测试 Nginx 配置..."
|
||||
nginx -t 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "[ERROR] Nginx 配置有误"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[INFO] 重新加载 Nginx..."
|
||||
nginx -s reload
|
||||
|
||||
echo "[INFO] Nginx 已重新加载"
|
||||
37
deploy/remote/scripts/restart-task.sh
Executable file
37
deploy/remote/scripts/restart-task.sh
Executable file
@@ -0,0 +1,37 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# 重启 Task 服务(Spring Boot JAR)
|
||||
#
|
||||
# 用法: restart-task.sh [profile] [jvm_opts]
|
||||
|
||||
TASK_DIR="/opt/smartclean/task"
|
||||
JAR_FILE="$TASK_DIR/task.jar"
|
||||
PID_FILE="$TASK_DIR/task.pid"
|
||||
LOG_FILE="$TASK_DIR/logs/task.log"
|
||||
PROFILE="${1:-prod}"
|
||||
JVM_OPTS="${2:--Xms256m -Xmx512m}"
|
||||
|
||||
# 停止旧进程
|
||||
if [ -f "$PID_FILE" ]; then
|
||||
OLD_PID=$(cat "$PID_FILE")
|
||||
if kill -0 "$OLD_PID" 2>/dev/null; then
|
||||
echo "[INFO] 停止旧进程 PID=$OLD_PID"
|
||||
kill "$OLD_PID"
|
||||
sleep 3
|
||||
if kill -0 "$OLD_PID" 2>/dev/null; then
|
||||
echo "[WARN] 进程未正常退出,强制终止"
|
||||
kill -9 "$OLD_PID"
|
||||
fi
|
||||
fi
|
||||
rm -f "$PID_FILE"
|
||||
fi
|
||||
|
||||
# 启动新进程
|
||||
echo "[INFO] 启动 Task 服务 (profile=$PROFILE)..."
|
||||
nohup java $JVM_OPTS \
|
||||
-jar "$JAR_FILE" \
|
||||
--spring.profiles.active=$PROFILE \
|
||||
> "$LOG_FILE" 2>&1 &
|
||||
|
||||
echo $! > "$PID_FILE"
|
||||
echo "[INFO] Task 服务已启动, PID=$(cat "$PID_FILE")"
|
||||
26
deploy/remote/scripts/restart-web.sh
Executable file
26
deploy/remote/scripts/restart-web.sh
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# 重启 Web 服务(Tomcat)
|
||||
|
||||
TOMCAT_HOME="/opt/smartclean/web/tomcat"
|
||||
|
||||
echo "[INFO] 停止 Tomcat..."
|
||||
"$TOMCAT_HOME/bin/shutdown.sh" 2>/dev/null
|
||||
sleep 3
|
||||
|
||||
# 确保进程已停
|
||||
TOMCAT_PID=$(ps -ef | grep "[c]atalina" | awk '{print $2}')
|
||||
if [ -n "$TOMCAT_PID" ]; then
|
||||
echo "[WARN] Tomcat 未正常关闭,强制终止 PID=$TOMCAT_PID"
|
||||
kill -9 $TOMCAT_PID
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
# 清理旧的解压目录,保留 WAR
|
||||
rm -rf "$TOMCAT_HOME/webapps/ROOT"
|
||||
rm -rf "$TOMCAT_HOME/work/Catalina"
|
||||
|
||||
echo "[INFO] 启动 Tomcat..."
|
||||
"$TOMCAT_HOME/bin/startup.sh"
|
||||
|
||||
echo "[INFO] Tomcat 已启动"
|
||||
14
deploy/remote/scripts/setup.sh
Executable file
14
deploy/remote/scripts/setup.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# 服务器初始化脚本(仅需执行一次)
|
||||
# 在远程服务器上创建标准目录结构
|
||||
|
||||
DEPLOY_BASE="/opt/smartclean"
|
||||
|
||||
echo "[INFO] 创建目录结构..."
|
||||
mkdir -p "$DEPLOY_BASE"/{web/logs,task/logs,front,backups,scripts}
|
||||
|
||||
echo "[INFO] 目录结构:"
|
||||
find "$DEPLOY_BASE" -maxdepth 2 -type d | sort
|
||||
|
||||
echo "[INFO] 服务器初始化完成"
|
||||
Reference in New Issue
Block a user