第四章:实战应用¶
本章通过实际案例展示 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 是一个功能强大且灵活的工具,掌握它可以大大提高系统管理和数据备份的效率。建议在实际工作中多练习,根据具体需求调整配置和脚本。