Obsidian
Mac
在Mac使用终端命令安装DMG
终端无法访问外挂硬盘
小诗词
SSH 无密码登录及 Rsync 同步配置笔记
Cron专题
at 命令笔记
Kostal 服务器密码
Docker 安装指南
MySQL Workbench 数据库迁移:哪些内容不需要迁移?
kostia
配置管理系统(ConfigManager)设计说明
本文档使用 MrDoc 发布
-
+
首页
SSH 无密码登录及 Rsync 同步配置笔记
## 背景 - **目标**:从服务器A(`cnsfail001`,用户 `li054`)同步 Docker 卷数据(`/var/lib/docker/volumes/open-webui/_data`,含 `webui.db`)到服务器B(`sam-pn64`,用户 `sam`,路径 `/diskA/test_rsync/open-webui`),并通过 `cron` 实现三种同步: - 每5分钟(调试用)。 - 每天17:00(日常用)。 - 2025年4月25日20:00(一次性)。 - **要求**: - 使用 `rsync` 同步,需停止/重启服务器B的 Docker 容器(假设名为 `open-webui`)以确保数据一致性。 - 服务器A的 `li054` 用户非 `root`,但有 `sudo` 权限,需通过 `sudo` 访问 Docker 卷。 - 配置SSH无密码登录以支持 `cron` 自动化。 - **问题**: - 初始SSH无密码登录配置失败,`sudo rsync` 提示输入 `sam@sam-pn64` 密码。 - 环境变量未正确传递导致 `rsync` 错误(`Could not resolve hostname`)。 - `sudo` 环境重置 `HOME`,影响SSH密钥使用。 ## 问题分析与解决方案 ### 1. SSH 无密码登录问题 - **症状**: - `ssh sam@sam-pn64` 最终无需密码(2025年4月22日确认),但 `sudo rsync ...` 提示密码。 - 公钥已存在于服务器B的 `/home/sam/.ssh/authorized_keys`,但 `sudo` 环境未正确使用 `li054` 的SSH密钥。 - **原因**: - `sudo` 重置 `HOME` 环境变量(可能为 `/root`),未使用 `/home/li054/.ssh/`。 - 服务器A的 `~/.ssh/id_rsa.pub` 权限初始为 `640`,应为 `644`。 - 服务器B的 `authorized_keys` 包含无关公钥(`kostalcn\li054@cn221428`),可能干扰。 - **解决方案**: 1. **修复服务器A密钥权限**: ```bash chmod 700 ~/.ssh chmod 600 ~/.ssh/id_rsa chmod 644 ~/.ssh/id_rsa.pub ``` 2. **重新复制公钥**: ```bash ssh-copy-id -f sam@sam-pn64 ``` 3. **清理服务器B的** `authorized_keys`: - 保留 `ssh-rsa ... li054@cnsfail001.cn.kostal.int`,删除无关公钥。 ```bash cp /home/sam/.ssh/authorized_keys /home/sam/.ssh/authorized_keys.bak nano /home/sam/.ssh/authorized_keys chmod 600 /home/sam/.ssh/authorized_keys chown sam:sam /home/sam/.ssh/authorized_keys ``` 4. **确保服务器B权限**: ```bash chmod 755 /home/sam chmod 700 /home/sam/.ssh chmod 600 /home/sam/.ssh/authorized_keys ``` 5. **检查服务器B的SSH配置**: - 编辑 `/etc/ssh/sshd_config`,确保: ```bash PubkeyAuthentication yes AuthorizedKeysFile .ssh/authorized_keys ``` - 重启服务: ```bash sudo systemctl restart sshd ``` 6. **处理** `sudo` **环境**: - 显式指定SSH密钥和 `HOME`: ```bash sudo HOME=/home/li054 rsync -avz --delete -e "ssh -i /home/li054/.ssh/id_rsa" ... ``` 7. **验证**: ```bash ssh sam@sam-pn64 # 无需密码 sudo HOME=/home/li054 rsync -avz --delete -e "ssh -i /home/li054/.ssh/id_rsa" /var/lib/docker/volumes/open-webui/_data/ sam@sam-pn64:/diskA/test_rsync/open-webui/ ``` ### 2. 环境变量问题 - **症状**: - 运行 `sudo rsync $RSYNC_OPTIONS -e ssh "$SOURCE_DIR/" "$DEST_SERVER:$DEST_DIR/"` 报错: ``` ssh: Could not resolve hostname : Name or service not known ``` - **原因**:变量(如 `SOURCE_DIR`、`DEST_SERVER`)未在脚本或 `sudo` 环境中定义。 - **解决方案**: - 在脚本中硬编码变量: ```bash SOURCE_DIR="/var/lib/docker/volumes/open-webui/_data" DEST_SERVER="sam@sam-pn64" DEST_DIR="/diskA/test_rsync/open-webui" ``` - 添加变量检查: ```bash if [ -z "$SOURCE_DIR" ] || [ -z "$DEST_SERVER" ] || [ -z "$DEST_DIR" ]; then log "Error: SOURCE_DIR, DEST_SERVER, or DEST_DIR not set" exit 1 fi ``` ### 3. 脚本执行问题 - **症状**:直接运行脚本片段(`log` 和 `rsync`)失败,因缺少上下文(变量、函数)。 - **解决方案**:使用完整脚本(见下文),确保所有变量和函数定义。 ## 最终脚本 以下是最终的 `sync_docker_data.sh` 脚本,已解决SSH无密码登录和环境变量问题,用户确认可行(2025年4月23日): ```bash #!/bin/bash # sync_docker_data.sh # 配置 SOURCE_DIR="/var/lib/docker/volumes/open-webui/_data" # 服务器A的源路径 DEST_SERVER="sam@sam-pn64" # 服务器B的SSH地址 DEST_DIR="/diskA/test_rsync/open-webui" # 服务器B的目标路径 RSYNC_OPTIONS="-avz --delete" # rsync选项 LOG_FILE="/var/log/docker_sync.log" # 日志文件 CONTAINER_NAME="open-webui" # 服务器B的容器名称(待确认) SSH_KEY="/home/li054/.ssh/id_rsa" # 显式指定SSH密钥 # 日志记录函数 log() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | sudo tee -a "$LOG_FILE" } # 检查环境变量 if [ -z "$SOURCE_DIR" ] || [ -z "$DEST_SERVER" ] || [ -z "$DEST_DIR" ]; then log "Error: SOURCE_DIR, DEST_SERVER, or DEST_DIR not set" exit 1 fi # 开始同步 log "Starting Docker data sync..." # 停止服务器B的容器 log "Stopping container $CONTAINER_NAME on $DEST_SERVER..." ssh -i "$SSH_KEY" "$DEST_SERVER" "docker stop $CONTAINER_NAME" || { log "Failed to stop container $CONTAINER_NAME on $DEST_SERVER" exit 1 } # 执行rsync(使用sudo和显式SSH密钥) log "Syncing $SOURCE_DIR to $DEST_SERVER:$DEST_DIR..." sudo HOME=/home/li054 rsync $RSYNC_OPTIONS -e "ssh -i $SSH_KEY" "$SOURCE_DIR/" "$DEST_SERVER:$DEST_DIR/" if [ $? -eq 0 ]; then log "Sync completed successfully" else log "Sync failed with error code $?" exit 1 fi # 重启服务器B的容器 log "Starting container $CONTAINER_NAME on $DEST_SERVER..." ssh -i "$SSH_KEY" "$DEST_SERVER" "docker start $CONTAINER_NAME" || { log "Failed to start container $CONTAINER_NAME on $DEST_SERVER" exit 1 } log "Sync process finished" ``` **保存和权限**: ```bash mv sync_docker_data.sh /home/li054/sync_docker_data.sh chmod +x /home/li054/sync_docker_data.sh ``` **日志文件权限**: ```bash sudo touch /var/log/docker_sync.log sudo chown li054:li054 /var/log/docker_sync.log sudo chmod 664 /var/log/docker_sync.log ``` **测试**: ```bash sudo /home/li054/sync_docker_data.sh ``` - 确认无需密码。 - 检查 `/var/log/docker_sync.log`、服务器B的 `/diskA/test_rsync/open-webui/` 和容器状态: ```bash ssh sam@sam-pn64 "ls -l /diskA/test_rsync/open-webui" ssh sam@sam-pn64 "docker ps" ``` ## Cron 配置 为实现三种同步需求,配置 `li054` 用户的 `crontab`,使用 `sudo` 运行脚本。 ### 配置sudo无密码 ```bash sudo visudo -f /etc/sudoers.d/li054 ``` 添加: ```bash li054 ALL=(ALL) NOPASSWD: /home/li054/sync_docker_data.sh ``` 验证: ```bash sudo -l ``` ### 三种同步方式 1. **每5分钟同步(调试用)**: - **Cron表达式**:`*/5 * * * *` - **配置**: ```bash crontab -e ``` 添加: ```bash */5 * * * * sudo /home/li054/sync_docker_data.sh >> /var/log/docker_sync.log 2>&1 ``` - **禁用**:调试后注释或删除: ```bash # */5 * * * * sudo /home/li054/sync_docker_data.sh >> /var/log/docker_sync.log 2>&1 ``` 2. **每天17:00同步(日常用)**: - **Cron表达式**:`0 17 * * *` - **配置**: ```bash crontab -e ``` 添加: ```bash 0 17 * * * sudo /home/li054/sync_docker_data.sh >> /var/log/docker_sync.log 2>&1 ``` 3. **2025年4月25日20:00同步(一次性)**: - **Cron表达式**:`0 20 25 4 *` - **配置**: ```bash crontab -e ``` 添加: ```bash 0 20 25 4 * sudo /home/li054/sync_docker_data.sh >> /var/log/docker_sync.log 2>&1 ``` - **清理**:2025年4月26日后移除: ```bash crontab -e # 删除或注释掉上述行 ``` ### 完整Cron配置 ```bash crontab -e ``` 添加: ```bash # 每5分钟同步(调试用,调试后注释或删除) */5 * * * * sudo /home/li054/sync_docker_data.sh >> /var/log/docker_sync.log 2>&1 # 每天17:00同步(日常用) 0 17 * * * sudo /home/li054/sync_docker_data.sh >> /var/log/docker_sync.log 2>&1 # 2025年4月25日20:00同步(一次性,运行后可删除) 0 20 25 4 * sudo /home/li054/sync_docker_data.sh >> /var/log/docker_sync.log 2>&1 ``` **验证**: ```bash crontab -l ``` ## 验证步骤 1. **脚本测试**: ```bash sudo /home/li054/sync_docker_data.sh ``` - 确认无需密码,日志正常,同步成功,容器正常。 2. **调试同步(每5分钟)**: - 启用后等待5分钟,检查 `/var/log/docker_sync.log` 和服务器B的 `/diskA/test_rsync/open-webui/`。 - 禁用调试任务。 3. **日常同步(每天17:00)**: - 临时改为 `*/10 * * * *` 测试,确认后恢复 `0 17 * * *`。 4. **一次性同步(2025年4月25日20:00)**: - 模拟测试:临时改为 `0 20 * * *`,确认后恢复。 ## 注意事项 1. **SSH无密码登录**: - 已通过 `HOME=/home/li054` 和 `-i /home/li054/.ssh/id_rsa` 解决。 - 如问题复现,检查: ```bash ssh -v sam@sam-pn64 ssh sam@sam-pn64 "sudo tail -f /var/log/auth.log" ``` 2. **sudo权限**: - 确保 `li054` 用户对脚本的 `sudo` 无密码权限。 - 如果 `rsync` 报权限错误,检查: ```bash ls -ld /var/lib/docker /var/lib/docker/volumes /var/lib/docker/volumes/open-webui ``` 调整(谨慎): ```bash sudo chmod -R o+rx /var/lib/docker/volumes/open-webui ``` 3. **数据一致性**: - 同步 `webui.db` 时,停止服务器B容器避免锁或损坏。 - 每5分钟同步可能影响服务,调试后禁用。 4. **目标目录**: - 确保服务器B的 `/diskA/test_rsync/open-webui/` 已创建: ```bash ssh sam@sam-pn64 "mkdir -p /diskA/test_rsync/open-webui && chmod -R u+rwX /diskA/test_rsync/open-webui" ``` 5. **日志管理**: - 配置 `logrotate`: ```bash sudo nano /etc/logrotate.d/docker_sync ``` 添加: ```bash /var/log/docker_sync.log { weekly rotate 4 compress missingok } ``` 6. **备份**: - 首次同步前,备份服务器B: ```bash ssh sam@sam-pn64 "tar -czf /diskA/test_rsync_backup.tar.gz /diskA/test_rsync/open-webui" ``` ## 待确认事项 1. **容器名称**: - 脚本假设服务器B容器名为 `open-webui`。请确认: ```bash ssh sam@sam-pn64 "docker ps -a" ``` - 如不同,修改脚本的 `CONTAINER_NAME`。 2. **通知需求**: - 是否需要同步失败/成功的通知?例如: ```bash echo "Sync failed" | mail -s "Docker Sync Error" your_email@example.com ``` 3. **排除文件**: - 是否需要排除 `audit.log` 或 `cache/`?可修改: ```bash RSYNC_OPTIONS="-avz --delete --exclude 'audit.log' --exclude 'cache/'" ``` 4. **网络环境**: - 服务器A和B在同一内网(IP `10.190.x.x`),无需公网安全措施。如有公网需求,需加强SSH配置。 ## 总结 - **问题解决**:通过显式SSH密钥(`-i /home/li054/.ssh/id_rsa`)、`HOME=/home/li054` 和环境变量检查,解决SSH无密码登录和 `rsync` 问题。 - **脚本**:`sync_docker_data.sh` 已可行(2025年4月23日确认)。 - **Cron**:配置三种同步方式(每5分钟、每天17:00、2025年4月25日20:00)。 - **下一步**: - 配置 `cron` 并测试。 - 确认容器名称和通知需求。 - 定期检查日志和备份。 如需进一步优化(通知、错误重试、文件排除),请随时告知! ## 完整源码 ```bash #!/bin/bash # sync_docker_data.sh # 配置 SOURCE_DIRS=( "/var/lib/docker/volumes/open-webui/_data" # open-webui 源路径 "/var/lib/docker/volumes/pipelines/_data" # pipelines 源路径 ) DEST_SERVER="kochiae@cnsfaiappl002" # 服务器B的SSH地址 DEST_DIRS=( "/home/kochiae/dockers/open-webui" # open-webui 目标路径 "/home/kochiae/dockers/pipelines" # pipelines 目标路径 ) RSYNC_OPTIONS="-avz --delete" # rsync选项 LOG_FILE="/var/log/docker_sync.log" # 日志文件 CONTAINER_NAMES=("open-webui" "pipelines") # 服务器B的容器名称列表 SSH_KEY="/home/li054/.ssh/id_rsa" # 显式指定SSH密钥 # 日志记录函数 log() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | sudo tee -a "$LOG_FILE" } # 检查环境变量 if [ ${#SOURCE_DIRS[@]} -ne ${#DEST_DIRS[@]} ]; then log "Error: Number of SOURCE_DIRS and DEST_DIRS do not match" exit 1 fi for dir in "${SOURCE_DIRS[@]}" "${DEST_DIRS[@]}"; do if [ -z "$dir" ]; then log "Error: One or more source or destination directories not set" exit 1 fi done if [ -z "$DEST_SERVER" ]; then log "Error: DEST_SERVER not set" exit 1 fi # 开始同步 log "Starting Docker data sync..." # 停止服务器B的容器 for CONTAINER_NAME in "${CONTAINER_NAMES[@]}"; do log "Stopping container $CONTAINER_NAME on $DEST_SERVER..." ssh -i "$SSH_KEY" "$DEST_SERVER" "docker stop $CONTAINER_NAME" || { log "Failed to stop container $CONTAINER_NAME on $DEST_SERVER" exit 1 } done # 执行rsync(同步所有源目录到对应目标目录) for ((i=0; i<${#SOURCE_DIRS[@]}; i++)); do SOURCE_DIR="${SOURCE_DIRS[$i]}" DEST_DIR="${DEST_DIRS[$i]}" log "Syncing $SOURCE_DIR to $DEST_SERVER:$DEST_DIR..." sudo HOME=/home/li054 rsync $RSYNC_OPTIONS -e "ssh -i $SSH_KEY" "$SOURCE_DIR/" "$DEST_SERVER:$DEST_DIR/" || { log "Failed to sync $SOURCE_DIR to $DEST_SERVER:$DEST_DIR with error code $?" exit 1 } log "Sync of $SOURCE_DIR to $DEST_SERVER:$DEST_DIR completed successfully" done # 重启服务器B的容器 for CONTAINER_NAME in "${CONTAINER_NAMES[@]}"; do log "Starting container $CONTAINER_NAME on $DEST_SERVER..." ssh -i "$SSH_KEY" "$DEST_SERVER" "docker start $CONTAINER_NAME" || { log "Failed to start container $CONTAINER_NAME on $DEST_SERVER" exit 1 } done log "Sync process finished" ```
admin
2025年4月22日 11:30
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
分享
链接
类型
密码
更新密码