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

feat(scripts): 优化数据库备份脚本增加多数据库备份和审计功能

- 实现通用备份函数支持数组形式传入多个数据库
- 增加mysql容器模糊匹配和启动状态检查功能
- 添加磁盘空间检查和同日多次执行防护机制
- 实现分级别日志审计和备份失败汇总报告
- 更新定时任务脚本支持mysql备份参数配置
- 增加定期清理15天前备份数据和日志文件功能
上级 65e7d726
# 数据库备份脚本优化
## 代码路径
- 需调用代码路径:[自动化部署脚本/x86架构/新统一平台/定时脚本/UbainsmysqlBakUp.sh]
- 需要同步调整的定时任务脚本:[自动化部署脚本/x86架构/新统一平台/auto_crontab_settings.sh]
## 功能需求
### 功能目标
**目标:** 数据库备份脚本代码逻辑优化,增加数据库:offline、nacos_mysql、devops_voice以及huazhao2的备份操作。
### 需求描述
- 优化现有的代码框架:
- 设置通用备份函数,设置数据库:offline、nacos_mysql、devops_voice以及huazhao2的备份操作,以数组形式传入。
- 增加对mysql容器是否存在的判断,且mysql容器名称需要模糊匹配,例如:umysql、umysql2。以umysql开头的mysql容器,则认为该容器是mysql容器。服务器上mysql容器只会存在一个。如果检查到两个运行的mysql容器那就退出脚本,增加日志说明。
- 添加对mysql容器是否启动的判断,若未启动则退出脚本。
- 若单个数据库备份失败,则跳过该数据库的备份。需要记录失败的数据库名称和原因,且需要一个汇总报告(成功x个,失败x个)
- 备份路径:
- 统一在/data/bakup/mysql下存放,以文件夹形式存放本次备份的数据库文件。文件夹命名为日期格式。
- 通过 docker exec 管道备份到宿主机路径,如:/data/bakup/mysql/`YYYYMMDD`/数据库名称_YYYYMMDD.sql
- 定时清理:
- 默认保留15天的备份数据。超出15天的备份文件夹则删除。清理的位置是/data/bakup/mysql下。通过文件夹名称来判断时间,文件夹名称为日期格式`YYYYMMDD`
- 空间检测判断:
- 检查当前服务器`/data`空间是否小于5G,若小于5G则退出脚本。
- 剩余空间 < 5G(df 命令的 Available)
- 特殊处理:
- 如果在同一天(同一个 YYYYMMDD 文件夹)内多次执行脚本,则退出脚本。
- 日志审计:
- 脚本执行过程中产生的日志,统一存放在/data/bakup/mysql/log下,以日期格式`YYYYMMDD`命名。
- 且日志需记录脚本执行的每一步,要能支撑审计作用。
- 分级别日志,如:INFO、WARN、ERROR。
- 增加时间戳格式,如:2021-01-01 01:01:01。
- 日志文件命名:mysql_$(date +%Y%m%d).log
- 定期清理日志文件,如:mysql_$(date +%Y%m%d).log,默认保留15天的日志文件。
### 数据库连接信息
- 数据库账号:root
- 数据库密码:dNrprU&2S
- 通用命令:docker exec umysql mysqldump -uroot -p"dNrprU&2S" 数据库名 > /data/bakup/mysql/日期/数据库名_日期.sql
### 关联脚本
- 定时任务脚本:[自动化部署脚本/x86架构/新统一平台/auto_crontab_settings.sh]需要增加mysql的参数,可通过接收该参数设置定时任务。
- 数据库定时脚本在服务器上的路径:[/data/services/scripts/UbainsmysqlBakUp.sh]
- 参数名称设置:--enable-mysql-backup 或 --enable-mysql
- 执行周期:每周5晚上0点进行备份。
## 规范文档
- 代码规范: `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`
---
\ No newline at end of file
#!/bin/bash
#####################################
#用于数据库备份 23-01-13
#####################################
#预定数据库备份
function ubainsbak()
{
echo -e "\033[33m 检查mysql...... \033[0m"
sudo docker images |grep mysql
sudo docker ps |grep umysql
if [ $? -eq 0 ]; then
sudo docker exec -i umysql bash <<'EOF'
find /home/mysql/ubains/* -mtime +30 -exec rm -rf {} \;
mkdir -p /home/mysql/ubains/$(date +%Y%m%d)
# 备份指定数据库
mysqldump -uroot -p"dNrprU&2S" ubains > /home/mysql/ubains/$(date +%Y%m%d)/ubains_$(date +%Y%m%d_%H%M%S).sql
#删除30天之前的备份
log3=$(date -d "30 day ago" +%Y%m%d)
rm /home/mysql/ubains/$log3* -rf
exit
EOF
sudo mkdir -p /data/bakup/mysql/ubains/$(date +%Y%m%d)
sudo docker cp umysql:/home/mysql/ubains/$(date +%Y%m%d) /data/bakup/mysql/ubains
#删除30天之前的备份
log3=$(date -d "30 day ago" +%Y%m%d)
sudo rm /data/bakup/mysql/ubains/$log3* -rf
else
echo -e "\033[33m 请正确安装数据库...... \033[0m"
fi
}
#运维数据库备份
function devopsbak()
{
echo -e "\033[33m 检查mysql...... \033[0m"
sudo docker images |grep mysql
sudo docker ps |grep umysql
if [ $? -eq 0 ]; then
sudo docker exec -i umysql bash <<'EOF'
find /home/mysql/devops/* -mtime +30 -exec rm -rf {} \;
mkdir -p /home/mysql/devops/$(date +%Y%m%d)
# 备份指定数据库
mysqldump -uroot -p"dNrprU&2S" devops > /home/mysql/devops/$(date +%Y%m%d)/devops_$(date +%Y%m%d_%H%M%S).sql
#删除30天之前的备份
log3=$(date -d "30 day ago" +%Y%m%d)
rm /home/mysql/devops/$log3* -rf
exit
EOF
sudo mkdir -p /data/bakup/mysql/devops/$(date +%Y%m%d)
sudo docker cp umysql:/home/mysql/devops/$(date +%Y%m%d) /data/bakup/mysql/devops
#删除30天之前的备份
log3=$(date -d "30 day ago" +%Y%m%d)
sudo rm /data/bakup/mysql/devops/$log3* -rf
else
echo -e "\033[33m 请正确安装数据库...... \033[0m"
fi
}
#############################################################脚本配置项##################################################################################################
#################预定系统 数据库本地备份###############################
ubainsbak
#################运维系统 数据库本地备份###############################
devopsbak
......@@ -26,6 +26,12 @@ TASK_SCRIPT[check_health]="/data/services/scripts/check_server_health.sh"
TASK_LOG[check_health]=""
TASK_STATUS[check_health]=true # 默认启用
# mysql_backup 任务定义
TASK_CRON[mysql_backup]="0 0 * * 5"
TASK_SCRIPT[mysql_backup]="/data/services/scripts/UbainsmysqlBakUp.sh"
TASK_LOG[mysql_backup]=""
TASK_STATUS[mysql_backup]=true # 默认启用
# 初始化 sudo 相关变量
if [[ $(id -u) -ne 0 ]]; then
SUDO="sudo"
......@@ -59,6 +65,10 @@ function show_help() {
--disable-ujava2 禁用 ujava2-startup 定时任务
--enable-check-health 启用 check_server_health 定时任务
--disable-check-health 禁用 check_server_health 定时任务
--enable-mysql-backup 启用 mysql_backup 定时任务
--disable-mysql-backup 禁用 mysql_backup 定时任务
--enable-mysql 启用 mysql_backup 定时任务(别名)
--disable-mysql 禁用 mysql_backup 定时任务(别名)
-h, --help 显示此帮助信息
默认行为:
......@@ -66,8 +76,9 @@ function show_help() {
示例:
$0 # 默认启用所有任务
$0 --disable-ujava2 # 只启用 check_server_health
$0 --enable-ujava2 --enable-check-health # 显式启用指定任务
$0 --disable-ujava2 # 禁用 ujava2-startup
$0 --enable-mysql-backup # 启用数据库备份
$0 --enable-ujava2 --enable-check-health --enable-mysql-backup # 显式启用所有任务
EOF
}
......@@ -101,6 +112,17 @@ function parse_arguments() {
TASK_STATUS[check_health]=false
fi
;;
--enable-mysql-backup|--enable-mysql)
TASK_STATUS[mysql_backup]=true
;;
--disable-mysql-backup|--disable-mysql)
if [[ "${TASK_STATUS[mysql_backup]}" == "false" ]]; then
log "WARN" "⚠️ 参数冲突:mysql_backup 同时被启用和禁用,跳过该任务"
TASK_STATUS[mysql_backup]=conflict
else
TASK_STATUS[mysql_backup]=false
fi
;;
-h|--help)
show_help
exit 0
......
#!/bin/bash
# ========================================
# 数据库备份脚本
# 功能:多数据库备份、容器检查、空间检查、日志审计
# ========================================
# ========================================
# 全局变量定义
# ========================================
# 数据库列表(数组形式)
DATABASES=("offline" "nacos_mysql" "devops_voice" "huazhao2")
# 备份路径配置
BACKUP_BASE="/data/bakup/mysql"
LOG_DIR="${BACKUP_BASE}/log"
# 数据库连接信息
DB_USER="root"
DB_PASSWORD="dNrprU&2S"
# MySQL 容器名称(动态获取)
MYSQL_CONTAINER=""
# 统计变量
SUCCESS_COUNT=0
FAILED_COUNT=0
FAILED_DBS=()
# 日志文件
LOG_FILE="${LOG_DIR}/mysql_$(date +%Y%m%d).log"
# 初始化 sudo 相关变量
if [[ $(id -u) -ne 0 ]]; then
SUDO="sudo"
else
SUDO=""
fi
# ========================================
# 日志函数
# ========================================
function log() {
local level="$1"
local message="$2"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
# 输出到控制台
echo "[$timestamp] [$level] $message"
# 追加到日志文件
if [[ -n "$LOG_FILE" ]]; then
echo "[$timestamp] [$level] $message" >> "$LOG_FILE"
fi
}
# ========================================
# ✅ 函数:检查磁盘空间
# ========================================
function check_disk_space() {
log "INFO" "🔍 检查磁盘空间..."
local available_space=$(df /data | awk 'NR==2 {print $4}')
local available_gb=$((available_space / 1024 / 1024))
if [[ $available_gb -lt 5 ]]; then
log "ERROR" "⛔ 磁盘空间不足:当前剩余 ${available_gb}G,要求至少 5G"
return 1
fi
log "INFO" "✅ 磁盘空间检查通过:剩余 ${available_gb}G"
return 0
}
# ========================================
# ✅ 函数:查找 MySQL 容器
# ========================================
function find_mysql_container() {
log "INFO" "🔍 查找 MySQL 容器..."
# 查找以 umysql 开头且正在运行的容器
local containers=$(docker ps --format '{{.Names}}' | grep '^umysql')
# 统计容器数量
local count=$(echo "$containers" | grep -c '^umysql' 2>/dev/null || echo 0)
if [[ $count -eq 0 ]]; then
log "ERROR" "⛔ 未找到 MySQL 容器(以 umysql 开头且正在运行)"
return 1
fi
if [[ $count -gt 1 ]]; then
log "ERROR" "⛔ 检测到多个 MySQL 容器:"
echo "$containers" | while read -r container; do
log "ERROR" " - $container"
done
log "ERROR" "⛔ 为避免误操作,脚本退出"
return 1
fi
MYSQL_CONTAINER=$(echo "$containers" | head -n 1)
log "INFO" "✅ 找到 MySQL 容器: $MYSQL_CONTAINER"
return 0
}
# ========================================
# ✅ 函数:检查容器是否启动
# ========================================
function check_container_running() {
log "INFO" "🔍 检查容器运行状态..."
if ! docker ps --format '{{.Names}}' | grep -q "^${MYSQL_CONTAINER}$"; then
log "ERROR" "⛔ MySQL 容器未启动: $MYSQL_CONTAINER"
return 1
fi
log "INFO" "✅ MySQL 容器运行正常"
return 0
}
# ========================================
# ✅ 函数:备份数据库
# ========================================
function backup_database() {
local db_name="$1"
local backup_dir="$2"
local date_str=$(date +%Y%m%d)
local backup_file="${backup_dir}/${db_name}_${date_str}.sql"
log "INFO" "🔧 开始备份数据库: $db_name"
# 执行备份
if docker exec "$MYSQL_CONTAINER" mysqldump -u"${DB_USER}" -p"${DB_PASSWORD}" "$db_name" > "$backup_file" 2>/dev/null; then
# 检查备份文件是否为空
if [[ -s "$backup_file" ]]; then
log "INFO" "✅ 数据库备份成功: $db_name"
((SUCCESS_COUNT++))
return 0
else
log "ERROR" "⛔ 数据库备份失败: $db_name (备份文件为空)"
((FAILED_COUNT++))
FAILED_DBS+=("$db_name")
rm -f "$backup_file"
return 1
fi
else
log "ERROR" "⛔ 数据库备份失败: $db_name (mysqldump 执行失败)"
((FAILED_COUNT++))
FAILED_DBS+=("$db_name")
return 1
fi
}
# ========================================
# ✅ 函数:清理旧备份文件
# ========================================
function cleanup_old_backups() {
log "INFO" "🧹 开始清理旧备份文件..."
# 删除 15 天前的备份文件夹
local deleted_count=$(find "$BACKUP_BASE" -maxdepth 1 -type d -name "[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]" -mtime +15 -print -exec rm -rf {} \; 2>/dev/null | wc -l)
if [[ $deleted_count -gt 0 ]]; then
log "INFO" "✅ 已删除 ${deleted_count} 个旧备份文件夹"
else
log "INFO" "✅ 无需清理的旧备份文件夹"
fi
}
# ========================================
# ✅ 函数:清理旧日志文件
# ========================================
function cleanup_old_logs() {
log "INFO" "🧹 开始清理旧日志文件..."
# 删除 15 天前的日志文件
local deleted_count=$(find "$LOG_DIR" -name "mysql_*.log" -mtime +15 -print -delete 2>/dev/null | wc -l)
if [[ $deleted_count -gt 0 ]]; then
log "INFO" "✅ 已删除 ${deleted_count} 个旧日志文件"
else
log "INFO" "✅ 无需清理的旧日志文件"
fi
}
# ========================================
# ✅ 函数:打印汇总报告
# ========================================
function print_summary() {
local total=$((SUCCESS_COUNT + FAILED_COUNT))
log "INFO" "=========================================="
log "INFO" "📊 备份汇总报告"
log "INFO" "=========================================="
log "INFO" "总计数据库:$total 个"
log "INFO" "成功备份:$SUCCESS_COUNT 个"
log "INFO" "失败备份:$FAILED_COUNT 个"
if [[ ${#FAILED_DBS[@]} -gt 0 ]]; then
log "INFO" "失败列表:"
for db in "${FAILED_DBS[@]}"; do
log "INFO" " - $db"
done
fi
log "INFO" "=========================================="
# 根据备份结果决定退出码
if [[ $FAILED_COUNT -gt 0 ]]; then
return 1
else
return 0
fi
}
# ========================================
# ✅ 函数:主函数
# ========================================
function main() {
# 获取当前日期
local today=$(date +%Y%m%d)
local backup_dir="${BACKUP_BASE}/${today}"
# 创建日志目录
$SUDO mkdir -p "$LOG_DIR"
log "INFO" "=========================================="
log "INFO" "🚀 开始数据库备份"
log "INFO" "=========================================="
log "INFO" "备份日期: $today"
log "INFO" "备份数据库数量: ${#DATABASES[@]}"
# 1. 空间检查
if ! check_disk_space; then
log "INFO" "=========================================="
log "ERROR" "⛔ 备份失败:磁盘空间不足"
log "INFO" "=========================================="
exit 1
fi
# 2. 容器检查
if ! find_mysql_container; then
log "INFO" "=========================================="
log "ERROR" "⛔ 备份失败:MySQL 容器检查失败"
log "INFO" "=========================================="
exit 1
fi
# 3. 检查容器是否启动
if ! check_container_running; then
log "INFO" "=========================================="
log "ERROR" "⛔ 备份失败:MySQL 容器未启动"
log "INFO" "=========================================="
exit 1
fi
# 4. 检查今日是否已备份
if [[ -d "$backup_dir" ]]; then
log "ERROR" "⛔ 今日备份文件夹已存在:$backup_dir"
log "ERROR" "⛔ 为避免覆盖,脚本退出"
log "INFO" "=========================================="
log "ERROR" "⛔ 备份失败:今日已备份"
log "INFO" "=========================================="
exit 1
fi
# 5. 创建备份目录
$SUDO mkdir -p "$backup_dir"
log "INFO" "📁 创建备份目录: $backup_dir"
# 6. 执行备份
for db_name in "${DATABASES[@]}"; do
backup_database "$db_name" "$backup_dir"
done
# 7. 清理旧文件
cleanup_old_backups
cleanup_old_logs
# 8. 打印汇总报告
print_summary
local exit_code=$?
if [[ $exit_code -eq 0 ]]; then
log "INFO" "✅ 数据库备份完成"
else
log "ERROR" "⛔ 数据库备份完成,但部分数据库备份失败"
fi
exit $exit_code
}
# ========================================
# 主函数入口
# ========================================
main
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论