实战:用 Shell 脚本自动备份网站和数据库,并上传到云存储

1. 备份方案概述

在本教程中,我们将创建一个完整的自动化备份系统,用于备份网站文件和数据库,并将备份文件上传到云存储。该系统包含错误处理、日志记录和通知功能,适合生产环境使用。

graph TD A[开始备份任务] --> B[初始化环境和变量] B --> C[备份网站文件] C --> D[备份MySQL数据库] D --> E[备份PostgreSQL数据库] E --> F[压缩备份文件] F --> G{上传到云存储} G --> H[AWS S3] G --> I[Google Cloud Storage] G --> J[阿里云OSS] H --> K[清理旧备份] I --> K J --> K K --> L[发送通知] L --> M[备份完成] style A fill:#2C3E50,stroke:#2C3E50,color:#fff style M fill:#27AE60,stroke:#27AE60,color:#fff style G fill:#E74C3C,stroke:#E74C3C,color:#fff style C fill:#3498DB,stroke:#3498DB,color:#fff style D fill:#3498DB,stroke:#3498DB,color:#fff style E fill:#3498DB,stroke:#3498DB,color:#fff

2. 环境准备和依赖安装

2.1 系统要求检查

首先创建环境检查脚本:

bash 复制代码
#!/bin/bash
# check_environment.sh

echo "检查系统环境..."

# 检查操作系统
if [ -f /etc/os-release ]; then
    . /etc/os-release
    OS=$NAME
    VER=$VERSION_ID
    echo "操作系统: $OS $VER"
else
    echo "警告: 无法检测操作系统版本"
fi

# 检查磁盘空间
echo "磁盘空间信息:"
df -h / /tmp /var

# 检查必要的工具
required_tools=("tar" "gzip" "mysql" "pg_dump" "curl")
for tool in "${required_tools[@]}"; do
    if command -v $tool &> /dev/null; then
        echo "✓ $tool 已安装"
    else
        echo "✗ $tool 未安装"
    fi
done

# 检查云存储工具
cloud_tools=("aws" "gsutil" "ossutil")
for tool in "${cloud_tools[@]}"; do
    if command -v $tool &> /dev/null; then
        echo "✓ $tool 已安装"
    else
        echo "✗ $tool 未安装 (可选)"
    fi
done

2.2 安装必要的软件包

根据不同的Linux发行版安装所需软件:

bash 复制代码
#!/bin/bash
# install_dependencies.sh

echo "安装备份所需的软件包..."

# 检测发行版
if [ -f /etc/redhat-release ]; then
    # CentOS/RHEL
    sudo yum update -y
    sudo yum install -y tar gzip mysql-server postgresql curl python3-pip
    
elif [ -f /etc/debian_version ]; then
    # Ubuntu/Debian
    sudo apt update
    sudo apt install -y tar gzip mysql-client postgresql-client curl python3-pip
    
else
    echo "不支持的Linux发行版"
    exit 1
fi

# 安装云存储CLI工具
echo "安装AWS CLI..."
pip3 install awscli --upgrade --user

echo "安装Google Cloud SDK..."
curl https://sdk.cloud.google.com | bash
exec -l $SHELL

echo "安装阿里云OSS工具..."
wget -O ossutil64 https://gosspublic.alicdn.com/ossutil/1.7.14/ossutil64
chmod 755 ossutil64
sudo mv ossutil64 /usr/local/bin/ossutil

3. 配置文件设置

创建主配置文件:

bash 复制代码
#!/bin/bash
# config/backup.conf

# 备份配置
BACKUP_DIR="/opt/backups"
LOG_DIR="/var/log/backups"
RETENTION_DAYS=30
COMPRESSION_LEVEL=6

# 网站文件配置
WEB_ROOT="/var/www/html"
EXCLUDE_PATTERNS=("*.log" "*.tmp" "cache/*" "tmp/*")

# 数据库配置
# MySQL
MYSQL_HOST="localhost"
MYSQL_PORT="3306"
MYSQL_USER="backup_user"
MYSQL_PASSWORD="your_secure_password"
MYSQL_DATABASES=("wordpress" "mydatabase" "application_db")

# PostgreSQL
PG_HOST="localhost"
PG_PORT="5432"
PG_USER="backup_user"
PG_PASSWORD="your_secure_password"
PG_DATABASES=("app_production" "analytics_db")

# 云存储配置
# AWS S3
AWS_BUCKET="my-backup-bucket"
AWS_REGION="us-east-1"

# Google Cloud Storage
GCS_BUCKET="my-backup-bucket"

# 阿里云OSS
OSS_BUCKET="my-backup-bucket"
OSS_ENDPOINT="oss-cn-hangzhou.aliyuncs.com"

# 通知配置
EMAIL_RECIPIENT="admin@example.com"
SLACK_WEBHOOK_URL="https://hooks.slack.com/services/your/webhook/url"

创建数据库用户配置脚本:

bash 复制代码
#!/bin/bash
# setup_database_users.sh

echo "设置数据库备份用户..."

# MySQL备份用户设置
mysql -u root -p <<EOF
-- 创建备份用户
CREATE USER IF NOT EXISTS 'backup_user'@'localhost' IDENTIFIED BY 'your_secure_password';

-- 授予必要权限
GRANT SELECT, LOCK TABLES, SHOW VIEW, PROCESS ON *.* TO 'backup_user'@'localhost';

-- 刷新权限
FLUSH PRIVILEGES;

-- 显示用户权限
SHOW GRANTS FOR 'backup_user'@'localhost';
EOF

# PostgreSQL备份用户设置
sudo -u postgres psql <<EOF
-- 创建备份用户
CREATE USER backup_user WITH PASSWORD 'your_secure_password';

-- 授予必要权限
ALTER USER backup_user WITH SUPERUSER;

-- 显示用户信息
\du backup_user
EOF

echo "数据库备份用户设置完成"

4. 核心备份脚本

创建主备份脚本:

bash 复制代码
#!/bin/bash
# website_backup.sh

# 加载配置
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/config/backup.conf"

# 设置变量
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_NAME="backup_${TIMESTAMP}"
BACKUP_PATH="${BACKUP_DIR}/${BACKUP_NAME}"
LOG_FILE="${LOG_DIR}/backup_${TIMESTAMP}.log"

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 日志函数
log() {
    local level=$1
    local message=$2
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    echo -e "${timestamp} [${level}] ${message}" | tee -a "$LOG_FILE"
}

log_info() {
    log "INFO" "${BLUE}$1${NC}"
}

log_success() {
    log "SUCCESS" "${GREEN}$1${NC}"
}

log_warning() {
    log "WARNING" "${YELLOW}$1${NC}"
}

log_error() {
    log "ERROR" "${RED}$1${NC}"
}

# 错误处理函数
error_exit() {
    log_error "$1"
    send_notification "备份失败" "$1"
    exit 1
}

# 通知函数
send_notification() {
    local subject=$1
    local message=$2
    
    # 邮件通知
    if command -v mail &> /dev/null && [ -n "$EMAIL_RECIPIENT" ]; then
        echo "$message" | mail -s "Backup Alert: $subject" "$EMAIL_RECIPIENT"
    fi
    
    # Slack通知
    if command -v curl &> /dev/null && [ -n "$SLACK_WEBHOOK_URL" ]; then
        curl -X POST -H 'Content-type: application/json' \
            --data "{\"text\":\"*Backup Alert*: $subject\n$message\"}" \
            "$SLACK_WEBHOOK_URL" > /dev/null 2>&1
    fi
}

# 初始化备份环境
init_backup() {
    log_info "初始化备份环境..."
    
    # 创建目录
    mkdir -p "$BACKUP_DIR" "$LOG_DIR" "$BACKUP_PATH"
    
    # 检查目录权限
    if [ ! -w "$BACKUP_DIR" ]; then
        error_exit "备份目录不可写: $BACKUP_DIR"
    fi
    
    if [ ! -r "$WEB_ROOT" ]; then
        error_exit "网站目录不可读: $WEB_ROOT"
    fi
    
    log_success "备份环境初始化完成"
}

# 备份网站文件
backup_website_files() {
    log_info "开始备份网站文件..."
    
    local exclude_args=()
    for pattern in "${EXCLUDE_PATTERNS[@]}"; do
        exclude_args+=(--exclude="$pattern")
    done
    
    cd "$WEB_ROOT" || error_exit "无法进入网站目录: $WEB_ROOT"
    
    # 创建文件列表
    find . -type f > "${BACKUP_PATH}/file_list.txt"
    
    # 打包网站文件
    if tar czf "${BACKUP_PATH}/website_files.tar.gz" \
        "${exclude_args[@]}" \
        . > /dev/null 2>&1; then
        local size=$(du -h "${BACKUP_PATH}/website_files.tar.gz" | cut -f1)
        log_success "网站文件备份完成: ${size}"
    else
        error_exit "网站文件备份失败"
    fi
}

# 备份MySQL数据库
backup_mysql_databases() {
    log_info "开始备份MySQL数据库..."
    
    # 测试MySQL连接
    if ! mysql -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u "$MYSQL_USER" -p"$MYSQL_PASSWORD" -e "SELECT 1" > /dev/null 2>&1; then
        log_warning "MySQL连接失败,跳过MySQL备份"
        return 1
    fi
    
    # 获取数据库列表
    local databases
    databases=$(mysql -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u "$MYSQL_USER" -p"$MYSQL_PASSWORD" -e "SHOW DATABASES;" | grep -Ev "(Database|information_schema|performance_schema|mysql|sys)")
    
    local success_count=0
    local total_count=0
    
    for db in $databases; do
        # 检查数据库是否在配置列表中
        if [[ " ${MYSQL_DATABASES[@]} " =~ " ${db} " ]] || [ ${#MYSQL_DATABASES[@]} -eq 0 ]; then
            ((total_count++))
            log_info "备份MySQL数据库: $db"
            
            if mysqldump -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u "$MYSQL_USER" -p"$MYSQL_PASSWORD" \
                --single-transaction \
                --routines \
                --triggers \
                "$db" > "${BACKUP_PATH}/mysql_${db}.sql" 2>> "$LOG_FILE"; then
                
                # 压缩备份文件
                gzip "${BACKUP_PATH}/mysql_${db}.sql"
                ((success_count++))
                log_success "MySQL数据库备份完成: $db"
            else
                log_error "MySQL数据库备份失败: $db"
            fi
        fi
    done
    
    log_success "MySQL备份完成: ${success_count}/${total_count} 个数据库"
}

# 备份PostgreSQL数据库
backup_postgresql_databases() {
    log_info "开始备份PostgreSQL数据库..."
    
    # 设置密码
    export PGPASSWORD="$PG_PASSWORD"
    
    # 测试PostgreSQL连接
    if ! psql -h "$PG_HOST" -p "$PG_PORT" -U "$PG_USER" -d postgres -c "SELECT 1" > /dev/null 2>&1; then
        log_warning "PostgreSQL连接失败,跳过PostgreSQL备份"
        return 1
    fi
    
    local success_count=0
    local total_count=0
    
    for db in "${PG_DATABASES[@]}"; do
        ((total_count++))
        log_info "备份PostgreSQL数据库: $db"
        
        if pg_dump -h "$PG_HOST" -p "$PG_PORT" -U "$PG_USER" \
            --verbose \
            --no-password \
            "$db" > "${BACKUP_PATH}/pgsql_${db}.sql" 2>> "$LOG_FILE"; then
            
            # 压缩备份文件
            gzip "${BACKUP_PATH}/pgsql_${db}.sql"
            ((success_count++))
            log_success "PostgreSQL数据库备份完成: $db"
        else
            log_error "PostgreSQL数据库备份失败: $db"
        fi
    done
    
    log_success "PostgreSQL备份完成: ${success_count}/${total_count} 个数据库"
}

# 创建备份清单
create_backup_manifest() {
    log_info "创建备份清单..."
    
    cat > "${BACKUP_PATH}/manifest.json" << EOF
{
    "backup_name": "${BACKUP_NAME}",
    "timestamp": "${TIMESTAMP}",
    "created_at": "$(date -Iseconds)",
    "components": {
        "website_files": "$(if [ -f "${BACKUP_PATH}/website_files.tar.gz" ]; then echo "true"; else echo "false"; fi)",
        "mysql_databases": "$(ls "${BACKUP_PATH}"/mysql_*.sql.gz 2>/dev/null | wc -l)",
        "postgresql_databases": "$(ls "${BACKUP_PATH}"/pgsql_*.sql.gz 2>/dev/null | wc -l)"
    },
    "system_info": {
        "hostname": "$(hostname)",
        "disk_usage": "$(df -h / | awk 'NR==2 {print $5}')"
    }
}
EOF
    
    log_success "备份清单创建完成"
}

# 压缩备份文件
compress_backup() {
    log_info "压缩备份文件..."
    
    cd "$BACKUP_DIR" || error_exit "无法进入备份目录"
    
    if tar czf "${BACKUP_NAME}.tar.gz" "$BACKUP_NAME" > /dev/null 2>&1; then
        local final_size=$(du -h "${BACKUP_NAME}.tar.gz" | cut -f1)
        log_success "备份文件压缩完成: ${final_size}"
        
        # 清理临时文件
        rm -rf "$BACKUP_PATH"
    else
        error_exit "备份文件压缩失败"
    fi
}

# 上传到云存储
upload_to_cloud() {
    log_info "开始上传到云存储..."
    
    local backup_file="${BACKUP_DIR}/${BACKUP_NAME}.tar.gz"
    
    # 上传到AWS S3
    if command -v aws &> /dev/null && [ -n "$AWS_BUCKET" ]; then
        log_info "上传到AWS S3..."
        if aws s3 cp "$backup_file" "s3://${AWS_BUCKET}/${BACKUP_NAME}.tar.gz" --region "$AWS_REGION" >> "$LOG_FILE" 2>&1; then
            log_success "上传到AWS S3完成"
        else
            log_error "上传到AWS S3失败"
        fi
    fi
    
    # 上传到Google Cloud Storage
    if command -v gsutil &> /dev/null && [ -n "$GCS_BUCKET" ]; then
        log_info "上传到Google Cloud Storage..."
        if gsutil cp "$backup_file" "gs://${GCS_BUCKET}/${BACKUP_NAME}.tar.gz" >> "$LOG_FILE" 2>&1; then
            log_success "上传到Google Cloud Storage完成"
        else
            log_error "上传到Google Cloud Storage失败"
        fi
    fi
    
    # 上传到阿里云OSS
    if command -v ossutil &> /dev/null && [ -n "$OSS_BUCKET" ]; then
        log_info "上传到阿里云OSS..."
        if ossutil cp "$backup_file" "oss://${OSS_BUCKET}/${BACKUP_NAME}.tar.gz" -e "$OSS_ENDPOINT" >> "$LOG_FILE" 2>&1; then
            log_success "上传到阿里云OSS完成"
        else
            log_error "上传到阿里云OSS失败"
        fi
    fi
}

# 清理旧备份
cleanup_old_backups() {
    log_info "清理旧备份文件..."
    
    local local_count=0
    local cloud_count=0
    
    # 清理本地备份
    find "$BACKUP_DIR" -name "backup_*.tar.gz" -type f -mtime +$RETENTION_DAYS | while read -r file; do
        rm -f "$file"
        ((local_count++))
    done
    
    # 清理云存储备份 (AWS S3示例)
    if command -v aws &> /dev/null && [ -n "$AWS_BUCKET" ]; then
        aws s3 ls "s3://${AWS_BUCKET}/" | grep "backup_" | while read -r date time size file; do
            local backup_date=$(echo "$file" | cut -d'_' -f2)
            local current_ts=$(date +%s)
            local backup_ts=$(date -d "${backup_date:0:8} ${backup_date:9:2}:${backup_date:11:2}:${backup_date:13:2}" +%s 2>/dev/null || echo 0)
            local age_days=$(( (current_ts - backup_ts) / 86400 ))
            
            if [ $age_days -gt $RETENTION_DAYS ]; then
                aws s3 rm "s3://${AWS_BUCKET}/$file"
                ((cloud_count++))
            fi
        done
    fi
    
    log_success "清理完成: 本地${local_count}个, 云存储${cloud_count}个备份文件"
}

# 生成备份报告
generate_report() {
    local end_time=$(date +%s)
    local duration=$((end_time - ${START_TIME}))
    
    cat > "${BACKUP_DIR}/backup_report_${TIMESTAMP}.txt" << EOF
备份报告
========

备份名称: ${BACKUP_NAME}
开始时间: $(date -d @${START_TIME} '+%Y-%m-%d %H:%M:%S')
结束时间: $(date -d @${end_time} '+%Y-%m-%d %H:%M:%S')
持续时间: ${duration} 秒

备份组件:
- 网站文件: $(if [ -f "${BACKUP_DIR}/${BACKUP_NAME}.tar.gz" ]; then echo "成功"; else echo "失败"; fi)
- MySQL数据库: $(ls "${BACKUP_DIR}" | grep "mysql_.*\.sql.gz" | wc -l) 个
- PostgreSQL数据库: $(ls "${BACKUP_DIR}" | grep "pgsql_.*\.sql.gz" | wc -l) 个

存储信息:
- 本地备份: ${BACKUP_DIR}/${BACKUP_NAME}.tar.gz
- 云存储: $(if [ -n "$AWS_BUCKET" ] || [ -n "$GCS_BUCKET" ] || [ -n "$OSS_BUCKET" ]; then echo "已上传"; else echo "未配置"; fi)

错误日志: $LOG_FILE
EOF
}

# 主函数
main() {
    START_TIME=$(date +%s)
    
    log_info "=== 开始备份任务 ==="
    
    # 执行备份流程
    init_backup
    backup_website_files
    backup_mysql_databases
    backup_postgresql_databases
    create_backup_manifest
    compress_backup
    upload_to_cloud
    cleanup_old_backups
    
    # 生成报告
    generate_report
    
    local end_time=$(date +%s)
    local duration=$((end_time - START_TIME))
    
    log_success "=== 备份任务完成 ==="
    log_success "总耗时: ${duration} 秒"
    
    # 发送成功通知
    send_notification "备份完成" "备份任务 ${BACKUP_NAME} 已完成,耗时 ${duration} 秒"
}

# 信号处理
trap 'log_error "备份被用户中断"; exit 1' INT TERM

# 执行主函数
main "$@"

5. 自动化部署脚本

创建安装和部署脚本:

bash 复制代码
#!/bin/bash
# deploy_backup_system.sh

set -e

echo "开始部署自动化备份系统..."

# 创建目录结构
echo "创建目录结构..."
sudo mkdir -p /opt/backups/{config,scripts,logs}
sudo mkdir -p /var/log/backups

# 复制脚本文件
echo "复制脚本文件..."
sudo cp website_backup.sh /opt/backups/scripts/
sudo cp config/backup.conf /opt/backups/config/
sudo cp check_environment.sh /opt/backups/scripts/

# 设置权限
echo "设置权限..."
sudo chmod +x /opt/backups/scripts/*.sh
sudo chmod 600 /opt/backups/config/backup.conf

# 设置配置文件权限
sudo chown root:root /opt/backups/config/backup.conf
sudo chmod 400 /opt/backups/config/backup.conf

# 创建备份用户
echo "创建备份用户..."
if ! id "backupuser" &>/dev/null; then
    sudo useradd -r -s /bin/bash -d /opt/backups backupuser
fi

# 设置目录所有权
sudo chown -R backupuser:backupuser /opt/backups
sudo chown -R backupuser:backupuser /var/log/backups

# 配置日志轮转
echo "配置日志轮转..."
sudo tee /etc/logrotate.d/backups > /dev/null <<EOF
/var/log/backups/*.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    create 644 backupuser backupuser
}
EOF

echo "部署完成!"

6. 定时任务配置

创建crontab配置:

bash 复制代码
#!/bin/bash
# setup_cron.sh

echo "配置定时任务..."

# 备份crontab
sudo cp /etc/crontab /etc/crontab.backup.$(date +%Y%m%d)

# 添加每日备份任务 (凌晨2点)
echo "0 2 * * * backupuser /opt/backups/scripts/website_backup.sh >> /var/log/backups/cron.log 2>&1" | sudo tee -a /etc/crontab

# 添加每周完整备份 (周日凌晨1点)
echo "0 1 * * 0 backupuser /opt/backups/scripts/website_backup.sh >> /var/log/backups/cron.log 2>&1" | sudo tee -a /etc/crontab

# 添加监控检查 (每小时)
echo "0 * * * * backupuser /opt/backups/scripts/check_environment.sh >> /var/log/backups/monitor.log 2>&1" | sudo tee -a /etc/crontab

# 重新加载cron
sudo systemctl reload crond

echo "定时任务配置完成"
echo "当前crontab配置:"
sudo crontab -l

7. 监控和验证脚本

创建备份验证脚本:

bash 复制代码
#!/bin/bash
# verify_backup.sh

source /opt/backups/config/backup.conf

echo "开始验证备份完整性..."

# 检查最新备份文件
latest_backup=$(ls -t ${BACKUP_DIR}/backup_*.tar.gz 2>/dev/null | head -1)

if [ -z "$latest_backup" ]; then
    echo "错误: 未找到备份文件"
    exit 1
fi

echo "验证备份文件: $latest_backup"

# 检查文件大小
file_size=$(du -h "$latest_backup" | cut -f1)
echo "备份文件大小: $file_size"

# 检查文件完整性
if tar tzf "$latest_backup" > /dev/null 2>&1; then
    echo "✓ 备份文件完整性检查通过"
else
    echo "✗ 备份文件损坏"
    exit 1
fi

# 检查备份内容
echo "备份内容:"
tar tzf "$latest_backup" | head -10

# 检查云存储备份
if command -v aws &> /dev/null && [ -n "$AWS_BUCKET" ]; then
    if aws s3 ls "s3://${AWS_BUCKET}/" | grep -q "$(basename $latest_backup)"; then
        echo "✓ 云存储备份验证通过"
    else
        echo "✗ 云存储备份不存在"
    fi
fi

echo "备份验证完成"

8. 恢复脚本

创建数据恢复脚本:

bash 复制代码
#!/bin/bash
# restore_backup.sh

source /opt/backups/config/backup.conf

show_usage() {
    echo "使用方法: $0 [选项]"
    echo "选项:"
    echo "  -f, --file FILE    指定备份文件"
    echo "  -d, --date DATE    按日期恢复 (格式: YYYYMMDD_HHMMSS)"
    echo "  -l, --list         列出可用备份"
    echo "  -w, --website      恢复网站文件"
    echo "  -m, --mysql        恢复MySQL数据库"
    echo "  -p, --postgresql   恢复PostgreSQL数据库"
    echo "  -a, --all          恢复所有内容"
}

list_backups() {
    echo "可用的备份文件:"
    ls -la ${BACKUP_DIR}/backup_*.tar.gz 2>/dev/null | while read file; do
        local size=$(du -h "$file" | cut -f1)
        local date=$(basename "$file" | sed 's/backup_\(.*\)\.tar\.gz/\1/')
        echo "  $date - $size - $file"
    done
}

restore_website() {
    local extract_dir="$1"
    echo "恢复网站文件..."
    
    if [ -f "${extract_dir}/website_files.tar.gz" ]; then
        sudo tar xzf "${extract_dir}/website_files.tar.gz" -C /tmp/website_restore
        echo "网站文件已提取到 /tmp/website_restore"
        echo "请手动将文件复制到目标目录"
    else
        echo "警告: 未找到网站文件备份"
    fi
}

restore_mysql() {
    local extract_dir="$1"
    echo "恢复MySQL数据库..."
    
    for sql_file in "${extract_dir}"/mysql_*.sql.gz; do
        if [ -f "$sql_file" ]; then
            local db_name=$(basename "$sql_file" | sed 's/mysql_\(.*\)\.sql\.gz/\1/')
            echo "恢复数据库: $db_name"
            
            gunzip -c "$sql_file" | mysql -h "$MYSQL_HOST" -u "$MYSQL_USER" -p"$MYSQL_PASSWORD"
            if [ $? -eq 0 ]; then
                echo "✓ 数据库恢复成功: $db_name"
            else
                echo "✗ 数据库恢复失败: $db_name"
            fi
        fi
    done
}

main() {
    local backup_file=""
    local restore_website=false
    local restore_mysql=false
    local restore_postgresql=false
    
    while [[ $# -gt 0 ]]; do
        case $1 in
            -f|--file)
                backup_file="$2"
                shift 2
                ;;
            -d|--date)
                local date="$2"
                backup_file="${BACKUP_DIR}/backup_${date}.tar.gz"
                shift 2
                ;;
            -l|--list)
                list_backups
                exit 0
                ;;
            -w|--website)
                restore_website=true
                shift
                ;;
            -m|--mysql)
                restore_mysql=true
                shift
                ;;
            -p|--postgresql)
                restore_postgresql=true
                shift
                ;;
            -a|--all)
                restore_website=true
                restore_mysql=true
                restore_postgresql=true
                shift
                ;;
            *)
                echo "未知选项: $1"
                show_usage
                exit 1
                ;;
        esac
    done
    
    if [ -z "$backup_file" ]; then
        echo "错误: 必须指定备份文件"
        show_usage
        exit 1
    fi
    
    if [ ! -f "$backup_file" ]; then
        echo "错误: 备份文件不存在: $backup_file"
        exit 1
    fi
    
    # 创建临时解压目录
    local temp_dir=$(mktemp -d)
    echo "解压备份文件到: $temp_dir"
    
    tar xzf "$backup_file" -C "$temp_dir"
    
    # 执行恢复操作
    if [ "$restore_website" = true ]; then
        restore_website "$temp_dir"
    fi
    
    if [ "$restore_mysql" = true ]; then
        restore_mysql "$temp_dir"
    fi
    
    # 清理临时文件
    rm -rf "$temp_dir"
    
    echo "恢复操作完成"
}

main "$@"

9. 使用说明和测试

创建测试脚本验证整个系统:

bash 复制代码
#!/bin/bash
# test_backup_system.sh

echo "开始测试备份系统..."

# 测试配置文件
if [ -f "/opt/backups/config/backup.conf" ]; then
    echo "✓ 配置文件存在"
else
    echo "✗ 配置文件缺失"
    exit 1
fi

# 测试主脚本
if [ -x "/opt/backups/scripts/website_backup.sh" ]; then
    echo "✓ 主脚本可执行"
else
    echo "✗ 主脚本不可执行"
    exit 1
fi

# 测试数据库连接
echo "测试数据库连接..."
if mysql -h localhost -u backup_user -p'your_secure_password' -e "SELECT 1" > /dev/null 2>&1; then
    echo "✓ MySQL连接正常"
else
    echo "✗ MySQL连接失败"
fi

# 执行测试备份
echo "执行测试备份..."
sudo -u backupuser /opt/backups/scripts/website_backup.sh

# 检查备份结果
if [ $? -eq 0 ]; then
    echo "✓ 备份测试成功"
else
    echo "✗ 备份测试失败"
    exit 1
fi

echo "备份系统测试完成"

10. 总结

本教程提供了一个完整的企业级网站和数据库备份解决方案,具有以下特点:

  1. 全面性:支持网站文件、MySQL、PostgreSQL数据库备份
  2. 可靠性:包含完整的错误处理和日志记录
  3. 自动化:支持定时任务和自动清理
  4. 多云支持:支持AWS S3、Google Cloud Storage、阿里云OSS
  5. 安全性:配置文件权限控制和敏感信息保护
  6. 可维护性:模块化设计和详细文档

通过按照本教程逐步实施,您可以建立一个生产级别的自动化备份系统,确保网站数据的安全性和可恢复性。

相关推荐
Yeats_Liao2 小时前
时序数据库系列(四):InfluxQL查询语言详解
数据库·后端·sql·时序数据库
清空mega2 小时前
从零开始搭建 flask 博客实验(常见疑问)
后端·python·flask
白衣鸽子2 小时前
MySQL数据库的“隐形杀手”:深入理解文件结构与治理数据碎片
数据库·后端·mysql
neoooo2 小时前
⚙️ Spring Boot × @RequiredArgsConstructor:写出最干净的依赖注入代码
spring boot·后端·spring
Victor3562 小时前
Redis(111)Redis的持久化机制有哪些?
后端
Victor3562 小时前
Redis(110)Redis的发布订阅机制如何使用?
后端
Python私教3 小时前
使用 FastAPI 实现文件上传接口:从入门到进阶
后端
Mos_x4 小时前
springboot系列--自动配置原理
java·后端
IT_陈寒4 小时前
Vue 3响应式原理深度拆解:5个90%开发者不知道的Ref与Reactive底层实现差异
前端·人工智能·后端