跳转至

第四章:实战应用

本章通过实际案例展示 rsync 在各种场景下的应用,包括网站部署、数据库备份、日志收集等。

网站部署

静态网站部署

#!/bin/bash
# deploy-static.sh

LOCAL_DIR="./dist/"
REMOTE_USER="webuser"
REMOTE_HOST="webserver.example.com"
REMOTE_DIR="/var/www/html/"

echo "开始部署静态网站..."

# 检查本地目录
if [ ! -d "$LOCAL_DIR" ]; then
    echo "错误:本地目录 $LOCAL_DIR 不存在"
    exit 1
fi

# 部署到生产环境
rsync -avz \
  --delete \
  --exclude=".git" \
  --exclude=".DS_Store" \
  --exclude="*.swp" \
  --exclude="node_modules/" \
  --exclude=".env" \
  --exclude="config.local.*" \
  --chmod=755 \
  $LOCAL_DIR $REMOTE_USER@$REMOTE_HOST:$REMOTE_DIR

echo "部署完成!"

WordPress 网站部署

#!/bin/bash
# deploy-wordpress.sh

LOCAL_DIR="./wordpress/"
REMOTE_USER="wpuser"
REMOTE_HOST="wp.example.com"
REMOTE_DIR="/var/www/wordpress/"

# 排除配置文件
rsync -avz \
  --delete \
  --exclude="wp-config.php" \
  --exclude=".htaccess" \
  --exclude="wp-content/cache/" \
  --exclude="wp-content/uploads/" \
  --exclude="*.log" \
  $LOCAL_DIR $REMOTE_USER@$REMOTE_HOST:$REMOTE_DIR

# 单独处理上传目录(不同步删除)
rsync -avz \
  --exclude="cache/" \
  ./wordpress/wp-content/uploads/ $REMOTE_USER@$REMOTE_HOST:$REMOTE_DIR/wp-content/uploads/

数据库备份

MySQL 备份脚本

#!/bin/bash
# mysql-backup.sh

# 配置
DB_USER="root"
DB_PASS="password"
DB_NAME="mydatabase"
BACKUP_DIR="/backup/mysql"
REMOTE_HOST="backup.example.com"
REMOTE_USER="backup"
REMOTE_DIR="/backup/mysql/"
KEEP_DAYS=30

# 创建备份目录
mkdir -p $BACKUP_DIR

# 备份文件名
BACKUP_FILE="$BACKUP_DIR/${DB_NAME}_$(date +%Y%m%d_%H%M%S).sql.gz"

echo "开始备份数据库: $DB_NAME"

# 备份数据库
mysqldump -u$DB_USER -p$DB_PASS \
  --single-transaction \
  --quick \
  --lock-tables=false \
  $DB_NAME | gzip > $BACKUP_FILE

if [ $? -eq 0 ]; then
    echo "本地备份成功: $BACKUP_FILE"

    # 同步到远程服务器
    rsync -avz \
      --bwlimit=1000 \
      $BACKUP_FILE $REMOTE_USER@$REMOTE_HOST:$REMOTE_DIR

    # 清理旧备份
    find $BACKUP_DIR -name "*.sql.gz" -mtime +$KEEP_DAYS -delete
    ssh $REMOTE_USER@$REMOTE_HOST "find $REMOTE_DIR -name '*.sql.gz' -mtime +$KEEP_DAYS -delete"

    echo "备份完成"
else
    echo "备份失败"
    exit 1
fi

PostgreSQL 备份

#!/bin/bash
# postgres-backup.sh

# 配置
DB_NAME="mydb"
BACKUP_DIR="/backup/postgres"
REMOTE_HOST="backup.example.com"
REMOTE_DIR="/backup/postgres/"

# 备份
pg_dump $DB_NAME | gzip > $BACKUP_DIR/$DB_NAME_$(date +%Y%m%d).sql.gz

# 同步
rsync -avz $BACKUP_DIR/ $REMOTE_HOST:$REMOTE_DIR

日志收集

Nginx 日志收集

#!/bin/bash
# collect-nginx-logs.sh

# 配置
LOG_DIR="/var/log/nginx"
BACKUP_HOST="logserver.example.com"
BACKUP_USER="loguser"
BACKUP_DIR="/backup/logs/nginx"
DATE=$(date +%Y%m%d)

# 压缩旧日志
find $LOG_DIR -name "*.log" -mtime +1 -exec gzip {} \;

# 同步日志文件
rsync -avz \
  --remove-source-files \
  --include="*.gz" \
  --exclude="*.log" \
  $LOG_DIR/ $BACKUP_USER@$BACKUP_HOST:$BACKUP_DIR/$DATE/

# 清理本地旧压缩文件
find $LOG_DIR -name "*.gz" -mtime +7 -delete

多服务器日志集中

#!/bin/bash
# centralize-logs.sh

# 服务器列表
SERVERS=(
    "web1.example.com"
    "web2.example.com"
    "db1.example.com"
    "app1.example.com"
)

LOCAL_DIR="/central/logs/"
DATE=$(date +%Y%m%d)

for SERVER in "${SERVERS[@]}"; do
    echo "收集 $SERVER 的日志..."

    # 创建目录
    mkdir -p $LOCAL_DIR/$DATE/$SERVER

    # 收集系统日志
    rsync -avz \
      --timeout=30 \
      --exclude="*.gz" \
      root@$SERVER:/var/log/ \
      $LOCAL_DIR/$DATE/$SERVER/

    # 收集应用日志
    rsync -avz \
      --timeout=30 \
      root@$SERVER:/opt/app/logs/ \
      $LOCAL_DIR/$DATE/$SERVER/app-logs/ 2>/dev/null || true
done

# 压缩归档
tar -czf $LOCAL_DIR/logs_$DATE.tar.gz -C $LOCAL_DIR $DATE

文件同步方案

双向同步

#!/bin/bash
# bidirectional-sync.sh

DIR_A="/data/sync/a/"
DIR_B="/data/sync/b/"
LOCK_FILE="/tmp/sync.lock"

# 防止并发执行
if [ -f "$LOCK_FILE" ]; then
    echo "同步正在运行,跳过..."
    exit 0
fi

touch $LOCK_FILE

# 同步 A -> B
rsync -av --delete $DIR_A $DIR_B

# 同步 B -> A
rsync -av --delete $DIR_B $DIR_A

rm -f $LOCK_FILE

实时同步(使用 inotify)

#!/bin/bash
# realtime-sync.sh

SOURCE_DIR="/data/source/"
DEST_DIR="/data/backup/"
REMOTE_HOST="backup.example.com"
REMOTE_DIR="/backup/"

# 安装 inotify-tools
# apt install inotify-tools

# 监控目录变化
inotifywait -m -r -e modify,create,delete,move $SOURCE_DIR |
while read path action file; do
    echo "检测到变化: $path$file ($action)"

    # 立即同步
    rsync -av --delete $SOURCE_DIR $DEST_DIR

    # 可选:同步到远程
    rsync -av --delete $SOURCE_DIR $REMOTE_HOST:$REMOTE_DIR
done

备份策略

完整备份方案

#!/bin/bash
# full-backup.sh

# 配置
SOURCE_DIRS=(
    "/etc"
    "/home"
    "/var/www"
    "/opt/app"
)
BACKUP_ROOT="/backup"
REMOTE_HOST="backup.example.com"
REMOTE_USER="backup"

# 备份类型
BACKUP_TYPE="full"  # full | incremental
DATE=$(date +%Y%m%d)

if [ "$BACKUP_TYPE" = "full" ]; then
    BACKUP_DIR="$BACKUP_ROOT/full_$DATE"
    LINK_DEST=""
else
    BACKUP_DIR="$BACKUP_ROOT/inc_$DATE"
    LATEST_FULL=$(ls -td $BACKUP_ROOT/full_* | head -1)
    LINK_DEST="--link-dest=$LATEST_FULL"
fi

# 创建备份目录
mkdir -p $BACKUP_DIR

echo "开始 $BACKUP_TYPE 备份..."

for DIR in "${SOURCE_DIRS[@]}"; do
    if [ -d "$DIR" ]; then
        echo "备份: $DIR"

        # 排除不需要备份的内容
        rsync -av \
          --delete \
          $LINK_DEST \
          --exclude="/home/*/.cache" \
          --exclude="/home/*/.tmp" \
          --exclude="*.log" \
          --exclude="*.tmp" \
          --exclude="*.swp" \
          $DIR $BACKUP_DIR/
    fi
done

# 同步到远程
echo "同步到远程服务器..."
rsync -avz --delete $BACKUP_ROOT/ $REMOTE_USER@$REMOTE_HOST:/remote/backup/

# 清理旧备份(保留最近7天)
find $BACKUP_ROOT -maxdepth 1 -type d -name "*_*" -mtime +7 -exec rm -rf {} \;

echo "备份完成: $BACKUP_DIR"

灾难恢复

恢复脚本

#!/bin/bash
# restore.sh

# 配置
BACKUP_SOURCE="/backup/latest/"
RESTORE_TARGET="/"
REMOTE_BACKUP="backup.example.com:/backup/latest/"

echo "警告:这将覆盖目标目录的文件!"
read -p "确认恢复?(yes/no): " CONFIRM

if [ "$CONFIRM" != "yes" ]; then
    echo "取消恢复"
    exit 0
fi

# 选择恢复源
echo "选择恢复源:"
echo "1) 本地备份 ($BACKUP_SOURCE)"
echo "2) 远程备份 ($REMOTE_BACKUP)"
read -p "选择 (1/2): " SOURCE_CHOICE

case $SOURCE_CHOICE in
    1)
        SOURCE=$BACKUP_SOURCE
        ;;
    2)
        SOURCE=$REMOTE_BACKUP
        ;;
    *)
        echo "无效选择"
        exit 1
        ;;
esac

# 恢复系统
echo "开始恢复..."
rsync -av \
  --delete \
  --exclude="/proc" \
  --exclude="/sys" \
  --exclude="/dev" \
  --exclude="/tmp" \
  --exclude="/run" \
  --exclude="/mnt" \
  --exclude="/media" \
  $SOURCE $RESTORE_TARGET

echo "恢复完成"
echo "建议重启系统"

监控和告警

备份监控脚本

#!/bin/bash
# monitor-backup.sh

# 配置
BACKUP_DIR="/backup"
LOG_FILE="/var/log/backup-monitor.log"
ALERT_EMAIL="admin@example.com"
MIN_FREE_SPACE=10  # GB

# 检查备份目录
if [ ! -d "$BACKUP_DIR" ]; then
    echo "$(date): 错误:备份目录不存在" >> $LOG_FILE
    echo "备份目录不存在" | mail -s "备份监控告警" $ALERT_EMAIL
    exit 1
fi

# 检查磁盘空间
FREE_SPACE=$(df -BG $BACKUP_DIR | awk 'NR==2 {print $4}' | sed 's/G//')
if [ $FREE_SPACE -lt $MIN_FREE_SPACE ]; then
    echo "$(date): 警告:磁盘空间不足 ($FREE_SPACE GB)" >> $LOG_FILE
    echo "备份磁盘空间不足:$FREE_SPACE GB" | mail -s "备份监控告警" $ALERT_EMAIL
fi

# 检查最新备份时间
LATEST_BACKUP=$(find $BACKUP_DIR -type f -name "*.tar.gz" -o -name "*.sql.gz" | xargs ls -t | head -1)
if [ -n "$LATEST_BACKUP" ]; then
    BACKUP_AGE=$(( ($(date +%s) - $(stat -c %Y "$LATEST_BACKUP")) / 3600 ))

    if [ $BACKUP_AGE -gt 24 ]; then
        echo "$(date): 警告:最近备份已超过24小时" >> $LOG_FILE
        echo "最近备份时间:$BACKUP_AGE 小时前" | mail -s "备份监控告警" $ALERT_EMAIL
    fi
else
    echo "$(date): 错误:未找到备份文件" >> $LOG_FILE
    echo "未找到备份文件" | mail -s "备份监控告警" $ALERT_EMAIL
fi

echo "$(date): 备份监控检查完成" >> $LOG_FILE

最佳实践

1. 测试备份

#!/bin/bash
# test-restore.sh

# 创建测试环境
TEST_DIR="/tmp/backup-test"
BACKUP_SOURCE="/backup/latest/"

mkdir -p $TEST_DIR

# 恢复测试
rsync -av --dry-run $BACKUP_SOURCE $TEST_DIR/

# 检查文件完整性
find $BACKUP_SOURCE -type f -exec md5sum {} \; > /tmp/original.md5
rsync -av $BACKUP_SOURCE $TEST_DIR/
find $TEST_DIR -type f -exec md5sum {} \; > /tmp/restored.md5

diff /tmp/original.md5 /tmp/restored.md5

if [ $? -eq 0 ]; then
    echo "备份完整性测试通过"
else
    echo "备份完整性测试失败"
fi

# 清理
rm -rf $TEST_DIR

2. 自动化调度

使用 crontab 定时执行:

# 编辑 crontab
crontab -e

# 每天凌晨2点执行完整备份
0 2 * * * /root/scripts/full-backup.sh

# 每小时执行增量备份
0 * * * * /root/scripts/incremental-backup.sh

# 每天检查备份状态
0 8 * * * /root/scripts/monitor-backup.sh

3. 文档化配置

创建配置文件:

# /etc/backup.conf
BACKUP_SOURCES="/etc /home /var/www"
BACKUP_DEST="/backup"
REMOTE_HOST="backup.example.com"
REMOTE_USER="backup"
KEEP_DAYS=30
EMAIL_ALERTS="admin@example.com"

小结

本章通过实际案例展示了 rsync 在: - 网站部署 - 数据库备份 - 日志收集 - 文件同步 - 灾难恢复 - 监控告警

等方面的应用。这些脚本可以直接使用或根据需要进行修改。

结束语

rsync 是一个功能强大且灵活的工具,掌握它可以大大提高系统管理和数据备份的效率。建议在实际工作中多练习,根据具体需求调整配置和脚本。