rsync同步文件到远程服务器脚本
一、创建ssh密钥认证
SSH 密钥认证(最推荐,安全且标准) ,如果使用nfs挂载目录方式,则跳过此步骤
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 这是 Linux 远程管理最标准、最安全的做法。
(1). 生成密钥对(在本地/源服务器执行,如果已有可跳过): ssh-keygen -t rsa -b 4096 # 一路回车即可
(2). 将公钥复制到远程服务器: ssh-copy-id user@remote_host # 或者手动复制本地 ~/.ssh/id_rsa.pub 的内容到远程服务器的 ~/.ssh/authorized_keys 文件中
(3). 权限设置 # 本地修复 chmod 600 ~/.ssh/id_ed25519
# 远程修复 chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys
(4). 验证: 再次执行 rsync 命令,无需输入密码即可直接同步。
|
如果远程服务器修改了用户登录密码,SSH 密钥认证完全不受影响,无需重新生成密钥,也无需重新部署公钥。
只有在以下场景下,才需要处理 SSH 密钥:
| 场景 |
操作建议 |
| 私钥泄露或丢失 |
必须重新生成。立即生成新的密钥对,将新公钥部署到服务器,并从服务器的 authorized_keys 中删除旧公钥。 |
| 更换客户端设备 |
无需重新生成(可选)。你可以将原有的私钥安全复制到新设备,或者为新设备生成一套新的密钥对并部署公钥。 |
| 服务器重装系统 |
需要重新部署。因为 ~/.ssh/authorized_keys 文件被清空,你需要将本地公钥再次复制到新系统中。 |
| 误删了 authorized_keys |
需要重新部署。只需将本地公钥再次追加到服务器的 ~/.ssh/authorized_keys 文件中即可,无需生成新密钥。 |
二、创建同步脚本
1.sync同步至nfs目录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
| #!/usr/bin/env bash
# ============================================================================== # 严格模式设置 # ============================================================================== set -euo pipefail # e: 出错立即退出; u: 未定义变量报错; o pipefail: 管道中任一命令失败则整体失败
# ============================================================================== # 配置变量 # ============================================================================== SRC_DIR="/backup" DST_DIR="/backup-rsync" LOG_FILE="/var/log/rsync_backup/sync.log" LOCK_FILE="/tmp/rsync_backup.lock" RSYNC_TIMEOUT=600 # rsync IO 超时时间 HEALTH_CHECK_TIMEOUT=10 # 健康检查超时时间
# ============================================================================== # 函数定义 # ==============================================================================
# 日志函数:同时输出到屏幕和日志文件 log() { local msg="[$(date '+%Y-%m-%d %H:%M:%S')] $1" echo "$msg" | tee -a "${LOG_FILE}" }
# 清理函数:确保脚本退出时释放锁 cleanup() { # 如果文件描述符 200 已打开,则解锁并关闭 if [ -n "${LOCK_FD:-}" ]; then flock -u 200 2>/dev/null || true exec 200>&- 2>/dev/null || true fi } trap cleanup EXIT
# 健康检查函数:检查目录是否可读写且非空(可选) check_dir_health() { local dir="$1" local label="$2" # 用于日志标识 "Source" 或 "Destination"
# 1. 检查目录是否存在且为目录 if [ ! -d "$dir" ]; then log "ERROR: ${label} directory '$dir' does not exist or is not a directory." return 1 fi
# 2. 检查是否可写 (对于源目录,至少需要可读;对于目标,需要可写) # 这里统一检查可写性,因为 rsync 需要在目标端创建临时文件 # 如果是纯源端检查,可以改为 [ -r "$dir" ] && [ -x "$dir" ] local test_f="$dir/.health_check_tmp_$$" if ! timeout "${HEALTH_CHECK_TIMEOUT}" bash -c "echo 'test' > '$test_f' && rm -f '$test_f'" 2>/dev/null; then log "ERROR: ${label} directory '$dir' is not writable or IO is stuck (NFS stale?)." return 1 fi # 3. 额外安全检查:防止源目录为空导致 --delete 误删目标 if [ "$label" == "Source" ]; then # 尝试列出少量文件,确认源目录非空且可读 if [ -z "$(ls -A "$dir" 2>/dev/null)" ]; then log "WARNING: Source directory '$dir' appears empty. Aborting to prevent accidental deletion on destination." return 1 fi fi
return 0 }
# ============================================================================== # 主逻辑 # ==============================================================================
# 1. 获取排他锁 (Non-blocking: 如果已被锁定,则直接退出,避免排队) exec 200>"$LOCK_FILE" if ! flock -n 200; then log "ERROR: Another instance is running (lock file: $LOCK_FILE). Exiting." exit 1 fi LOCK_FD=200 # 标记锁已获取,供 cleanup 使用
log "==========================================" log "Backup sync started." log "Source: $SRC_DIR" log "Target: $DST_DIR" log "=========================================="
# 2. 前置健康检查 # 检查源目录:必须存在、可读、非空(防止误删) if ! check_dir_health "$SRC_DIR" "Source"; then log "ABORTING: Source health check failed." exit 1 fi
# 检查目标目录:必须存在、可写 if ! check_dir_health "$DST_DIR" "Destination"; then log "ABORTING: Destination health check failed." exit 1 fi
log "Health checks passed. Starting rsync..."
# 3. 执行 rsync # 关键参数说明: # --delete: 删除目标端多余文件,保持镜像一致 # --timeout: 防止 NFS/网络卡死导致进程永久挂起 # --partial: 保留部分传输的文件,支持断点续传 # --stats: 输出统计信息,方便日志分析 rsync -avz --delete \ --timeout="${RSYNC_TIMEOUT}" \ --partial \ --stats \ "$SRC_DIR/" "$DST_DIR/" >> "$LOG_FILE" 2>&1
# 4. 检查退出码 # 由于设置了 set -e,如果 rsync 失败,脚本会自动终止并跳到 trap # 如果执行到这里,说明成功 log "Sync completed successfully."
log "==========================================" log "Backup sync finished." log "=========================================="
exit 0
|
含义:
-n 等同于 --dry-run (模拟运行)
它会让 rsync 执行完整的同步检查流程,列出所有将会被传输、更新或删除的文件,但不会实际执行任何文件复制或修改操作。
主要用途:
安全预览:在执行可能具有破坏性的操作(如使用 --delete 参数)之前,先确认哪些文件会被影响,防止误删重要数据。
调试命令:验证排除规则(--exclude)或包含规则是否按预期工作。
估算传输量:查看即将同步的文件列表和大小,预估所需时间和带宽。
常用组合示例:
通常与 -v(详细模式)一起使用,以便清晰地看到输出结果:
--delete 用于实现镜像同步(Mirror Sync)。它的作用是删除目标目录($DST_DIR)中存在、但源目录($SRC_DIR)中不存在的文件和目录。
核心逻辑:
- 以源为准:同步结束后,目标目录的内容将与源目录完全一致。
- 清理多余文件如果源端删除了某个文件,执行同步后,目标端对应的文件也会被删除。
- 应用场景:常用于静态网站部署、代码发布或需要保持两端数据严格一致的备份场景。
⚠️ 高危风险警告:
这是 rsync 中最危险的参数之一。如果源目录因为挂载失败、权限不足或路径错误导致内容为空或不完整,--delete 会忠实地将目标目录中的大量数据清空。
2.rsync通过ssh同步到远程目录
需要在第一步中创建ssh密钥认证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
| #!/bin/bash
# ============================================================================== # 严格模式设置 # ============================================================================== set -euo pipefail # e: 出错立即退出; u: 未定义变量报错; o pipefail: 管道中任一命令失败则整体失败
# ============================================================================== # 配置变量 # ============================================================================== DATE_D=$(date +%Y%m%d) SYNC_DAYS=2 BACKUP_PATH="/backup" REMOTE_USER="tidb" REMOTE_HOST="172.28.6.120" REMOTE_PATH="/backup/10.195.6.31" LOGFILE="/home/tidb/script/tidb_rsync_backup_${DATE_D}.log" LOCKFILE="/tmp/rsync_backup.lock"
# ============================================================================== # 函数定义 # ==============================================================================
# 日志函数:同时输出到屏幕和日志文件 log() { local msg="[$(date '+%Y-%m-%d %H:%M:%S')] $1" echo "$msg" | tee -a "${LOGFILE}" }
# 清理函数:确保脚本退出时释放锁 cleanup() { # 如果文件描述符 200 已打开,则解锁并关闭 if [ -n "${LOCK_FD:-}" ]; then flock -u 200 2>/dev/null || true exec 200>&- 2>/dev/null || true fi } trap cleanup EXIT
# ============================================================================== # 主逻辑 # ==============================================================================
# 1. 获取排他锁 (Non-blocking: 如果已被锁定,则直接退出,避免排队) exec 200>"$LOCKFILE" if ! flock -n 200; then log "ERROR: Another instance is running (lock file: $LOCKFILE). Exiting." exit 1 fi LOCK_FD=200 # 标记锁已获取,供 cleanup 使用
log "==========================================" log "Backup started. Date: ${DATE_D}" log "Source: ${BACKUP_PATH}" log "Target: ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_PATH}" log "=========================================="
# 2. 前置检查:确保备份目录存在 if [ ! -d "$BACKUP_PATH" ]; then log "ERROR: Backup path '$BACKUP_PATH' does not exist." exit 1 fi
# 3. 执行同步 # 注意:使用 subshell () 包裹 cd,防止改变当前脚本的工作目录 # 使用 --files-from=- 配合 find 的相对路径 ( cd "$BACKUP_PATH" # 查找最近 SYNC_DAYS 天内修改的文件 # 注意:find 输出相对路径,如 ./data/file.txt find . -type f -mtime -"${SYNC_DAYS}" -print0 | \ rsync -avz \ --partial \ --append-verify \ --timeout=600 \ --files-from=- \ --from0 \ -e "ssh -o ServerAliveInterval=30 -o ServerAliveCountMax=3" \ ./ "${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_PATH}" ) >> "$LOGFILE" 2>&1
# 4. 检查退出码 # 由于设置了 set -e 和 pipefail,如果上面命令失败,脚本会自动终止并跳到 trap # 如果执行到这里,说明成功 log "Sync completed successfully."
# 5. 可选:清理旧备份逻辑(示例) # find /backup -type f -mtime +30 -delete # log "Old backups cleaned."
log "==========================================" log "Backup finished." log "=========================================="
exit 0
改进: # 优化点: # 1. 移除 --checksum:避免全量哈希计算,极大提升启动速度。 # 2. 保留 --append-verify:确保断点续传的安全性。 # 3. 添加 --inplace (可选):如果文件很大且经常微调,--inplace 比默认的先传临时文件再改名更快,但会失去原子性。对于备份,默认行为(临时文件)更安全,建议先不加 inplace。 # 4. 添加 -h (--human-readable):方便看日志
|