chore: 针对备份及还原处理
This commit is contained in:
278
scripts/backup_restore/backup_server.sh
Normal file
278
scripts/backup_restore/backup_server.sh
Normal file
@@ -0,0 +1,278 @@
|
||||
#!/bin/bash
|
||||
# backup_server.sh - 支持长路径和配置文件的智能备份脚本
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# 脚本配置
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
CONFIG_FILE="${SCRIPT_DIR}/backup_config.json"
|
||||
ENV_FILE="${SCRIPT_DIR}/.env"
|
||||
LOG_FILE="${SCRIPT_DIR}/backup_$(date +%Y%m%d_%H%M%S).log"
|
||||
|
||||
# 颜色输出
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
log() { echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1" | tee -a "$LOG_FILE"; }
|
||||
warn() { echo -e "${YELLOW}[WARN]${NC} $1" | tee -a "$LOG_FILE"; }
|
||||
error() { echo -e "${RED}[ERROR]${NC} $1" | tee -a "$LOG_FILE"; }
|
||||
info() { echo -e "${BLUE}[INFO]${NC} $1" | tee -a "$LOG_FILE"; }
|
||||
|
||||
# 加载配置
|
||||
load_config() {
|
||||
if [[ ! -f "$CONFIG_FILE" ]]; then
|
||||
error "配置文件不存在: $CONFIG_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -f "$ENV_FILE" ]]; then
|
||||
source "$ENV_FILE"
|
||||
log "环境配置文件已加载"
|
||||
fi
|
||||
|
||||
# 解析JSON配置
|
||||
BACKUP_NAME=$(jq -r '.backup.name // "server-backup"' "$CONFIG_FILE")
|
||||
SOURCE_DIRS=$(jq -r '.backup.source_dirs[]?' "$CONFIG_FILE" | tr '\n' ' ')
|
||||
EXCLUDE_PATTERNS=$(jq -r '.backup.exclude_patterns[]?' "$CONFIG_FILE")
|
||||
LONG_PATH_SUPPORT=$(jq -r '.backup.long_path_support // "true"' "$CONFIG_FILE")
|
||||
LOCAL_BACKUP_PATH=$(jq -r '.storage.local_path // "/backups"' "$CONFIG_FILE")
|
||||
|
||||
log "配置文件加载完成"
|
||||
}
|
||||
|
||||
# 检查长路径支持
|
||||
check_long_path_support() {
|
||||
if [[ "$LONG_PATH_SUPPORT" == "true" ]]; then
|
||||
# 检查tar版本是否支持长路径
|
||||
TAR_VERSION=$(tar --version | head -1 | grep -oE '[0-9]+\.[0-9]+')
|
||||
if [[ $(echo "$TAR_VERSION >= 1.22" | bc -l 2>/dev/null) -eq 1 ]]; then
|
||||
TAR_OPTIONS="--force-local"
|
||||
log "tar版本 $TAR_VERSION 支持长路径"
|
||||
else
|
||||
warn "tar版本较低,长路径支持可能受限"
|
||||
TAR_OPTIONS=""
|
||||
fi
|
||||
else
|
||||
TAR_OPTIONS=""
|
||||
info "长路径支持已禁用"
|
||||
fi
|
||||
}
|
||||
|
||||
# 创建排除文件
|
||||
create_exclude_file() {
|
||||
local exclude_file="${SCRIPT_DIR}/exclude_patterns.txt"
|
||||
|
||||
# 从配置文件读取排除模式
|
||||
jq -r '.backup.exclude_patterns[]?' "$CONFIG_FILE" > "$exclude_file"
|
||||
|
||||
# 添加系统默认排除
|
||||
cat >> "$exclude_file" << EOF
|
||||
*.log
|
||||
*.tmp
|
||||
*.swp
|
||||
*.swo
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
._*
|
||||
EOF
|
||||
|
||||
echo "$exclude_file"
|
||||
}
|
||||
|
||||
# 备份数据库
|
||||
backup_databases() {
|
||||
local db_enabled=$(jq -r '.database.enabled // "false"' "$CONFIG_FILE")
|
||||
|
||||
if [[ "$db_enabled" != "true" ]]; then
|
||||
info "数据库备份已禁用"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local timestamp=$(date +%Y%m%d_%H%M%S)
|
||||
local db_backup_dir="${LOCAL_BACKUP_PATH}/database_${timestamp}"
|
||||
|
||||
mkdir -p "$db_backup_dir"
|
||||
log "开始备份数据库..."
|
||||
|
||||
# MySQL备份
|
||||
if command -v mysqldump > /dev/null; then
|
||||
local mysql_config=$(jq -r '.database.mysql // {}' "$CONFIG_FILE")
|
||||
if [[ "$mysql_config" != "{}" ]]; then
|
||||
local mysql_host=$(jq -r '.host // "localhost"' <<< "$mysql_config")
|
||||
local mysql_user=$(jq -r '.user // "root"' <<< "$mysql_config")
|
||||
local mysql_password=$(jq -r '.password // ""' <<< "$mysql_config")
|
||||
local databases=$(jq -r '.databases[]?' <<< "$mysql_config")
|
||||
|
||||
for db in $databases; do
|
||||
info "备份MySQL数据库: $db"
|
||||
if [[ -n "$mysql_password" ]]; then
|
||||
mysqldump -h "$mysql_host" -u "$mysql_user" -p"$mysql_password" "$db" > "${db_backup_dir}/${db}_mysql.sql"
|
||||
else
|
||||
mysqldump -h "$mysql_host" -u "$mysql_user" "$db" > "${db_backup_dir}/${db}_mysql.sql"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
# PostgreSQL备份
|
||||
if command -v pg_dump > /dev/null; then
|
||||
local pgsql_config=$(jq -r '.database.postgresql // {}' "$CONFIG_FILE")
|
||||
if [[ "$pgsql_config" != "{}" ]]; then
|
||||
local pgsql_host=$(jq -r '.host // "localhost"' <<< "$pgsql_config")
|
||||
local pgsql_user=$(jq -r '.user // "postgres"' <<< "$pgsql_config")
|
||||
local databases=$(jq -r '.databases[]?' <<< "$pgsql_config")
|
||||
|
||||
for db in $databases; do
|
||||
info "备份PostgreSQL数据库: $db"
|
||||
pg_dump -h "$pgsql_host" -U "$pgsql_user" "$db" > "${db_backup_dir}/${db}_pgsql.sql"
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
log "数据库备份完成: $db_backup_dir"
|
||||
}
|
||||
|
||||
# 主备份函数
|
||||
perform_backup() {
|
||||
local timestamp=$(date +%Y%m%d_%H%M%S)
|
||||
local backup_file="${LOCAL_BACKUP_PATH}/backup_${timestamp}.tar.gz"
|
||||
local exclude_file=$(create_exclude_file)
|
||||
|
||||
log "开始备份服务器源码..."
|
||||
info "源目录: $SOURCE_DIRS"
|
||||
info "备份文件: $backup_file"
|
||||
|
||||
# 创建备份目录
|
||||
mkdir -p "$LOCAL_BACKUP_PATH"
|
||||
|
||||
# 备份数据库
|
||||
backup_databases
|
||||
|
||||
# 使用tar进行备份(支持长路径)
|
||||
local tar_command="tar $TAR_OPTIONS -czf \"$backup_file\" --exclude-from=\"$exclude_file\" $SOURCE_DIRS"
|
||||
|
||||
log "执行备份命令: $tar_command"
|
||||
|
||||
if eval "$tar_command"; then
|
||||
local backup_size=$(du -h "$backup_file" | cut -f1)
|
||||
log "✅ 备份成功! 文件大小: $backup_size"
|
||||
echo "$backup_file" > "${SCRIPT_DIR}/latest_backup.txt"
|
||||
else
|
||||
error "❌ 备份失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 清理临时文件
|
||||
rm -f "$exclude_file"
|
||||
}
|
||||
|
||||
# 加密备份文件
|
||||
encrypt_backup() {
|
||||
local encryption_enabled=$(jq -r '.encryption.enabled // "false"' "$CONFIG_FILE")
|
||||
|
||||
if [[ "$encryption_enabled" != "true" ]]; then
|
||||
info "加密功能已禁用"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local backup_file=$(cat "${SCRIPT_DIR}/latest_backup.txt" 2>/dev/null || echo "")
|
||||
if [[ -z "$backup_file" || ! -f "$backup_file" ]]; then
|
||||
warn "未找到备份文件进行加密"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local public_key=$(jq -r '.encryption.public_key // ""' "$CONFIG_FILE")
|
||||
if [[ -z "$public_key" || ! -f "$public_key" ]]; then
|
||||
error "加密公钥不存在: $public_key"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log "开始加密备份文件..."
|
||||
|
||||
if command -v gpg > /dev/null; then
|
||||
gpg --encrypt --recipient-file "$public_key" --trust-model always "$backup_file"
|
||||
if [[ $? -eq 0 ]]; then
|
||||
local encrypted_file="${backup_file}.gpg"
|
||||
log "✅ 加密完成: $encrypted_file"
|
||||
# 可选:删除未加密文件
|
||||
# rm -f "$backup_file"
|
||||
else
|
||||
error "❌ 加密失败"
|
||||
fi
|
||||
else
|
||||
error "GPG未安装,无法加密"
|
||||
fi
|
||||
}
|
||||
|
||||
# 清理旧备份
|
||||
cleanup_old_backups() {
|
||||
local retention_days=$(jq -r '.backup.backup_retention_days // 30' "$CONFIG_FILE")
|
||||
|
||||
log "清理超过 $retention_days 天的旧备份..."
|
||||
|
||||
find "$LOCAL_BACKUP_PATH" -name "backup_*.tar.gz" -mtime "+$retention_days" -delete
|
||||
find "$LOCAL_BACKUP_PATH" -name "backup_*.tar.gz.gpg" -mtime "+$retention_days" -delete
|
||||
find "$LOCAL_BACKUP_PATH" -name "database_*" -type d -mtime "+$retention_days" -exec rm -rf {} +
|
||||
|
||||
log "旧备份清理完成"
|
||||
}
|
||||
|
||||
# 发送通知
|
||||
send_notification() {
|
||||
local backup_file=$(cat "${SCRIPT_DIR}/latest_backup.txt" 2>/dev/null || echo "未知")
|
||||
local backup_size=$(du -h "$backup_file" 2>/dev/null | cut -f1 || echo "未知")
|
||||
|
||||
local message="✅ 服务器备份完成\n时间: $(date)\n文件: $(basename "$backup_file")\n大小: $backup_size"
|
||||
|
||||
# Slack通知
|
||||
local slack_webhook=$(jq -r '.notifications.slack_webhook // ""' "$CONFIG_FILE")
|
||||
if [[ -n "$slack_webhook" ]]; then
|
||||
curl -X POST -H 'Content-type: application/json' \
|
||||
--data "{\"text\":\"$message\"}" "$slack_webhook" > /dev/null 2>&1 &&
|
||||
log "Slack通知已发送"
|
||||
fi
|
||||
|
||||
# 邮件通知(需要配置邮件服务器)
|
||||
local email_to=$(jq -r '.notifications.email // ""' "$CONFIG_FILE")
|
||||
if [[ -n "$email_to" && -f "/usr/sbin/sendmail" ]]; then
|
||||
echo -e "Subject: 服务器备份完成\n\n$message" | sendmail "$email_to"
|
||||
log "邮件通知已发送"
|
||||
fi
|
||||
}
|
||||
|
||||
# 主函数
|
||||
main() {
|
||||
log "🚀 启动服务器源码备份流程"
|
||||
log "========================================"
|
||||
|
||||
# 加载配置
|
||||
load_config
|
||||
|
||||
# 检查长路径支持
|
||||
check_long_path_support
|
||||
|
||||
# 执行备份
|
||||
perform_backup
|
||||
|
||||
# 加密备份
|
||||
encrypt_backup
|
||||
|
||||
# 清理旧备份
|
||||
cleanup_old_backups
|
||||
|
||||
# 发送通知
|
||||
send_notification
|
||||
|
||||
log "🎉 备份流程完成!"
|
||||
log "========================================"
|
||||
}
|
||||
|
||||
# 异常处理
|
||||
trap 'error "脚本执行中断"; exit 1' INT TERM
|
||||
trap 'cleanup_old_backups' EXIT
|
||||
|
||||
# 执行主函数
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user