提交 e0f57343 authored 作者: 陈泽健's avatar 陈泽健

Merge remote-tracking branch 'origin/develop' into develop

...@@ -131,7 +131,8 @@ ...@@ -131,7 +131,8 @@
"Bash(sed -i '/^[[:space:]]*TARGET_KEY=/d' check_deleted_file_ubains.sh)", "Bash(sed -i '/^[[:space:]]*TARGET_KEY=/d' check_deleted_file_ubains.sh)",
"Bash(check_deleted_file_ubains_header.tmp:*)", "Bash(check_deleted_file_ubains_header.tmp:*)",
"Bash(mv check_deleted_file_ubains_header.tmp check_deleted_file_ubains.sh)", "Bash(mv check_deleted_file_ubains_header.tmp check_deleted_file_ubains.sh)",
"Bash(chmod +x check_deleted_file_ubains.sh)" "Bash(chmod +x check_deleted_file_ubains.sh)",
"Bash(bash -n \"E:\\\\ubains-module-test\\\\ubains-module-test\\\\自动化部署脚本\\\\x86架构\\\\预定系统\\\\一键更新\\\\update_cron_jobs.sh\")"
] ]
} }
} }
# _PRD_预定系统一键更新定时任务脚本需求文档.md
> 版本:V1.0
> 创建日期:2026-03-30
> 适用范围:预定系统x86架构定时脚本自动化部署与更新
> 实现脚本:`自动化部署脚本/x86架构/预定系统/一键更新/update_cron_jobs.sh`
---
## 版本变更记录
| 版本 | 日期 | 变更内容 | 变更人 |
|------|------|----------|--------|
| V1.0 | 2026-03-30 | 初始版本,定义一键更新定时任务脚本需求 | Claude |
---
## 1. 背景与目标
### 1.1 背景
预定系统的定时监控与维护脚本已部署在多台服务器上,随着功能的持续迭代(如日志轮转、PID锁机制、连续失败阈值等),需要频繁更新这些脚本。当前手动更新方式存在以下问题:
1. **操作繁琐**:需要手动备份、传输、替换、配置权限
2. **容易出错**:人工操作容易遗漏文件或配置错误
3. **效率低下**:多台服务器需要逐台操作
4. **风险较高**:更新过程中可能影响正在运行的监控服务
5. **版本混乱**:难以确认服务器上的脚本版本
### 1.2 现状环境
| 项目 | 路径/配置 |
|------|-----------|
| **脚本存放目录** | `/opt/scripts/` |
| **日志目录** | `/var/log/scripts/` |
| **状态文件目录** | `/var/log/scripts/``/var/log/scripts/*_state/` |
| **PID文件目录** | `/var/log/scripts/` |
| **执行权限** | `chmod +x *.sh` |
| **日志目录权限** | `755` |
### 1.3 改进目标
实现一个一键更新脚本,具备以下能力:
1. **自动化更新**:一键完成所有监控脚本的替换更新
2. **智能备份**:更新前自动备份原有脚本
3. **安全替换**:采用原子替换策略,避免更新过程中服务中断
4. **批量部署**:支持单台或多台服务器批量更新
5. **版本验证**:更新后自动验证脚本版本
6. **回滚能力**:更新失败时支持快速回滚
7. **完整性检查**:更新前检查依赖环境和权限
---
## 2. 总体范围
### 2.1 纳入更新范围的脚本
#### 2.1.1 监控类脚本(每10分钟执行)
| 序号 | 脚本名称 | 版本 | 功能说明 |
|-----|---------|------|----------|
| 1 | `monitor_emqx_service.sh` | V2.2 | EMQX服务监控与自愈 |
| 2 | `monitor_mysql_service.sh` | V1.2 | MySQL服务监控与自愈 |
| 3 | `monitor_redis_service.sh` | V1.2 | Redis服务监控与自愈 |
| 4 | `monitor_external_api_services_v2.sh` | V1.2 | 外部API服务监控与自愈 |
| 5 | `monitor_inner_api_services.sh` | V1.2 | 内部API服务监控与自愈 |
#### 2.1.2 备份类脚本(每日执行)
| 序号 | 脚本名称 | 版本 | 功能说明 |
|-----|---------|------|----------|
| 1 | `backup_mysql_databases.sh` | V1.1 | MySQL数据库备份 |
| 2 | `backup_mysql_logs.sh` | V1.1 | MySQL日志备份 |
| 3 | `backup_nginx_logs.sh` | V1.1 | Nginx日志备份 |
#### 2.1.3 维护类脚本
| 序号 | 脚本名称 | 版本 | 功能说明 |
|-----|---------|------|----------|
| 1 | `auto_clean_deleted_ubains_v3.sh` | V3.0 | 已删除大文件自动清理 |
### 2.2 不在本期范围
- Docker镜像更新
- 应用配置文件更新
- 数据库结构变更
- 服务器批量管理工具(如Ansible)集成
---
## 3. 功能需求
### 3.1 核心功能
#### 3.1.1 脚本清单定义
```bash
# 脚本列表配置
declare -A SCRIPTS
SCRIPTS["monitor_emqx_service.sh"]="V2.2"
SCRIPTS["monitor_mysql_service.sh"]="V1.2"
SCRIPTS["monitor_redis_service.sh"]="V1.2"
SCRIPTS["monitor_external_api_services_v2.sh"]="V1.2"
SCRIPTS["monitor_inner_api_services.sh"]="V1.2"
SCRIPTS["backup_mysql_databases.sh"]="V1.1"
SCRIPTS["backup_mysql_logs.sh"]="V1.1"
SCRIPTS["backup_nginx_logs.sh"]="V1.1"
SCRIPTS["auto_clean_deleted_ubains_v3.sh"]="V3.0"
```
#### 3.1.2 更新流程
```
┌─────────────────────────────────────────────────────────────┐
│ 一键更新脚本主流程 │
└─────────────────────────────────────────────────────────────┘
┌───────────────────────────────────────┐
│ 1. 前置检查 │
│ - 检查脚本源目录是否存在 │
│ - 检查目标服务器SSH连接 │
│ - 检查目标目录权限 │
│ - 验证新脚本版本号 │
└───────────────┬───────────────────────┘
│ 检查失败
┌─────────┐
│ 中止执行 │
│ 提示原因 │
└─────────┘
│ 检查通过
┌───────────────────────────────────────┐
│ 2. 创建备份目录 │
│ - 创建时间戳备份目录 │
│ - 记录备份元数据 │
└───────────────┬───────────────────────┘
┌───────────────────────────────────────┐
│ 3. 备份原有脚本 │
│ - 复制现有脚本到备份目录 │
│ - 备份当前crontab配置 │
│ - 记录备份文件列表 │
└───────────────┬───────────────────────┘
┌───────────────────────────────────────┐
│ 4. 停止定时任务(可选) │
│ - 临时注释掉相关cron任务 │
│ - 等待正在运行的脚本完成 │
└───────────────┬───────────────────────┘
┌───────────────────────────────────────┐
│ 5. 更新脚本文件 │
│ - 复制新脚本到临时目录 │
│ - 设置执行权限 │
│ - 原子移动到目标目录 │
└───────────────┬───────────────────────┘
┌───────────────────────────────────────┐
│ 6. 创建必要目录 │
│ - 状态文件目录 │
│ - 确保日志目录存在 │
└───────────────┬───────────────────────┘
┌───────────────────────────────────────┐
│ 7. 更新crontab配置 │
│ - 更新定时任务配置(10分钟间隔) │
│ - 验证crontab语法 │
└───────────────┬───────────────────────┘
┌───────────────────────────────────────┐
│ 8. 版本验证 │
│ - 检查更新后脚本版本 │
│ - 验证脚本语法正确性 │
└───────────────┬───────────────────────┘
│ 验证失败
┌─────────┐
│ 自动回滚 │
│ 恢复备份 │
└─────────┘
│ 验证成功
┌───────────────────────────────────────┐
│ 9. 清理与完成 │
│ - 记录更新日志 │
│ - 输出更新报告 │
│ - 保留备份文件(7天) │
└───────────────────────────────────────┘
```
### 3.2 详细功能需求
#### 3.2.1 前置检查模块
**功能说明**:在执行更新前进行全面的环境检查
**检查项**
1. 源脚本目录存在性检查
2. 目标服务器SSH连通性检查
3. 目标目录写入权限检查
4. 新脚本版本号格式验证
5. 必需命令可用性检查(docker, gzip, mysqladmin, redis-cli等)
**失败处理**
- 任一检查失败则中止更新
- 输出详细的失败原因和建议
- 记录到日志文件
#### 3.2.2 自动备份模块
**功能说明**:更新前自动备份原有脚本和配置
**备份内容**
1. 所有待更新的脚本文件
2. 当前crontab配置
3. 备份元数据(版本、时间、文件MD5)
**备份策略**
- 备份目录:`/opt/scripts/backup/YYYYMMDD_HHMMSS/`
- 备份保留期:7天(自动清理过期备份)
- 备份命名:`脚本名.备份`
**备份格式**
```bash
/opt/scripts/backup/
├── 20260330_120000/
│ ├── monitor_emqx_service.sh.backup
│ ├── monitor_mysql_service.sh.backup
│ ├── crontab.backup
│ └── metadata.txt
└── 20260329_150000/
└── ...
```
#### 3.2.3 脚本更新模块
**功能说明**:安全、原子地替换脚本文件
**更新策略**
1. 先复制到临时目录(`/opt/scripts/.tmp/`
2. 设置执行权限
3. 验证脚本语法(`bash -n`
4. 原子移动到目标位置(`mv`
5. 验证文件完整性(MD5校验)
**安全措施**
- 使用临时目录进行中转
- 原子操作避免服务中断
- 失败时自动回滚
#### 3.2.4 Crontab配置模块
**功能说明**:自动更新定时任务配置
**更新内容**
```bash
# 预定系统定时任务配置(每 10 分钟,错峰执行)
*/10 * * * * /opt/scripts/monitor_emqx_service.sh
*/10 * * * * sleep 60 && /opt/scripts/monitor_mysql_service.sh
*/10 * * * * sleep 120 && /opt/scripts/monitor_redis_service.sh
*/10 * * * * sleep 180 && /opt/scripts/monitor_external_api_services_v2.sh
*/10 * * * * sleep 240 && /opt/scripts/monitor_inner_api_services.sh
# 数据备份类(每日凌晨)
0 1 * * * /opt/scripts/backup_mysql_databases.sh
0 2 * * * /opt/scripts/backup_mysql_logs.sh
0 3 * * * /opt/scripts/backup_nginx_logs.sh
# 系统维护类(每日凌晨)
0 4 * * * /opt/scripts/auto_clean_deleted_ubains_v3.sh
```
**配置策略**
- 保留用户自定义的其他cron任务
- 仅更新匹配预定系统脚本的cron项
- 更新前备份原有crontab
#### 3.2.5 目录创建模块
**功能说明**:确保必要的目录结构存在
**创建目录**
```bash
# 日志目录
/var/log/scripts/
# 状态文件目录
/var/log/scripts/external_api_state/
/var/log/scripts/inner_api_state/
# 备份目录
/opt/scripts/backup/
```
**权限设置**
- 目录权限:755
- 脚本权限:755 (rwxr-xr-x)
- 日志文件:644 (rw-r--r--)
#### 3.2.6 版本验证模块
**功能说明**:更新后验证脚本版本和功能
**验证项**
1. 脚本文件完整性(MD5校验)
2. 脚本版本号匹配
3. 脚本语法正确性
4. 执行权限正确设置
**版本号提取规则**
```bash
# 从脚本头部提取版本号
grep "^# 版本:" /opt/scripts/monitor_emqx_service.sh | awk '{print $2}'
```
#### 3.2.7 回滚模块
**功能说明**:更新失败时自动恢复原有脚本
**触发条件**
- 版本验证失败
- 脚本语法检查失败
- 文件完整性校验失败
- 用户手动中止
**回滚流程**
1. 停止更新过程
2. 从备份目录恢复原脚本
3. 恢复原crontab配置
4. 记录回滚日志
5. 输出回滚报告
### 3.3 远程更新支持
#### 3.3.1 单台服务器更新
```bash
# 本地更新模式(脚本在同一台服务器上)
./update_cron_jobs.sh
# 远程更新模式(通过SSH)
./update_cron_jobs.sh --host 192.168.1.100 --user root
```
#### 3.3.2 批量服务器更新
```bash
# 从服务器列表批量更新
./update_cron_jobs.sh --batch servers.txt
# servers.txt 格式:
192.168.1.100:root:password
192.168.1.101:root:password
192.168.1.102:root:password
```
### 3.4 交互式操作模式
#### 3.4.1 确认模式
```bash
# 执行前显示更新计划,等待用户确认
./update_cron_jobs.sh --confirm
# 输出示例:
========================================
即将更新以下服务器上的脚本:
服务器: 192.168.1.100
待更新脚本: 9 个
备份位置: /opt/scripts/backup/20260330_120000
========================================
是否继续?[y/N]
```
#### 3.4.2 干运行模式
```bash
# 仅检查不实际更新
./update_cron_jobs.sh --dry-run
```
### 3.5 日志与报告
#### 3.5.1 日志记录
**日志文件**`/var/log/scripts/update_cron_jobs.log`
**日志级别**:INFO, WARNING, ERROR, SUCCESS
**日志格式**
```
[2026-03-30 12:00:00] [INFO] ===== 开始更新任务 =====
[2026-03-30 12:00:01] [INFO] 服务器: 192.168.1.100
[2026-03-30 12:00:02] [INFO] 检查源脚本目录... 通过
[2026-03-30 12:00:03] [INFO] 检查SSH连接... 通过
[2026-03-30 12:00:04] [INFO] 备份原有脚本... 完成
[2026-03-30 12:00:10] [SUCCESS] 更新完成
```
#### 3.5.2 更新报告
**报告内容**
1. 更新服务器列表
2. 更新脚本列表及版本
3. 备份位置
4. 更新结果统计
5. 失败原因(如有)
**报告格式**
```
========================================
定时任务脚本更新报告
========================================
更新时间: 2026-03-30 12:00:00
服务器: 192.168.1.100
更新统计:
待更新脚本: 9 个
更新成功: 9 个
更新失败: 0 个
跳过脚本: 0 个
脚本版本:
monitor_emqx_service.sh V2.1 -> V2.2
monitor_mysql_service.sh V1.1 -> V1.2
monitor_redis_service.sh V1.1 -> V1.2
monitor_external_api_services_v2.sh V1.1 -> V1.2
monitor_inner_api_services.sh V1.1 -> V1.2
backup_mysql_databases.sh V1.0 -> V1.1
backup_mysql_logs.sh V1.0 -> V1.1
backup_nginx_logs.sh V1.0 -> V1.1
auto_clean_deleted_ubains_v3.sh V2.0 -> V3.0
备份位置: /opt/scripts/backup/20260330_120000
========================================
```
---
## 4. 技术方案
### 4.1 脚本结构
```bash
#!/bin/bash
#===============================================================================
# 脚本名称:update_cron_jobs.sh
# 功能描述:一键更新预定系统定时任务脚本
# 版本:V1.0
# 创建日期:2026-03-30
#
# 使用方法:
# ./update_cron_jobs.sh [选项]
#
# 选项:
# --host <地址> 远程服务器地址(默认本地)
# --user <用户> SSH用户名(默认root)
# --password <密码> SSH密码
# --batch <文件> 服务器列表文件
# --confirm 执行前确认
# --dry-run 干运行模式
# --rollback 回滚模式
# --help 显示帮助信息
#===============================================================================
# 配置参数
SCRIPT_DIR="./自动化部署脚本/x86架构/预定系统/定时脚本"
REMOTE_SCRIPT_DIR="/opt/scripts"
BACKUP_DIR="/opt/scripts/backup"
LOG_FILE="/var/log/scripts/update_cron_jobs.log"
# 脚本版本映射
declare -A SCRIPT_VERSIONS
SCRIPT_VERSIONS["monitor_emqx_service.sh"]="V2.2"
SCRIPT_VERSIONS["monitor_mysql_service.sh"]="V1.2"
# ... 其他脚本
# 函数定义
check_prerequisites() # 前置检查
backup_existing_scripts() # 备份原有脚本
update_scripts() # 更新脚本文件
update_crontab() # 更新定时任务
verify_update() # 验证更新结果
rollback_update() # 回滚更新
generate_report() # 生成更新报告
# 主流程
main() {
parse_arguments "$@"
check_prerequisites
backup_existing_scripts
update_scripts
update_crontab
verify_update
generate_report
}
main "$@"
```
### 4.2 关键技术点
#### 4.2.1 原子替换策略
```bash
# 使用临时目录实现原子替换
TEMP_DIR="/opt/scripts/.tmp"
mkdir -p "$TEMP_DIR"
# 复制新脚本到临时目录
cp "$NEW_SCRIPT" "$TEMP_DIR/"
# 设置权限
chmod +x "$TEMP_DIR/$(basename "$NEW_SCRIPT")"
# 原子移动
mv "$TEMP_DIR/$(basename "$NEW_SCRIPT")" "$TARGET_DIR/"
# 清理临时目录
rm -rf "$TEMP_DIR"
```
#### 4.2.2 版本号提取与验证
```bash
# 提取脚本版本号
get_script_version() {
local script_file="$1"
grep "^# 版本:" "$script_file" | awk '{print $2}'
}
# 验证版本号
verify_version() {
local script="$1"
local expected_version="$2"
local actual_version=$(get_script_version "$script")
if [ "$actual_version" != "$expected_version" ]; then
log "ERROR: $script 版本不匹配 (期望: $expected_version, 实际: $actual_version)"
return 1
fi
return 0
}
```
#### 4.2.3 Crontab安全更新
```bash
# 备份当前crontab
backup_crontab() {
crontab -l > "$BACKUP_DIR/crontab.backup"
}
# 更新crontab(保留其他任务)
update_crontab() {
local new_cron="$1"
local temp_cron="/tmp/crontab.tmp"
# 移除旧的预定系统cron任务
crontab -l | grep -v "/opt/scripts/" > "$temp_cron"
# 添加新的cron任务
echo "$new_cron" >> "$temp_cron"
# 安装新的crontab
crontab "$temp_cron"
rm -f "$temp_cron"
}
```
#### 4.2.4 远程执行支持
```bash
# 远程执行命令
remote_exec() {
local host="$1"
local user="$2"
local command="$3"
ssh "${user}@${host}" "$command"
}
# 远程复制文件
remote_copy() {
local host="$1"
local user="$2"
local source="$3"
local dest="$4"
scp "$source" "${user}@${host}:${dest}"
}
```
### 4.3 文件传输方案
#### 4.3.1 本地模式
脚本在同一台服务器上执行,直接使用 `cp` 命令复制文件。
#### 4.3.2 SSH远程模式
使用 `scp` 传输脚本文件,使用 `ssh` 执行远程命令。
#### 4.3.3 批量模式
读取服务器列表文件,循环执行远程更新。
---
## 5. 配置参数
### 5.1 脚本配置
| 参数名 | 默认值 | 说明 |
|--------|--------|------|
| SCRIPT_DIR | ./定时脚本 | 本地脚本源目录 |
| REMOTE_SCRIPT_DIR | /opt/scripts | 远程脚本目标目录 |
| BACKUP_DIR | /opt/scripts/backup | 备份目录 |
| LOG_FILE | /var/log/scripts/update_cron_jobs.log | 日志文件 |
| BACKUP_RETENTION_DAYS | 7 | 备份保留天数 |
| TEMP_DIR | /opt/scripts/.tmp | 临时目录 |
### 5.2 Crontab配置
```bash
# 监控类(每10分钟)
CRON_MONITOR="*/10 * * * *"
# 备份类(每日凌晨)
CRON_BACKUP_DAILY="0 1-3 * * *"
# 清理类(每日凌晨)
CRON_CLEAN="0 4 * * *"
```
---
## 6. 使用场景
### 6.1 场景一:首次部署
```bash
# 在新服务器上首次部署监控脚本
./update_cron_jobs.sh --host 192.168.1.100 --user root
```
**执行流程**
1. 检查目标目录是否存在(不存在则创建)
2. 上传所有脚本文件
3. 设置执行权限
4. 创建必要目录
5. 配置crontab定时任务
6. 验证部署结果
### 6.2 场景二:版本更新
```bash
# 更新已有服务器上的脚本版本
./update_cron_jobs.sh --host 192.168.1.100 --confirm
```
**执行流程**
1. 检查现有脚本版本
2. 备份原有脚本
3. 上传新版本脚本
4. 验证版本号
5. 更新crontab配置
6. 输出更新报告
### 6.3 场景三:批量更新
```bash
# 从服务器列表批量更新
./update_cron_jobs.sh --batch servers.txt
```
**执行流程**
1. 读取服务器列表
2. 逐台服务器执行更新
3. 汇总更新结果
4. 生成批量更新报告
### 6.4 场景四:回滚操作
```bash
# 回滚到上一个版本
./update_cron_jobs.sh --rollback --host 192.168.1.100
```
**执行流程**
1. 查找最新的备份目录
2. 恢复备份的脚本文件
3. 恢复备份的crontab配置
4. 验证回滚结果
---
## 7. 验收标准
### 7.1 功能验收
1. **前置检查**
- ✅ 能正确检测源脚本目录
- ✅ 能正确检测SSH连接
- ✅ 能正确检测目标目录权限
- ✅ 能验证脚本版本号
2. **备份功能**
- ✅ 能正确备份原有脚本
- ✅ 能正确备份crontab配置
- ✅ 备份文件能正确恢复
3. **更新功能**
- ✅ 能正确更新所有脚本
- ✅ 能正确设置执行权限
- ✅ 能正确更新crontab配置
- ✅ 能正确创建必要目录
4. **验证功能**
- ✅ 能正确验证脚本版本
- ✅ 能正确验证脚本语法
- ✅ 能正确验证文件完整性
5. **回滚功能**
- ✅ 更新失败时能自动回滚
- ✅ 能手动触发回滚操作
- ✅ 回滚后能正确恢复原状态
### 7.2 性能验收
1. **执行时间**
- ✅ 单台服务器更新时间 < 30秒
- ✅ 批量更新(10台)< 5分钟
2. **资源占用**
- ✅ CPU占用 < 50%
- ✅ 内存占用 < 100MB
- ✅ 网络带宽 < 10MB
### 7.3 安全验收
1. **数据安全**
- ✅ 更新前自动备份
- ✅ 备份文件完整可用
- ✅ 失败时能正确恢复
2. **操作安全**
- ✅ 原子操作避免服务中断
- ✅ 临时文件正确清理
- ✅ 权限正确设置
### 7.4 日志验收
1. **日志完整性**
- ✅ 所有操作都有日志记录
- ✅ 日志格式统一规范
- ✅ 错误信息详细准确
2. **报告完整性**
- ✅ 报告内容完整详细
- ✅ 统计数据准确无误
- ✅ 失败原因清晰明确
---
## 8. 错误处理
### 8.1 常见错误
| 错误类型 | 触发条件 | 处理策略 |
|----------|----------|----------|
| **源目录不存在** | SCRIPT_DIR不存在 | 中止执行,提示检查路径 |
| **SSH连接失败** | 网络不通或认证失败 | 中止执行,提示检查连接 |
| **权限不足** | 无法写入目标目录 | 中止执行,提示检查权限 |
| **版本不匹配** | 脚本版本号不符合预期 | 记录警告,继续更新 |
| **备份失败** | 无法创建备份目录 | 中止执行,提示检查空间 |
| **更新失败** | 文件复制或权限设置失败 | 自动回滚,记录错误 |
| **验证失败** | 版本或语法验证失败 | 自动回滚,记录错误 |
### 8.2 错误处理流程
```
错误发生
记录错误日志
├─ 致命错误 ──→ 自动回滚 ──→ 输出错误报告 ──→ 中止执行
└─ 非致命错误 ──→ 记录警告 ──→ 继续执行 ──→ 标记失败项
```
---
## 9. 附录
### 9.1 脚本完整版本映射
```bash
monitor_emqx_service.sh=V2.2
monitor_mysql_service.sh=V1.2
monitor_redis_service.sh=V1.2
monitor_external_api_services_v2.sh=V1.2
monitor_inner_api_services.sh=V1.2
backup_mysql_databases.sh=V1.1
backup_mysql_logs.sh=V1.1
backup_nginx_logs.sh=V1.1
auto_clean_deleted_ubains_v3.sh=V3.0
```
### 9.2 目录结构
```
预定系统一键更新/
├── update_cron_jobs.sh # 主更新脚本
├── config/
│ ├── scripts.conf # 脚本版本配置
│ └── servers.txt # 服务器列表
├── lib/
│ ├── backup.sh # 备份函数库
│ ├── verify.sh # 验证函数库
│ └── remote.sh # 远程执行函数库
└── logs/
└── update_cron_jobs.log # 更新日志
```
### 9.3 相关文档
- `_PRD_预定系统定时脚本需求文档概览.md`
- `配置说明.md`
- 各监控服务需求文档
### 9.4 缩略语说明
| 缩写 | 全称 | 说明 |
|------|------|------|
| SSH | Secure Shell | 安全外壳协议 |
| SCP | Secure Copy Protocol | 安全复制协议 |
| MD5 | Message-Digest Algorithm 5 | 消息摘要算法 |
| Cron | Chronological | 定时任务调度器 |
---
## 需求规范
- 代码规范:Docs/PRD/01规范文档/_PRD_规范文档_代码规范.md
- 问题总结:Docs/PRD/01规范文档/_PRD_问题总结_记录文档.md
- 方法总结:Docs/PRD/01规范文档/_PRD_方法总结_记录文档.md
- 文档规范:Docs/PRD/01规范文档/_PRD_规范文档_文档规范.md
- 测试规范:Docs/PRD/01规范文档/_PRD_规范文档_测试规范.md
# _PRD_预定系统一键更新定时任务脚本需求文档_计划执行.md
> 版本:V1.0
> 更新日期:2026-03-30
> 关联文档:_PRD_预定系统一键更新定时任务脚本需求文档.md (V1.0)
> 关联脚本:update_cron_jobs.sh (新建)
---
## 一、变更概述
### 1.1 变更背景
当前预定系统的定时监控与维护脚本部署在多台服务器上,每次版本更新都需要手动执行以下操作:
1. 登录服务器
2. 备份原有脚本
3. 上传新脚本
4. 设置执行权限
5. 更新crontab配置
6. 验证更新结果
这些操作繁琐、耗时且容易出错,需要开发一个自动化的一键更新脚本。
### 1.2 变更目标
开发一个一键更新脚本,实现以下目标:
- ✅ 自动备份原有脚本和配置
- ✅ 安全、原子地替换脚本文件
- ✅ 自动更新crontab配置
- ✅ 更新后自动验证脚本版本
- ✅ 失败时自动回滚
- ✅ 支持本地和远程更新模式
- ✅ 支持批量服务器更新
---
## 二、当前部署方式分析
### 2.1 当前手动更新流程
```
┌─────────────────────────────────────┐
│ 手动更新脚本流程 │
└─────────────────────────────────────┘
┌───────────────┐
│ 1. 登录服务器 │
│ ssh server │
└───────┬───────┘
┌───────────────┐
│ 2. 手动备份 │
│ cp .bak │
└───────┬───────┘
┌───────────────┐
│ 3. 上传脚本 │
│ scp upload │
└───────┬───────┘
┌───────────────┐
│ 4. 设置权限 │
│ chmod +x │
└───────┬───────┘
┌───────────────┐
│ 5. 更新crontab │
│ crontab -e │
└───────┬───────┘
┌───────────────┐
│ 6. 手动验证 │
│ 测试执行 │
└───────────────┘
```
### 2.2 手动更新的问题
| 问题 | 影响 | 解决方案 |
|------|------|----------|
| 操作繁琐 | 效率低下,10台服务器需要30分钟 | 自动化脚本 |
| 容易出错 | 可能遗漏文件或配置错误 | 标准化流程 |
| 无备份保障 | 更新失败无法回滚 | 自动备份 |
| 无版本验证 | 无法确认更新是否成功 | 版本验证 |
| 无批量支持 | 需逐台操作 | 批量模式 |
---
## 三、实现计划
### 3.1 脚本结构设计
```
update_cron_jobs.sh
├── 头部注释(版本、日期、功能描述)
├── 配置参数区
│ ├── SCRIPT_DIR # 源脚本目录
│ ├── REMOTE_SCRIPT_DIR # 目标脚本目录
│ ├── BACKUP_DIR # 备份目录
│ ├── LOG_FILE # 日志文件
│ └── SCRIPT_VERSIONS # 脚本版本映射
├── 函数定义区
│ ├── log() # 日志记录
│ ├── check_prerequisites() # 前置检查
│ ├── backup_scripts() # 备份脚本
│ ├── backup_crontab() # 备份crontab
│ ├── update_scripts() # 更新脚本
│ ├── update_crontab() # 更新crontab
│ ├── verify_update() # 验证更新
│ ├── rollback_update() # 回滚更新
│ ├── generate_report() # 生成报告
│ ├── remote_exec() # 远程执行
│ └── remote_copy() # 远程复制
└── 主流程区
├── parse_arguments() # 参数解析
├── main() # 主函数
└── 入口点
```
### 3.2 核心函数实现
#### 3.2.1 前置检查函数
```bash
check_prerequisites() {
log "========== 开始前置检查 =========="
# 1. 检查源脚本目录
if [ ! -d "$SCRIPT_DIR" ]; then
log "ERROR: 源脚本目录不存在: $SCRIPT_DIR"
exit 1
fi
log "INFO: 源脚本目录检查通过"
# 2. 检查SSH连接(远程模式)
if [ "$REMOTE_MODE" = true ]; then
if ! ssh -o ConnectTimeout=5 "${REMOTE_USER}@${REMOTE_HOST}" "echo 'ping'" >/dev/null 2>&1; then
log "ERROR: 无法连接到远程服务器: ${REMOTE_USER}@${REMOTE_HOST}"
exit 1
fi
log "INFO: SSH连接检查通过"
fi
# 3. 检查目标目录权限
if [ "$REMOTE_MODE" = true ]; then
ssh "${REMOTE_USER}@${REMOTE_HOST}" "mkdir -p $REMOTE_SCRIPT_DIR 2>/dev/null || exit 1"
else
mkdir -p "$REMOTE_SCRIPT_DIR" 2>/dev/null || {
log "ERROR: 无法创建目标目录: $REMOTE_SCRIPT_DIR"
exit 1
}
fi
log "INFO: 目标目录权限检查通过"
# 4. 验证脚本版本
for script in "${!SCRIPT_VERSIONS[@]}"; do
local script_path="$SCRIPT_DIR/$script"
if [ ! -f "$script_path" ]; then
log "ERROR: 脚本文件不存在: $script_path"
exit 1
fi
local expected_version="${SCRIPT_VERSIONS[$script]}"
local actual_version=$(grep "^# 版本:" "$script_path" | awk '{print $2}')
if [ "$actual_version" != "$expected_version" ]; then
log "WARNING: $script 版本不匹配 (期望: $expected_version, 实际: $actual_version)"
fi
done
log "INFO: 脚本版本验证完成"
log "========== 前置检查通过 =========="
return 0
}
```
#### 3.2.2 备份函数
```bash
backup_scripts() {
log "========== 开始备份原有脚本 =========="
# 创建备份目录
local backup_timestamp=$(date +%Y%m%d_%H%M%S)
local backup_base_dir="$BACKUP_DIR/$backup_timestamp"
if [ "$REMOTE_MODE" = true ]; then
ssh "${REMOTE_USER}@${REMOTE_HOST}" "mkdir -p $backup_base_dir"
else
mkdir -p "$backup_base_dir"
fi
# 备份每个脚本
for script in "${!SCRIPT_VERSIONS[@]}"; do
local target_path="$REMOTE_SCRIPT_DIR/$script"
local backup_path="$backup_base_dir/${script}.backup"
if [ "$REMOTE_MODE" = true ]; then
ssh "${REMOTE_USER}@${REMOTE_HOST}" "test -f $target_path && cp $target_path $backup_path || true"
else
if [ -f "$target_path" ]; then
cp "$target_path" "$backup_path"
log "INFO: 已备份: $script"
else
log "WARNING: 脚本不存在,跳过备份: $script"
fi
fi
done
# 备份crontab
backup_crontab "$backup_timestamp"
# 记录备份元数据
local metadata_file="$backup_base_dir/metadata.txt"
local metadata_content="备份时间: $(date '+%Y-%m-%d %H:%M:%S')
备份用户: $(whoami)
备份服务器: ${REMOTE_HOST:-localhost}
脚本版本:
"
for script in "${!SCRIPT_VERSIONS[@]}"; do
metadata_content="${metadata_content}${script}=${SCRIPT_VERSIONS[$script]}\n"
done
if [ "$REMOTE_MODE" = true ]; then
echo -e "$metadata_content" | ssh "${REMOTE_USER}@${REMOTE_HOST}" "cat > $metadata_file"
else
echo -e "$metadata_content" > "$metadata_file"
fi
log "INFO: 备份完成,备份位置: $backup_base_dir"
log "========== 备份完成 =========="
return 0
}
backup_crontab() {
local backup_timestamp="$1"
log "INFO: 开始备份crontab配置"
local crontab_backup="$BACKUP_DIR/$backup_timestamp/crontab.backup"
if [ "$REMOTE_MODE" = true ]; then
ssh "${REMOTE_USER}@${REMOTE_HOST}" "crontab -l > $crontab_backup 2>/dev/null || true"
else
crontab -l > "$crontab_backup" 2>/dev/null || true
fi
log "INFO: crontab备份完成"
return 0
}
```
#### 3.2.3 更新脚本函数
```bash
update_scripts() {
log "========== 开始更新脚本文件 =========="
local temp_dir="/opt/scripts/.tmp"
# 远程模式:先上传到临时目录
if [ "$REMOTE_MODE" = true ]; then
# 创建远程临时目录
ssh "${REMOTE_USER}@${REMOTE_HOST}" "mkdir -p $temp_dir"
# 上传脚本到临时目录
for script in "${!SCRIPT_VERSIONS[@]}"; do
local script_path="$SCRIPT_DIR/$script"
scp "$script_path" "${REMOTE_USER}@${REMOTE_HOST}:${temp_dir}/"
log "INFO: 已上传: $script"
done
# 远程执行更新
ssh "${REMOTE_USER}@${REMOTE_HOST}" << 'ENDSSH'
cd $temp_dir
for script in *; do
# 设置执行权限
chmod +x "$script"
# 验证语法
if bash -n "$script" 2>/dev/null; then
# 原子移动到目标目录
mv -f "$script" "$REMOTE_SCRIPT_DIR/"
echo "已更新: $script"
else
echo "ERROR: $script 语法验证失败"
exit 1
fi
done
rm -rf $temp_dir
ENDSSH
else
# 本地模式:直接复制到临时目录
mkdir -p "$temp_dir"
for script in "${!SCRIPT_VERSIONS[@]}"; do
local script_path="$SCRIPT_DIR/$script"
cp "$script_path" "$temp_dir/"
done
# 设置权限并验证
for script in "${!SCRIPT_VERSIONS[@]}"; do
chmod +x "$temp_dir/$script"
if bash -n "$temp_dir/$script" 2>/dev/null; then
mv -f "$temp_dir/$script" "$REMOTE_SCRIPT_DIR/"
log "INFO: 已更新: $script"
else
log "ERROR: $script 语法验证失败"
rm -rf "$temp_dir"
return 1
fi
done
rm -rf "$temp_dir"
fi
log "========== 脚本更新完成 =========="
return 0
}
```
#### 3.2.4 更新Crontab函数
```bash
update_crontab() {
log "========== 开始更新crontab配置 =========="
# 新的crontab配置
local new_cron="# 预定系统定时任务配置(每 10 分钟,错峰执行)
*/10 * * * * $REMOTE_SCRIPT_DIR/monitor_emqx_service.sh
*/10 * * * * sleep 60 && $REMOTE_SCRIPT_DIR/monitor_mysql_service.sh
*/10 * * * * sleep 120 && $REMOTE_SCRIPT_DIR/monitor_redis_service.sh
*/10 * * * * sleep 180 && $REMOTE_SCRIPT_DIR/monitor_external_api_services_v2.sh
*/10 * * * * sleep 240 && $REMOTE_SCRIPT_DIR/monitor_inner_api_services.sh
# 数据备份类(每日凌晨)
0 1 * * * $REMOTE_SCRIPT_DIR/backup_mysql_databases.sh
0 2 * * * $REMOTE_SCRIPT_DIR/backup_mysql_logs.sh
0 3 * * * $REMOTE_SCRIPT_DIR/backup_nginx_logs.sh
# 系统维护类(每日凌晨)
0 4 * * * $REMOTE_SCRIPT_DIR/auto_clean_deleted_ubains_v3.sh"
"
if [ "$REMOTE_MODE" = true ]; then
ssh "${REMOTE_USER}@${REMOTE_HOST}" << ENDSSH
# 移除旧的预定系统cron任务
crontab -l | grep -v "$REMOTE_SCRIPT_DIR/" > /tmp/crontab.tmp 2>/dev/null || true
# 添加新的cron任务
echo "$new_cron" >> /tmp/crontab.tmp
# 安装新的crontab
crontab /tmp/crontab.tmp
rm -f /tmp/crontab.tmp
ENDSSH
else
# 移除旧的预定系统cron任务
crontab -l | grep -v "$REMOTE_SCRIPT_DIR/" > /tmp/crontab.tmp 2>/dev/null || true
# 添加新的cron任务
echo "$new_cron" >> /tmp/crontab.tmp
# 安装新的crontab
crontab /tmp/crontab.tmp
rm -f /tmp/crontab.tmp
fi
log "INFO: crontab配置更新完成"
log "========== crontab更新完成 =========="
return 0
}
```
#### 3.2.5 版本验证函数
```bash
verify_update() {
log "========== 开始版本验证 =========="
local verify_failed=0
for script in "${!SCRIPT_VERSIONS[@]}"; do
local expected_version="${SCRIPT_VERSIONS[$script]}"
local target_path="${REMOTE_SCRIPT_DIR}/${script}"
if [ "$REMOTE_MODE" = true ]; then
local actual_version=$(ssh "${REMOTE_USER}@${REMOTE_HOST}" "grep '^# 版本:' $target_path 2>/dev/null | awk '{print \$2}'")
else
local actual_version=$(grep "^# 版本:" "$target_path" 2>/dev/null | awk '{print $2}')
fi
if [ "$actual_version" = "$expected_version" ]; then
log "SUCCESS: $script 版本验证通过 ($actual_version)"
else
log "ERROR: $script 版本不匹配 (期望: $expected_version, 实际: $actual_version)"
verify_failed=1
fi
done
if [ $verify_failed -eq 0 ]; then
log "========== 版本验证通过 =========="
return 0
else
log "ERROR: 版本验证失败,将执行回滚"
log "========== 版本验证失败 =========="
return 1
fi
}
```
#### 3.2.6 回滚函数
```bash
rollback_update() {
log "========== 开始回滚操作 =========="
# 获取最新备份目录
local latest_backup=$(ls -t "$BACKUP_DIR" | head -1)
if [ -z "$latest_backup" ]; then
log "ERROR: 未找到备份目录,无法回滚"
return 1
fi
log "INFO: 使用备份: $latest_backup"
# 恢复脚本
for script in "${!SCRIPT_VERSIONS[@]}"; do
local backup_path="$BACKUP_DIR/$latest_backup/${script}.backup"
local target_path="$REMOTE_SCRIPT_DIR/$script"
if [ -f "$backup_path" ]; then
if [ "$REMOTE_MODE" = true ]; then
ssh "${REMOTE_USER}@${REMOTE_HOST}" "cp $backup_path $target_path"
else
cp "$backup_path" "$target_path"
fi
log "INFO: 已恢复: $script"
fi
done
# 恢复crontab
local crontab_backup="$BACKUP_DIR/$latest_backup/crontab.backup"
if [ -f "$crontab_backup" ]; then
if [ "$REMOTE_MODE" = true ]; then
ssh "${REMOTE_USER}@${REMOTE_HOST}" "crontab $crontab_backup"
else
crontab "$crontab_backup"
fi
log "INFO: 已恢复crontab配置"
fi
log "========== 回滚完成 =========="
return 0
}
```
### 3.3 目录创建
```bash
create_directories() {
log "INFO: 创建必要目录"
local dirs=(
"$REMOTE_SCRIPT_DIR"
"/var/log/scripts"
"/var/log/scripts/external_api_state"
"/var/log/scripts/inner_api_state"
"$BACKUP_DIR"
)
for dir in "${dirs[@]}"; do
if [ "$REMOTE_MODE" = true ]; then
ssh "${REMOTE_USER}@${REMOTE_HOST}" "mkdir -p $dir 2>/dev/null || true"
else
mkdir -p "$dir" 2>/dev/null || true
fi
done
# 设置权限
if [ "$REMOTE_MODE" = true ]; then
ssh "${REMOTE_USER}@${REMOTE_HOST}" "chmod 755 /var/log/scripts /var/log/scripts/*_state 2>/dev/null || true"
else
chmod 755 /var/log/scripts 2>/dev/null || true
chmod 755 /var/log/scripts/*_state 2>/dev/null || true
fi
}
```
---
## 四、主流程设计
### 4.1 主函数流程
```bash
main() {
log "=========================================="
log " 定时任务脚本一键更新工具"
log "=========================================="
log "更新时间: $(date '+%Y-%m-%d %H:%M:%S')"
log "目标服务器: ${REMOTE_HOST:-本地}"
log "=========================================="
# 解析参数
parse_arguments "$@"
# 检查是否为回滚模式
if [ "$ROLLBACK_MODE" = true ]; then
rollback_update
generate_report
exit 0
fi
# 检查是否为干运行模式
if [ "$DRY_RUN" = true ]; then
log "INFO: 干运行模式,仅检查不实际更新"
check_prerequisites
exit 0
fi
# 执行更新流程
check_prerequisites || exit 1
create_directories
backup_scripts || exit 1
update_scripts || { rollback_update; exit 1; }
update_crontab || { rollback_update; exit 1; }
verify_update || { rollback_update; exit 1; }
generate_report
# 清理过期备份
clean_old_backups
log "=========================================="
log " 更新完成"
log "=========================================="
}
```
### 4.2 参数解析
```bash
parse_arguments() {
REMOTE_MODE=false
REMOTE_HOST=""
REMOTE_USER="root"
BATCH_MODE=false
CONFIRM_MODE=false
DRY_RUN=false
ROLLBACK_MODE=false
SERVERS_FILE=""
while [ $# -gt 0 ]; do
case $1 in
--host)
REMOTE_MODE=true
REMOTE_HOST="$2"
shift 2
;;
--user)
REMOTE_USER="$2"
shift 2
;;
--password)
REMOTE_PASSWORD="$2"
shift 2
;;
--batch)
BATCH_MODE=true
SERVERS_FILE="$2"
shift 2
;;
--confirm)
CONFIRM_MODE=true
shift
;;
--dry-run)
DRY_RUN=true
shift
;;
--rollback)
ROLLBACK_MODE=true
shift
;;
--help)
show_help
exit 0
;;
*)
echo "未知参数: $1"
show_help
exit 1
;;
esac
done
}
```
---
## 五、代码验证清单
### 5.1 必需函数清单
```bash
# 核心函数(必须实现)
log() # 日志记录
check_prerequisites() # 前置检查
backup_scripts() # 备份脚本
backup_crontab() # 备份crontab
update_scripts() # 更新脚本
update_crontab() # 更新crontab
verify_update() # 验证更新
rollback_update() # 回滚更新
generate_report() # 生成报告
parse_arguments() # 参数解析
main() # 主函数
# 远程执行函数(远程模式需要)
remote_exec() # 远程执行命令
remote_copy() # 远程复制文件
```
### 5.2 配置参数清单
```bash
# 验证以下配置参数存在
SCRIPT_DIR="./自动化部署脚本/x86架构/预定系统/定时脚本"
REMOTE_SCRIPT_DIR="/opt/scripts"
BACKUP_DIR="/opt/scripts/backup"
LOG_FILE="/var/log/scripts/update_cron_jobs.log"
# 验证脚本版本映射
declare -A SCRIPT_VERSIONS
SCRIPT_VERSIONS["monitor_emqx_service.sh"]="V2.2"
SCRIPT_VERSIONS["monitor_mysql_service.sh"]="V1.2"
SCRIPT_VERSIONS["monitor_redis_service.sh"]="V1.2"
SCRIPT_VERSIONS["monitor_external_api_services_v2.sh"]="V1.2"
SCRIPT_VERSIONS["monitor_inner_api_services.sh"]="V1.2"
SCRIPT_VERSIONS["backup_mysql_databases.sh"]="V1.1"
SCRIPT_VERSIONS["backup_mysql_logs.sh"]="V1.1"
SCRIPT_VERSIONS["backup_nginx_logs.sh"]="V1.1"
SCRIPT_VERSIONS["auto_clean_deleted_ubains_v3.sh"]="V3.0"
```
### 5.3 日志格式验证
```bash
# 验证日志输出包含以下信息
# - 时间戳格式:[YYYY-MM-DD HH:MM:SS]
# - 日志级别:INFO, WARNING, ERROR, SUCCESS
# - 操作描述:清晰的操作说明
# 示例:
[2026-03-30 12:00:00] [INFO] ===== 开始更新任务 =====
[2026-03-30 12:00:01] [INFO] 服务器: 192.168.1.100
[2026-03-30 12:00:02] [SUCCESS] 更新完成
```
---
## 六、测试计划
### 6.1 单元测试
| 测试项 | 测试方法 | 预期结果 |
|--------|----------|----------|
| 前置检查 | 源目录不存在 | 报错并中止 |
| 前置检查 | SSH连接失败 | 报错并中止 |
| 备份功能 | 执行备份 | 创建备份目录和文件 |
| 版本验证 | 版本号不匹配 | 记录警告但继续 |
| 更新功能 | 脚本更新 | 新脚本替换旧脚本 |
| 回滚功能 | 执行回滚 | 恢复备份脚本 |
### 6.2 集成测试
| 测试场景 | 操作步骤 | 预期结果 |
|----------|----------|----------|
| 本地更新 | 在本地执行更新脚本 | 所有脚本更新成功 |
| 远程更新 | 通过SSH更新远程服务器 | 远程脚本更新成功 |
| 批量更新 | 从服务器列表批量更新 | 所有服务器更新成功 |
| 版本不匹配 | 使用错误版本脚本 | 记录警告,继续更新 |
| 更新失败 | 脚本更新失败 | 自动回滚,记录错误 |
### 6.3 异常测试
| 测试项 | 测试方法 | 预期结果 |
|--------|----------|----------|
| 网络中断 | 更新过程中断开SSH | 记录错误,支持重试 |
| 权限不足 | 目标目录无写权限 | 报错并中止 |
| 磁盘满 | 备份目录磁盘满 | 报错并中止 |
| 脚本语法错误 | 使用语法错误的脚本 | 验证失败,自动回滚 |
---
## 七、部署步骤
### 7.1 脚本创建
```bash
# 创建更新脚本目录
mkdir -p 自动化部署脚本/x86架构/预定系统/一键更新
# 创建更新脚本文件
cat > 自动化部署脚本/x86架构/预定系统/一键更新/update_cron_jobs.sh << 'EOF'
[脚本内容]
EOF
# 设置执行权限
chmod +x 自动化部署脚本/x86架构/预定系统/一键更新/update_cron_jobs.sh
```
### 7.2 本地测试
```bash
# 干运行模式测试
./自动化部署脚本/x86架构/预定系统/一键更新/update_cron_jobs.sh --dry-run
# 确认模式测试
./自动化部署脚本/x86架构/预定系统/一键更新/update_cron_jobs.sh --confirm
```
### 7.3 远程测试
```bash
# 单台服务器测试
./自动化部署脚本/x86架构/预定系统/一键更新/update_cron_jobs.sh \
--host 192.168.1.100 \
--user root \
--confirm
```
---
## 八、回滚方案
### 8.1 自动回滚触发条件
- 版本验证失败
- 脚本语法检查失败
- 文件完整性校验失败
- 用户手动中止(Ctrl+C)
### 8.2 手动回滚步骤
```bash
# 方式1:使用回滚模式
./自动化部署脚本/x86架构/预定系统/一键更新/update_cron_jobs.sh \
--host 192.168.1.100 \
--rollback
# 方式2:手动回滚
# 1. 登录服务器
ssh root@192.168.1.100
# 2. 查找最新备份
ls -lt /opt/scripts/backup/
# 3. 恢复备份
cp /opt/scripts/backup/20260330_120000/monitor_emqx_service.sh.backup \
/opt/scripts/monitor_emqx_service.sh
# 4. 恢复crontab
crontab /opt/scripts/backup/20260330_120000/crontab.backup
```
---
## 九、验收标准
### 9.1 功能验收
- [ ] 前置检查能正确检测环境
- [ ] 备份功能能正确备份原有脚本和crontab
- [ ] 更新功能能正确替换脚本文件
- [ ] Crontab更新功能能正确更新定时任务
- [ ] 版本验证功能能正确验证脚本版本
- [ ] 回滚功能能正确恢复原有脚本
- [ ] 批量更新功能能正确处理多台服务器
### 9.2 远程执行验收
- [ ] 本地模式能正确更新本地服务器
- [ ] 远程模式能正确通过SSH更新远程服务器
- [ ] 批量模式能正确从列表文件读取服务器
### 9.3 异常处理验收
- [ ] 前置检查失败能正确中止执行
- [ ] 更新失败能自动回滚
- [ ] 网络中断能正确处理错误
### 9.4 日志验收
- [ ] 所有操作都有日志记录
- [ ] 日志格式统一规范
- [ ] 错误信息详细准确
- [ ] 报告内容完整详细
---
## 十、使用示例
### 10.1 本地更新示例
```bash
# 本地更新(脚本在同一台服务器)
cd 自动化部署脚本/x86架构/预定系统/一键更新
./update_cron_jobs.sh
# 输出示例:
==========================================
定时任务脚本一键更新工具
==========================================
更新时间: 2026-03-30 12:00:00
目标服务器: 本地
==========================================
[INFO] ===== 开始前置检查 =====
[INFO] 源脚本目录检查通过
[INFO] ===== 开始备份原有脚本 =====
[INFO] 已备份: monitor_emqx_service.sh
...
[SUCCESS] 更新完成
==========================================
```
### 10.2 远程更新示例
```bash
# 远程单台服务器更新
./update_cron_jobs.sh --host 192.168.1.100 --user root
# 批量服务器更新
./update_cron_jobs.sh --batch servers.txt
# 确认模式更新
./update_cron_jobs.sh --host 192.168.1.100 --confirm
# 干运行模式(仅检查)
./update_cron_jobs.sh --host 192.168.1.100 --dry-run
```
---
## 需求规范
- 代码规范:Docs/PRD/01规范文档/_PRD_规范文档_代码规范.md
- 问题总结:Docs/PRD/01规范文档/_PRD_问题总结_记录文档.md
- 方法总结:Docs/PRD/01规范文档/_PRD_方法总结_记录文档.md
- 文档规范:Docs/PRD/01规范文档/_PRD_规范文档_文档规范.md
- 测试规范:Docs/PRD/01规范文档/_PRD_规范文档_测试规范.md
#!/bin/bash
#===============================================================================
# 脚本名称:update_cron_jobs.sh
# 功能描述:预定系统定时任务脚本一键更新工具
# 版本:V1.3
# 创建日期:2026-03-30
# 更新日期:2026-03-30
# 基于文档:_PRD_预定系统一键更新定时任务脚本需求文档.md
#
# 支持功能:
# 1. 自动备份原有脚本和crontab配置
# 2. 安全、原子地替换脚本文件
# 3. 自动更新crontab定时任务配置(10分钟间隔)
# 4. 更新后自动验证脚本版本
# 5. 失败时自动回滚到备份版本
# 6. 支持本地和远程更新模式
# 7. 支持批量服务器更新
#
# 更新日志:
# V1.3 (2026-03-30):
# - 修复crontab重复问题(改进grep过滤模式,使用扩展正则表达式)
# - 添加废弃脚本清理功能(自动清理旧版本脚本文件)
# - 修复SCP命令缺少连接复用选项的问题
# V1.2 (2026-03-30):
# - 添加SSH连接复用(ControlMaster)减少密码输入次数
# - 所有SSH/SCP调用统一使用连接复用选项
# V1.1 (2026-03-30):
# - 修复版本提取逻辑(使用sed代替awk正确提取中文版本号)
# - 修复远程更新输出解析(正确捕获并处理更新结果)
# - 移除重复的远程更新代码块
# V1.0 (2026-03-30):
# - 初始版本
#
# 使用方法:
# chmod +x update_cron_jobs.sh
# ./update_cron_jobs.sh [选项]
#
# 选项:
# --host <地址> 远程服务器地址(默认本地)
# --user <用户> SSH用户名(默认root)
# --batch <文件> 服务器列表文件
# --confirm 执行前确认
# --dry-run 干运行模式(仅检查不更新)
# --rollback 回滚模式
# --help 显示帮助信息
#
# 定时任务配置:
# 监控类:每10分钟执行(错峰间隔1分钟)
# 备份类:每日凌晨1-4点执行
#===============================================================================
#-------------------------------------------------------------------------------
# 配置参数
#-------------------------------------------------------------------------------
# 脚本源目录(假设更新脚本与定时脚本在同一目录)
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
# 远程服务器配置
REMOTE_MODE=false
REMOTE_HOST=""
REMOTE_USER="root"
REMOTE_PASSWORD=""
# 目标目录配置
REMOTE_SCRIPT_DIR="/opt/scripts"
BACKUP_DIR="/opt/scripts/backup"
LOG_DIR="/var/log/scripts"
LOG_FILE="$LOG_DIR/update_cron_jobs.log"
# 备份配置
BACKUP_RETENTION_DAYS=7
# 操作模式配置
CONFIRM_MODE=false
DRY_RUN=false
ROLLBACK_MODE=false
BATCH_MODE=false
SERVERS_FILE=""
# 脚本版本映射
declare -A SCRIPT_VERSIONS
SCRIPT_VERSIONS["monitor_emqx_service.sh"]="V2.2"
SCRIPT_VERSIONS["monitor_mysql_service.sh"]="V1.2"
SCRIPT_VERSIONS["monitor_redis_service.sh"]="V1.2"
SCRIPT_VERSIONS["monitor_external_api_services_v2.sh"]="V1.2"
SCRIPT_VERSIONS["monitor_inner_api_services.sh"]="V1.2"
SCRIPT_VERSIONS["backup_mysql_databases.sh"]="V1.1"
SCRIPT_VERSIONS["backup_mysql_logs.sh"]="V1.2"
SCRIPT_VERSIONS["backup_nginx_logs.sh"]="V1.2"
SCRIPT_VERSIONS["auto_clean_deleted_ubains_v3.sh"]="V3.1"
# 已废弃的旧脚本文件(需要清理)
declare -a OBSOLETE_SCRIPTS=(
"clean_deleted_ubains_v2.sh"
"monitor_emqx_service.sh.old"
"monitor_mysql_service.sh.old"
"monitor_redis_service.sh.old"
)
# 更新统计
declare -i UPDATE_SUCCESS_COUNT=0
declare -i UPDATE_FAILED_COUNT=0
declare -a UPDATE_SUCCESS_LIST=()
declare -a UPDATE_FAILED_LIST=()
#-------------------------------------------------------------------------------
# 工具函数
#-------------------------------------------------------------------------------
# 日志记录函数
log() {
local level="$1"
local message="$2"
local timestamp
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
if [ "$REMOTE_MODE" = true ]; then
# 远程模式:日志同时记录到本地和远程
echo "[$timestamp] [$level] $message" | tee -a "$LOG_FILE"
else
# 本地模式:日志记录到本地
echo "[$timestamp] [$level] $message" | tee -a "$LOG_FILE"
fi
}
# 远程执行命令
remote_exec() {
local command="$1"
if [ "$REMOTE_MODE" = true ]; then
ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no -o ControlMaster=auto -o ControlPath=/tmp/ssh_mux_%h_%p_%r -o ControlPersist=300s "${REMOTE_USER}@${REMOTE_HOST}" "$command"
else
eval "$command"
fi
}
# 远程复制文件
remote_copy() {
local source="$1"
local dest="$2"
if [ "$REMOTE_MODE" = true ]; then
scp -o ConnectTimeout=10 -o StrictHostKeyChecking=no -o ControlMaster=auto -o ControlPath=/tmp/ssh_mux_%h_%p_%r -o ControlPersist=300s "$source" "${REMOTE_USER}@${REMOTE_HOST}:${dest}"
else
cp "$source" "$dest"
fi
}
#-------------------------------------------------------------------------------
# 核心功能函数
#-------------------------------------------------------------------------------
# 显示帮助信息
show_help() {
cat << EOF
========================================
定时任务脚本一键更新工具 V1.0
========================================
使用方法:
$0 [选项]
选项:
--host <地址> 远程服务器地址(默认本地更新)
--user <用户> SSH用户名(默认root)
--password <密码> SSH密码
--batch <文件> 服务器列表文件(批量更新)
--confirm 执行前确认
--dry-run 干运行模式(仅检查不更新)
--rollback 回滚到上一版本
--help 显示帮助信息
使用示例:
# 本地更新
$0
# 远程单台服务器更新
$0 --host 192.168.1.100 --user root
# 批量更新
$0 --batch servers.txt
# 确认模式更新
$0 --host 192.168.1.100 --confirm
# 干运行(仅检查)
$0 --dry-run
# 回滚
$0 --rollback
服务器列表文件格式:
192.168.1.100:root:password
192.168.1.101:root:password
192.168.1.102:root:password
========================================
EOF
}
# 前置检查
check_prerequisites() {
log "INFO" "========== 开始前置检查 =========="
# 1. 检查脚本源目录
if [ ! -d "$SCRIPT_DIR" ]; then
log "ERROR" "源脚本目录不存在: $SCRIPT_DIR"
log "ERROR" "请确保脚本位于: $(dirname "$0")/../定时脚本/"
return 1
fi
log "INFO" "源脚本目录检查通过: $SCRIPT_DIR"
# 2. 检查SSH连接(远程模式)
if [ "$REMOTE_MODE" = true ]; then
if ! remote_exec "echo 'ping'" >/dev/null 2>&1; then
log "ERROR" "无法连接到远程服务器: ${REMOTE_USER}@${REMOTE_HOST}"
log "ERROR" "请检查网络连接、用户名和密码"
return 1
fi
log "INFO" "SSH连接检查通过: ${REMOTE_USER}@${REMOTE_HOST}"
fi
# 3. 检查目标目录权限
local check_cmd="mkdir -p $REMOTE_SCRIPT_DIR 2>/dev/null && [ -w $REMOTE_SCRIPT_DIR ]"
if ! remote_exec "$check_cmd"; then
log "ERROR" "目标目录权限不足或无法创建: $REMOTE_SCRIPT_DIR"
return 1
fi
log "INFO" "目标目录权限检查通过"
# 4. 确保日志目录存在
if [ "$REMOTE_MODE" = true ]; then
remote_exec "mkdir -p $LOG_DIR"
else
mkdir -p "$LOG_DIR"
fi
# 5. 验证脚本文件
local missing_scripts=()
for script in "${!SCRIPT_VERSIONS[@]}"; do
local script_path="$SCRIPT_DIR/$script"
if [ ! -f "$script_path" ]; then
missing_scripts+=("$script")
fi
done
if [ ${#missing_scripts[@]} -gt 0 ]; then
log "ERROR" "以下脚本文件不存在:"
for script in "${missing_scripts[@]}"; do
log "ERROR" " - $script"
done
return 1
fi
log "INFO" "脚本文件检查通过 (${#SCRIPT_VERSIONS[@]} 个文件)"
log "INFO" "========== 前置检查通过 =========="
return 0
}
# 创建必要目录
create_directories() {
log "INFO" "创建必要目录"
local dirs=(
"$REMOTE_SCRIPT_DIR"
"$LOG_DIR"
"$BACKUP_DIR"
"/var/log/scripts/external_api_state"
"/var/log/scripts/inner_api_state"
)
for dir in "${dirs[@]}"; do
remote_exec "mkdir -p $dir"
done
# 设置权限
remote_exec "chmod 755 $LOG_DIR /var/log/scripts/*_state 2>/dev/null || true"
}
# 备份原有脚本
backup_scripts() {
log "INFO" "========== 开始备份原有脚本 =========="
# 创建备份目录
local backup_timestamp=$(date +%Y%m%d_%H%M%S)
local backup_base_dir="$BACKUP_DIR/$backup_timestamp"
remote_exec "mkdir -p $backup_base_dir"
# 备份每个脚本
local backed_count=0
for script in "${!SCRIPT_VERSIONS[@]}"; do
local target_path="$REMOTE_SCRIPT_DIR/$script"
local backup_path="$backup_base_dir/${script}.backup"
# 检查目标脚本是否存在
if remote_exec "test -f $target_path"; then
remote_exec "cp $target_path $backup_path"
log "INFO" "已备份: $script"
((backed_count++))
else
log "WARNING" "脚本不存在,跳过备份: $script"
fi
done
# 备份crontab
backup_crontab "$backup_timestamp"
# 记录备份元数据
local metadata_file="$backup_base_dir/metadata.txt"
local metadata_content="========================================
备份元数据
========================================
备份时间: $(date '+%Y-%m-%d %H:%M:%S')
备份用户: $(whoami)
备份服务器: ${REMOTE_HOST:-localhost}
操作模式: ${REMOTE_MODE:+远程更新}
脚本版本:
"
for script in "${!SCRIPT_VERSIONS[@]}"; do
metadata_content="${metadata_content} ${script}=${SCRIPT_VERSIONS[$script]}\n"
done
if [ "$REMOTE_MODE" = true ]; then
echo -e "$metadata_content" | ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no -o ControlMaster=auto -o ControlPath=/tmp/ssh_mux_%h_%p_%r -o ControlPersist=300s "${REMOTE_USER}@${REMOTE_HOST}" "cat > $metadata_file"
else
echo -e "$metadata_content" > "$metadata_file"
fi
log "INFO" "备份完成,备份位置: $backup_base_dir"
log "INFO" "========== 备份完成 =========="
return 0
}
# 备份crontab
backup_crontab() {
local backup_timestamp="$1"
local crontab_backup="$BACKUP_DIR/$backup_timestamp/crontab.backup"
log "INFO" "备份crontab配置"
if [ "$REMOTE_MODE" = true ]; then
ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no -o ControlMaster=auto -o ControlPath=/tmp/ssh_mux_%h_%p_%r -o ControlPersist=300s "${REMOTE_USER}@${REMOTE_HOST}" "crontab -l > $crontab_backup 2>/dev/null || true"
else
crontab -l > "$crontab_backup" 2>/dev/null || true
fi
log "INFO" "crontab备份完成"
}
# 更新脚本文件
update_scripts() {
log "INFO" "========== 开始更新脚本文件 =========="
local temp_dir="/opt/scripts/.tmp_update"
# 创建临时目录
remote_exec "mkdir -p $temp_dir"
# 上传/复制脚本到临时目录
for script in "${!SCRIPT_VERSIONS[@]}"; do
local script_path="$SCRIPT_DIR/$script"
local temp_script="$temp_dir/$script"
if [ "$REMOTE_MODE" = true ]; then
scp -o ConnectTimeout=10 -o StrictHostKeyChecking=no -o ControlMaster=auto -o ControlPath=/tmp/ssh_mux_%h_%p_%r -o ControlPersist=300s "$script_path" "${REMOTE_USER}@${REMOTE_HOST}:${temp_script}" 2>/dev/null
else
cp "$script_path" "$temp_script"
fi
done
# 远程执行更新操作
if [ "$REMOTE_MODE" = true ]; then
# 捕获并解析远程更新输出
local update_output=$(ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no -o ControlMaster=auto -o ControlPath=/tmp/ssh_mux_%h_%p_%r -o ControlPersist=300s "${REMOTE_USER}@${REMOTE_HOST}" << 'ENDSSH'
cd /opt/scripts/.tmp_update 2>/dev/null || exit 1
# 设置权限并验证
for script in *; do
chmod +x "$script"
# 验证脚本语法
if bash -n "$script" 2>/dev/null; then
mv -f "$script" "/opt/scripts/"
echo "SUCCESS:$script"
else
echo "FAILED:$script:语法验证失败"
rm -f "$script"
fi
done
# 清理临时目录
cd / && rm -rf /opt/scripts/.tmp_update
ENDSSH
)
# 解析更新输出
while IFS= read -r line; do
if [[ $line == SUCCESS:* ]]; then
local script="${line#SUCCESS:}"
((UPDATE_SUCCESS_COUNT++))
UPDATE_SUCCESS_LIST+=("$script")
elif [[ $line == FAILED:* ]]; then
local script="${line#FAILED:}"
script="${script%:*}" # 移除错误信息
((UPDATE_FAILED_COUNT++))
UPDATE_FAILED_LIST+=("$script")
fi
done <<< "$update_output"
# 验证版本(仅对成功的脚本)
for script in "${UPDATE_SUCCESS_LIST[@]}"; do
local target_path="$REMOTE_SCRIPT_DIR/$script"
local expected_version="${SCRIPT_VERSIONS[$script]}"
# 使用sed正确提取版本号(去除"# 版本:"前缀)
local actual_version=$(ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no -o ControlMaster=auto -o ControlPath=/tmp/ssh_mux_%h_%p_%r -o ControlPersist=300s "${REMOTE_USER}@${REMOTE_HOST}" "grep '^# 版本:' $target_path 2>/dev/null | sed 's/^# 版本://'")
if [ "$actual_version" = "$expected_version" ]; then
log "SUCCESS" "已更新: $script ($actual_version)"
else
log "WARNING" "$script 版本变化 (期望: $expected_version, 实际: $actual_version)"
fi
done
else
# 本地模式
cd "$temp_dir" || exit 1
for script in *; do
chmod +x "$script"
if bash -n "$script" 2>/dev/null; then
mv -f "$script" "$REMOTE_SCRIPT_DIR/"
log "SUCCESS" "已更新: $script"
((UPDATE_SUCCESS_COUNT++))
UPDATE_SUCCESS_LIST+=("$script")
else
log "ERROR" "$script 语法验证失败"
((UPDATE_FAILED_COUNT++))
UPDATE_FAILED_LIST+=("$script")
fi
done
cd - > /dev/null
rm -rf "$temp_dir"
fi
if [ $UPDATE_FAILED_COUNT -eq 0 ]; then
log "INFO" "========== 脚本更新完成 (${UPDATE_SUCCESS_COUNT}/${#SCRIPT_VERSIONS[@]}) =========="
return 0
else
log "ERROR" "========== 脚本更新失败 (${UPDATE_FAILED_COUNT}个失败) =========="
return 1
fi
}
# 更新crontab配置
update_crontab() {
log "INFO" "========== 开始更新crontab配置 =========="
# 新的crontab配置
local new_cron="# 预定系统定时任务配置(每 10 分钟,错峰执行)
*/10 * * * * $REMOTE_SCRIPT_DIR/monitor_emqx_service.sh
*/10 * * * * sleep 60 && $REMOTE_SCRIPT_DIR/monitor_mysql_service.sh
*/10 * * * * sleep 120 && $REMOTE_SCRIPT_DIR/monitor_redis_service.sh
*/10 * * * * sleep 180 && $REMOTE_SCRIPT_DIR/monitor_external_api_services_v2.sh
*/10 * * * * sleep 240 && $REMOTE_SCRIPT_DIR/monitor_inner_api_services.sh
# 数据备份类(每日凌晨)
0 1 * * * $REMOTE_SCRIPT_DIR/backup_mysql_databases.sh
0 2 * * * $REMOTE_SCRIPT_DIR/backup_mysql_logs.sh
0 3 * * * $REMOTE_SCRIPT_DIR/backup_nginx_logs.sh
# 系统维护类(每日凌晨)
0 4 * * * $REMOTE_SCRIPT_DIR/auto_clean_deleted_ubains_v3.sh
"
if [ "$REMOTE_MODE" = true ]; then
ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no -o ControlMaster=auto -o ControlPath=/tmp/ssh_mux_%h_%p_%r -o ControlPersist=300s "${REMOTE_USER}@${REMOTE_HOST}" << ENDSSH
# 移除旧的预定系统cron任务(匹配 /opt/scripts/ 和相关注释)
crontab -l 2>/dev/null | grep -vE "(/opt/scripts/预定系统|/opt/scripts/monitor_|/opt/scripts/backup_|/opt/scripts/auto_clean|# ========== .*类|# ============================================)" > /tmp/crontab_new.tmp || true
# 添加新的cron任务
echo "$new_cron" >> /tmp/crontab_new.tmp
# 安装新的crontab
crontab /tmp/crontab_new.tmp
rm -f /tmp/crontab_new.tmp
echo "SUCCESS:crontab更新完成"
ENDSSH
else
# 移除旧的预定系统cron任务(匹配 /opt/scripts/ 和相关注释)
crontab -l 2>/dev/null | grep -vE "(/opt/scripts/预定系统|/opt/scripts/monitor_|/opt/scripts/backup_|/opt/scripts/auto_clean|# ========== .*类|# ============================================)" > /tmp/crontab_new.tmp || true
# 添加新的cron任务
echo "$new_cron" >> /tmp/crontab_new.tmp
# 安装新的crontab
crontab /tmp/crontab_new.tmp
rm -f /tmp/crontab_new.tmp
fi
log "INFO" "crontab配置已更新为每10分钟间隔"
log "INFO" "========== crontab更新完成 =========="
return 0
}
# 验证更新
verify_update() {
log "INFO" "========== 开始版本验证 =========="
local verify_failed=0
for script in "${!SCRIPT_VERSIONS[@]}"; do
local expected_version="${SCRIPT_VERSIONS[$script]}"
local target_path="${REMOTE_SCRIPT_DIR}/${script}"
local actual_version
if [ "$REMOTE_MODE" = true ]; then
actual_version=$(ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no -o ControlMaster=auto -o ControlPath=/tmp/ssh_mux_%h_%p_%r -o ControlPersist=300s "${REMOTE_USER}@${REMOTE_HOST}" "grep '^# 版本:' '$target_path' 2>/dev/null | sed 's/^# 版本://' || echo 'UNKNOWN'")
else
actual_version=$(grep "^# 版本:" "$target_path" 2>/dev/null | sed 's/^# 版本://' || echo "UNKNOWN")
fi
if [ "$actual_version" = "$expected_version" ]; then
log "SUCCESS" "$script 版本验证通过 ($actual_version)"
else
log "ERROR" "$script 版本不匹配 (期望: $expected_version, 实际: $actual_version)"
verify_failed=1
fi
done
if [ $verify_failed -eq 0 ]; then
log "INFO" "========== 版本验证通过 =========="
return 0
else
log "ERROR" "========== 版本验证失败 =========="
return 1
fi
}
# 回滚更新
rollback_update() {
log "WARNING" "========== 开始回滚操作 =========="
# 查找最新备份目录
local latest_backup
if [ "$REMOTE_MODE" = true ]; then
latest_backup=$(ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no -o ControlMaster=auto -o ControlPath=/tmp/ssh_mux_%h_%p_%r -o ControlPersist=300s "${REMOTE_USER}@${REMOTE_HOST}" "ls -t $BACKUP_DIR 2>/dev/null | head -1")
else
latest_backup=$(ls -t "$BACKUP_DIR" 2>/dev/null | head -1)
fi
if [ -z "$latest_backup" ]; then
log "ERROR" "未找到备份目录,无法回滚"
return 1
fi
log "INFO" "使用备份: $latest_backup"
# 恢复脚本
for script in "${!SCRIPT_VERSIONS[@]}"; do
local backup_path="$BACKUP_DIR/$latest_backup/${script}.backup"
local target_path="$REMOTE_SCRIPT_DIR/$script"
if [ "$REMOTE_MODE" = true ]; then
if ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no -o ControlMaster=auto -o ControlPath=/tmp/ssh_mux_%h_%p_%r -o ControlPersist=300s "${REMOTE_USER}@${REMOTE_HOST}" "test -f $backup_path"; then
ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no -o ControlMaster=auto -o ControlPath=/tmp/ssh_mux_%h_%p_%r -o ControlPersist=300s "${REMOTE_USER}@${REMOTE_HOST}" "cp $backup_path $target_path"
log "INFO" "已恢复: $script"
fi
else
if [ -f "$backup_path" ]; then
cp "$backup_path" "$target_path"
log "INFO" "已恢复: $script"
fi
fi
done
# 恢复crontab
local crontab_backup="$BACKUP_DIR/$latest_backup/crontab.backup"
if [ "$REMOTE_MODE" = true ]; then
if ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no -o ControlMaster=auto -o ControlPath=/tmp/ssh_mux_%h_%p_%r -o ControlPersist=300s "${REMOTE_USER}@${REMOTE_HOST}" "test -f $crontab_backup"; then
ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no -o ControlMaster=auto -o ControlPath=/tmp/ssh_mux_%h_%p_%r -o ControlPersist=300s "${REMOTE_USER}@${REMOTE_HOST}" "crontab $crontab_backup"
log "INFO" "已恢复crontab配置"
fi
else
if [ -f "$crontab_backup" ]; then
crontab "$crontab_backup"
log "INFO" "已恢复crontab配置"
fi
fi
log "INFO" "========== 回滚完成 =========="
return 0
}
# 生成更新报告
generate_report() {
log "INFO" "========== 生成更新报告 =========="
local report_file="$LOG_DIR/update_report_$(date +%Y%m%d_%H%M%S).txt"
{
echo "========================================"
echo " 定时任务脚本更新报告"
echo "========================================"
echo "更新时间: $(date '+%Y-%m-%d %H:%M:%S')"
echo "目标服务器: ${REMOTE_HOST:-本地}"
echo ""
echo "更新统计:"
echo " 待更新脚本: ${#SCRIPT_VERSIONS[@]} 个"
echo " 更新成功: $UPDATE_SUCCESS_COUNT 个"
echo " 更新失败: $UPDATE_FAILED_COUNT 个"
echo ""
echo "脚本版本:"
for script in "${!SCRIPT_VERSIONS[@]}"; do
echo " $script=${SCRIPT_VERSIONS[$script]}"
done
if [ ${#UPDATE_SUCCESS_LIST[@]} -gt 0 ]; then
echo ""
echo "更新成功列表:"
for script in "${UPDATE_SUCCESS_LIST[@]}"; do
echo " ✓ $script"
done
fi
if [ ${#UPDATE_FAILED_LIST[@]} -gt 0 ]; then
echo ""
echo "更新失败列表:"
for script in "${UPDATE_FAILED_LIST[@]}"; do
echo " ✗ $script"
done
fi
echo ""
echo "备份位置: $BACKUP_DIR/$(date +%Y%m%d_%H%M%S)"
echo "========================================"
} | tee "$report_file"
log "INFO" "报告已生成: $report_file"
log "INFO" "========== 报告生成完成 =========="
}
# 清理过期备份
clean_old_backups() {
log "INFO" "清理超过 $BACKUP_RETENTION_DAYS 天的旧备份"
if [ "$REMOTE_MODE" = true ]; then
ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no -o ControlMaster=auto -o ControlPath=/tmp/ssh_mux_%h_%p_%r -o ControlPersist=300s "${REMOTE_USER}@${REMOTE_HOST}" "find $BACKUP_DIR -maxdepth 1 -type d -name '??????????_??????' -mtime +$BACKUP_RETENTION_DAYS -exec rm -rf {} + 2>/dev/null || true"
else
find "$BACKUP_DIR" -maxdepth 1 -type d -name '??????????_??????' -mtime +$BACKUP_RETENTION_DAYS -exec rm -rf {} + 2>/dev/null || true
fi
}
# 清理废弃的旧脚本文件
clean_obsolete_scripts() {
log "INFO" "========== 清理废弃的旧脚本文件 =========="
local cleaned_count=0
for old_script in "${OBSOLETE_SCRIPTS[@]}"; do
local script_path="$REMOTE_SCRIPT_DIR/$old_script"
if remote_exec "test -f $script_path"; then
# 备份旧脚本到backup目录
local backup_name="${old_script}.obsolete.$(date +%Y%m%d_%H%M%S)"
remote_exec "mv $script_path $BACKUP_DIR/$backup_name"
log "INFO" "已移除废弃脚本: $old_script (备份至: $backup_name)"
((cleaned_count++))
fi
done
if [ $cleaned_count -eq 0 ]; then
log "INFO" "没有发现废弃脚本"
else
log "INFO" "已清理 $cleaned_count 个废弃脚本"
fi
log "INFO" "========== 旧脚本清理完成 =========="
}
#-------------------------------------------------------------------------------
# 主流程
#-------------------------------------------------------------------------------
# 解析命令行参数
parse_arguments() {
while [ $# -gt 0 ]; do
case $1 in
--host)
shift
REMOTE_MODE=true
REMOTE_HOST="$1"
shift
;;
--user)
shift
REMOTE_USER="$1"
shift
;;
--password)
shift
REMOTE_PASSWORD="$1"
shift
;;
--batch)
shift
BATCH_MODE=true
SERVERS_FILE="$1"
shift
;;
--confirm)
CONFIRM_MODE=true
shift
;;
--dry-run)
DRY_RUN=true
shift
;;
--rollback)
ROLLBACK_MODE=true
shift
;;
--help|-h)
show_help
exit 0
;;
*)
echo "未知参数: $1"
echo "使用 --help 查看帮助信息"
exit 1
;;
esac
done
}
# 确认模式提示
confirm_action() {
echo "========================================"
echo " 即将执行更新操作"
echo "========================================"
echo "目标服务器: ${REMOTE_HOST:-本地}"
echo "待更新脚本: ${#SCRIPT_VERSIONS[@]} 个"
echo "备份位置: $BACKUP_DIR/$(date +%Y%m%d_%H%M%S)"
echo "========================================"
echo ""
echo "是否继续? [y/N]"
read -r response
if [[ ! "$response" =~ ^[Yy]$ ]]; then
echo "操作已取消"
exit 0
fi
}
# 批量更新
batch_update() {
local servers_file="$1"
if [ ! -f "$servers_file" ]; then
log "ERROR" "服务器列表文件不存在: $servers_file"
return 1
fi
log "INFO" "========== 批量更新模式 =========="
log "INFO" "服务器列表: $servers_file"
local total_servers=0
local success_servers=0
local failed_servers=0
while IFS=':' read -r host user password rest; do
# 跳过空行和注释行
[ -z "$host" ] && continue
[[ "$host" =~ ^#.* ]] && continue
((total_servers++))
echo ""
echo "=========================================="
echo "处理服务器: $host ($user)"
echo "=========================================="
# 设置远程模式
REMOTE_MODE=true
REMOTE_HOST="$host"
REMOTE_USER="$user"
# 测试连接
if ! ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no "${REMOTE_USER}@${REMOTE_HOST}" "echo 'ping'" >/dev/null 2>&1; then
log "ERROR" "无法连接到服务器: $host,跳过"
((failed_servers++))
continue
fi
# 执行更新
if main; then
((success_servers++))
echo "✓ $host 更新成功"
else
((failed_servers++))
echo "✗ $host 更新失败"
fi
# 重置统计
UPDATE_SUCCESS_COUNT=0
UPDATE_FAILED_COUNT=0
UPDATE_SUCCESS_LIST=()
UPDATE_FAILED_LIST=()
done < "$servers_file"
echo ""
echo "=========================================="
echo " 批量更新完成"
echo "=========================================="
echo "总服务器数: $total_servers"
echo "更新成功: $success_servers"
echo "更新失败: $failed_servers"
echo "=========================================="
return 0
}
# 主函数
main() {
# 记录开始时间
local start_time=$(date +%s)
# 解析参数
parse_arguments "$@"
# 输出开始信息
log "INFO" "=========================================="
log "INFO" " 定时任务脚本一键更新工具"
log "INFO" "=========================================="
log "INFO" "更新时间: $(date '+%Y-%m-%d %H:%M:%S')"
log "INFO" "目标服务器: ${REMOTE_HOST:-本地}"
log "INFO" "=========================================="
# 检查是否为回滚模式
if [ "$ROLLBACK_MODE" = true ]; then
rollback_update
local end_time=$(date +%s)
local duration=$((end_time - start_time))
log "INFO" "操作完成,耗时: ${duration}秒"
return 0
fi
# 检查是否为批量模式
if [ "$BATCH_MODE" = true ]; then
batch_update "$SERVERS_FILE"
return $?
fi
# 确认模式
if [ "$CONFIRM_MODE" = true ]; then
confirm_action
fi
# 干运行模式
if [ "$DRY_RUN" = true ]; then
log "INFO" "========== 干运行模式 =========="
check_prerequisites
log "INFO" "========== 干运行完成 =========="
return 0
fi
# 执行更新流程
check_prerequisites || { log "ERROR" "前置检查失败"; exit 1; }
create_directories
backup_scripts || { log "ERROR" "备份失败"; exit 1; }
update_scripts || { log "ERROR" "更新失败,执行回滚"; rollback_update; exit 1; }
update_crontab || { log "ERROR" "crontab更新失败"; exit 1; }
verify_update || { log "ERROR" "验证失败,执行回滚"; rollback_update; exit 1; }
clean_obsolete_scripts
generate_report
clean_old_backups
# 计算执行时间
local end_time=$(date +%s)
local duration=$((end_time - start_time))
log "INFO" "=========================================="
log "INFO" " 更新完成"
log "INFO" "=========================================="
log "INFO" "更新成功: $UPDATE_SUCCESS_COUNT 个"
log "INFO" "更新失败: $UPDATE_FAILED_COUNT 个"
log "INFO" "执行耗时: ${duration}秒"
log "INFO" "=========================================="
return 0
}
#-------------------------------------------------------------------------------
# 脚本入口
#-------------------------------------------------------------------------------
# 执行主函数
main "$@"
# 定时任务脚本一键更新工具 - 使用说明
> 版本:V1.3
> 更新日期:2026-03-30
> 脚本文件:`update_cron_jobs.sh`
> **更新日志**:
> - **V1.3 (2026-03-30)**:
> - 修复crontab重复问题(改进grep过滤模式)
> - 添加废弃脚本清理功能(自动清理旧版本脚本文件)
> - 修复SCP命令缺少连接复用选项的问题
> - **V1.2 (2026-03-30)**:
> - 添加SSH连接复用(ControlMaster)减少密码输入次数
> - 所有SSH/SCP调用统一使用连接复用选项
> - **V1.1 (2026-03-30)**:
> - 修复版本提取逻辑(使用sed代替awk正确提取中文版本号)
> - 修复远程更新输出解析(正确捕获并处理更新结果)
> - 移除重复的远程更新代码块
> - 更新所有定时脚本版本号(+0.1)
---
## 快速开始
### 本地更新(最常用)
```bash
cd 自动化部署脚本/x86架构/预定系统/一键更新
./update_cron_jobs.sh
```
### 远程更新服务器
```bash
./update_cron_jobs.sh --host 192.168.1.100 --user root
```
---
## 命令参数
| 参数 | 说明 | 示例 |
|------|------|------|
| `--host <IP>` | 远程服务器地址 | `--host 192.168.1.100` |
| `--user <用户>` | SSH用户名(默认root) | `--user admin` |
| `--batch <文件>` | 批量更新服务器列表 | `--batch servers.txt` |
| `--confirm` | 执行前确认 | `--confirm` |
| `--dry-run` | 干运行(仅检查不更新) | `--dry-run` |
| `--rollback` | 回滚到上一版本 | `--rollback` |
| `--help` | 显示帮助信息 | `--help` |
---
## 使用场景
### 场景1:更新单台本地服务器
```bash
./update_cron_jobs.sh
```
### 场景2:更新单台远程服务器
```bash
./update_cron_jobs.sh --host 192.168.1.100 --user root
```
### 场景3:批量更新多台服务器
```bash
# 1. 创建服务器列表文件
cat > servers.txt << EOF
192.168.1.100:root:password
192.168.1.101:root:password
192.168.1.102:root:password
EOF
# 2. 执行批量更新
./update_cron_jobs.sh --batch servers.txt
```
### 场景4:确认模式更新(推荐)
```bash
./update_cron_jobs.sh --host 192.168.1.100 --confirm
```
### 场景5:仅检查不更新
```bash
./update_cron_jobs.sh --dry-run
```
### 场景6:更新失败回滚
```bash
./update_cron_jobs.sh --rollback
```
---
## 更新内容
### 脚本列表
| 序号 | 脚本名称 | 版本 | 说明 |
|-----|---------|------|------|
| 1 | monitor_emqx_service.sh | V2.2 | EMQX服务监控 |
| 2 | monitor_mysql_service.sh | V1.2 | MySQL服务监控 |
| 3 | monitor_redis_service.sh | V1.2 | Redis服务监控 |
| 4 | monitor_external_api_services_v2.sh | V1.2 | 外部API服务监控 |
| 5 | monitor_inner_api_services.sh | V1.2 | 内部API服务监控 |
| 6 | backup_mysql_databases.sh | V1.1 | MySQL数据库备份 |
| 7 | backup_mysql_logs.sh | V1.2 | MySQL日志备份 |
| 8 | backup_nginx_logs.sh | V1.2 | Nginx日志备份 |
| 9 | auto_clean_deleted_ubains_v3.sh | V3.1 | 已删除文件清理 |
### 自动更新内容
- ✅ 脚本文件替换
- ✅ 执行权限设置(755)
- ✅ Crontab配置更新(10分钟间隔)
- ✅ 日志轮转机制(5MB轮转、保留30天)
- ✅ PID锁机制(防止并发执行)
- ✅ 自动清理废弃脚本文件(如 clean_deleted_ubains_v2.sh)
---
## Crontab 配置说明
### 更新后的定时任务
```bash
# 监控类:每 10 分钟执行,错峰间隔 1 分钟
*/10 * * * * /opt/scripts/monitor_emqx_service.sh # 0, 10, 20...
*/10 * * * * sleep 60 && /opt/scripts/monitor_mysql_service.sh # 1, 11, 21...
*/10 * * * * sleep 120 && /opt/scripts/monitor_redis_service.sh # 2, 12, 22...
*/10 * * * * sleep 180 && /opt/scripts/monitor_external_api_services_v2.sh # 3, 13, 23...
*/10 * * * * sleep 240 && /opt/scripts/monitor_inner_api_services.sh # 4, 14, 24...
# 备份类:每日凌晨执行
0 1 * * * /opt/scripts/backup_mysql_databases.sh
0 2 * * * /opt/scripts/backup_mysql_logs.sh
0 3 * * * /opt/scripts/backup_nginx_logs.sh
# 维护类:每日凌晨执行
0 4 * * * /opt/scripts/auto_clean_deleted_ubains_v3.sh
```
---
## 自动备份机制
### 备份位置
```
/opt/scripts/backup/
├── 20260330_120000/
│ ├── monitor_emqx_service.sh.backup
│ ├── monitor_mysql_service.sh.backup
│ ├── crontab.backup
│ └── metadata.txt
└── 20260329_150000/
└── ...
```
### 备份保留期
- 自动清理超过 **7天** 的备份
- 保留最新的备份用于回滚
---
## 更新报告
### 报告位置
```
/var/log/scripts/update_report_YYYYMMDD_HHMMSS.txt
```
### 报告内容
- 更新时间
- 更新服务器
- 更新统计(成功/失败数量)
- 脚本版本列表
- 更新成功/失败列表
- 备份位置
---
## 故障排查
### 问题1:远程更新需要多次输入密码
```bash
# 说明:首次SSH连接时需要输入密码,后续会复用连接(ControlMaster)
# 连接复用有效期:300秒(5分钟)
# 如需完全免密,建议配置SSH密钥认证
ssh-keygen -t rsa -b 4096
ssh-copy-id root@192.168.1.100
```
### 问题2:连接远程服务器失败
```bash
# 检查SSH连接
ssh root@192.168.1.100 "echo 'ping'"
# 检查防火墙
telnet 192.168.1.100 22
```
### 问题3:crontab出现重复任务
```bash
# V1.3版本已自动修复此问题,如仍有重复可手动清理:
crontab -l | grep -vE "(/opt/scripts/预定系统|/opt/scripts/monitor_|/opt/scripts/backup_|# ========== .*类|# ============================================)" > /tmp/crontab_clean.tmp
crontab /tmp/crontab_clean.tmp
# 重新运行更新脚本
./update_cron_jobs.sh --host 192.168.5.47 --user root
```
### 问题4:权限不足
```bash
# 确保有执行权限
chmod +x update_cron_jobs.sh
# 确保目标目录可写
ls -ld /opt/scripts
```
### 问题5:更新失败回滚
```bash
# 查看备份目录
ls -lt /opt/scripts/backup/
# 手动回滚
./update_cron_jobs.sh --rollback
```
### 问题6:查看更新日志
```bash
# 查看更新日志
tail -f /var/log/scripts/update_cron_jobs.log
# 查看最新报告
ls -lt /var/log/scripts/update_report_*
cat /var/log/scripts/update_report_*.txt | tail -1
```
---
## 目录结构
```
预定系统一键更新/
├── update_cron_jobs.sh # 主更新脚本
└── 使用说明.md # 本文档
```
---
## 注意事项
1. **执行权限**:确保脚本有执行权限(`chmod +x`
2. **脚本路径**:确保定时脚本目录正确(`../定时脚本`
3. **网络连接**:远程更新前确保SSH连接正常
4. **备份保留**:更新前会自动备份,7天后自动清理
5. **版本验证**:更新失败会自动回滚,请查看日志确认结果
---
## 技术支持
如遇问题,请提供以下信息:
1. 错误日志:`/var/log/scripts/update_cron_jobs.log`
2. 更新报告:`/var/log/scripts/update_report_*.txt`
3. 备份位置:`/opt/scripts/backup/`
4. 脚本版本:`./update_cron_jobs.sh --help`
---
**文档结束**
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
#=============================================================================== #===============================================================================
# 脚本名称:auto_clean_deleted_ubains_v3.sh # 脚本名称:auto_clean_deleted_ubains_v3.sh
# 功能描述:已删除大文件自动清理与容器重启脚本 # 功能描述:已删除大文件自动清理与容器重启脚本
# 版本:V3.0 # 版本:V3.1
# 创建日期:2026-01-27 # 创建日期:2026-01-27
# 更新日期:2026-03-30 # 更新日期:2026-03-30
# #
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
#=============================================================================== #===============================================================================
# 脚本名称:backup_mysql_databases.sh # 脚本名称:backup_mysql_databases.sh
# 功能描述:MySQL数据库定时备份脚本 # 功能描述:MySQL数据库定时备份脚本
# 版本:V1.0 # 版本:V1.1
# 创建日期:2026-01-27 # 创建日期:2026-01-27
# 基于文档:_PRD_预定系统_MySQL数据库备份需求文档.md # 基于文档:_PRD_预定系统_MySQL数据库备份需求文档.md
# #
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
#=============================================================================== #===============================================================================
# 脚本名称:backup_mysql_logs.sh # 脚本名称:backup_mysql_logs.sh
# 功能描述:MySQL日志文件定时备份与压缩脚本 # 功能描述:MySQL日志文件定时备份与压缩脚本
# 版本:V1.1 # 版本:V1.2
# 创建日期:2026-01-27 # 创建日期:2026-01-27
# 更新日期:2026-03-30 # 更新日期:2026-03-30
# 基于文档:_PRD_预定系统_MySQL日志备份需求文档.md # 基于文档:_PRD_预定系统_MySQL日志备份需求文档.md
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
#=============================================================================== #===============================================================================
# 脚本名称:backup_nginx_logs.sh # 脚本名称:backup_nginx_logs.sh
# 功能描述:Nginx日志文件定时备份与压缩脚本 # 功能描述:Nginx日志文件定时备份与压缩脚本
# 版本:V1.1 # 版本:V1.2
# 创建日期:2026-01-27 # 创建日期:2026-01-27
# 更新日期:2026-03-30 # 更新日期:2026-03-30
# 基于文档:_PRD_预定系统_Nginx日志备份需求文档.md # 基于文档:_PRD_预定系统_Nginx日志备份需求文档.md
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
#=============================================================================== #===============================================================================
# 脚本名称:check_deleted_file_ubains.sh # 脚本名称:check_deleted_file_ubains.sh
# 功能描述:已删除但仍被占用文件排查工具(内核直读版) # 功能描述:已删除但仍被占用文件排查工具(内核直读版)
# 版本:V1.1 # 版本:V1.2
# 创建日期:2026-02-28 # 创建日期:2026-02-28
# 更新日期:2026-03-30 # 更新日期:2026-03-30
# #
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
#=============================================================================== #===============================================================================
# 脚本名称:monitor_emqx_service.sh # 脚本名称:monitor_emqx_service.sh
# 功能描述:EMQX 服务监测与自愈脚本 (增强版) # 功能描述:EMQX 服务监测与自愈脚本 (增强版)
# 版本:V2.1 # 版本:V2.2
# 创建日期:2026-01-27 # 创建日期:2026-01-27
# 修改日期:2026-03-30 # 修改日期:2026-03-30
# 基于文档:_PRD_预定系统_EMQX 服务监控需求文档.md V2.1 # 基于文档:_PRD_预定系统_EMQX 服务监控需求文档.md V2.1
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
#=============================================================================== #===============================================================================
# 脚本名称:monitor_external_api_services_v2.sh # 脚本名称:monitor_external_api_services_v2.sh
# 功能描述:外部API服务监测与自愈脚本 # 功能描述:外部API服务监测与自愈脚本
# 版本:V1.1 # 版本:V1.2
# 创建日期:2026-01-27 # 创建日期:2026-01-27
# 更新日期:2026-03-30 # 更新日期:2026-03-30
# 基于文档:_PRD_预定系统外部API服务监控需求文档.md (V1.1) # 基于文档:_PRD_预定系统外部API服务监控需求文档.md (V1.1)
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
#=============================================================================== #===============================================================================
# 脚本名称:monitor_inner_api_services.sh # 脚本名称:monitor_inner_api_services.sh
# 功能描述:预定系统后端服务监测与自愈脚本 # 功能描述:预定系统后端服务监测与自愈脚本
# 版本:V1.1 # 版本:V1.2
# 创建日期:2026-01-27 # 创建日期:2026-01-27
# 更新日期:2026-03-30 # 更新日期:2026-03-30
# 基于文档:_PRD_预定系统后端服务监测需求文档.md (V1.1) # 基于文档:_PRD_预定系统后端服务监测需求文档.md (V1.1)
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
#=============================================================================== #===============================================================================
# 脚本名称:monitor_mysql_service.sh # 脚本名称:monitor_mysql_service.sh
# 功能描述:MySQL服务监测与自愈脚本 # 功能描述:MySQL服务监测与自愈脚本
# 版本:V1.1 # 版本:V1.2
# 创建日期:2026-01-27 # 创建日期:2026-01-27
# 更新日期:2026-03-30 # 更新日期:2026-03-30
# 基于文档:_PRD_预定系统_MySQL服务监控需求文档.md (V1.1) # 基于文档:_PRD_预定系统_MySQL服务监控需求文档.md (V1.1)
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
#=============================================================================== #===============================================================================
# 脚本名称:monitor_redis_service.sh # 脚本名称:monitor_redis_service.sh
# 功能描述:Redis服务监测与自愈脚本 # 功能描述:Redis服务监测与自愈脚本
# 版本:V1.1 # 版本:V1.2
# 创建日期:2026-01-27 # 创建日期:2026-01-27
# 更新日期:2026-03-30 # 更新日期:2026-03-30
# 基于文档:_PRD_预定系统_Redis服务监控需求文档.md (V1.1) # 基于文档:_PRD_预定系统_Redis服务监控需求文档.md (V1.1)
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论