自托管服务数据安全实战:Shell 脚本 + Crontab 定时备份 + 异地同步方案

举报
yd_273651526 发表于 2026/10/29 15:25:33 2026/10/29
【摘要】 服务部署只是开始,数据安全才是自托管的命脉。本文记录了一套轻量级自动化备份方案的完整落地过程:使用 Shell 脚本对 Docker 应用数据目录进行定时打包备份,通过 Crontab 调度执行,自动清理过期备份控制磁盘占用,并利用 rsync 将备份异地同步到备用服务器,实现「本机 + 异地」双重保障。全文脚本可直接复用,适合自托管开发者和个人站长参考。

前言

前面两篇文章分别分享了 ECS 的运维优化和 Docker + Nginx 的部署实践,服务跑起来之后,一个更关键的问题摆在面前:数据安全。

我在自己的服务器上托管了多个应用(如图书管理等),业务数据全部挂载在宿主机目录上。一旦出现以下任何一种情况,后果都不堪设想:

  • 磁盘损坏或文件系统故障;
  • 误操作删除了数据目录;
  • 应用升级失败导致数据损坏;
  • 服务器被入侵或遭遇勒索软件。

而容器本身是「易失」的——镜像可以随时重新拉取,配置可以重新编写,唯独数据丢了就是真丢了。所以这套备份方案的原则很朴素:自动化、有保留周期、异地容灾。

一、方案设计

整体思路如下:

数据目录 → tar 打包(带日期命名)→ 本地保留目录
                                    ↓
              Crontab 每日定时调度  ↓
                                    ↓
              自动清理 N 天前的旧备份 → rsync 异地同步

设计要点:

  1. 每日全量打包:个人应用数据量通常在几百 MB 到几 GB,每日全量备份简单可靠,不必引入增量备份的复杂度;
  2. 保留周期:本地保留 7 天,异地保留 30 天,自动清理,避免备份本身把磁盘撑爆;
  3. 备份期间不停服:对挂载目录直接打包,应用持续写入的理论风险用「低峰期执行」来规避(凌晨 3 点);
  4. 失败可感知:脚本记录日志,备份异常时输出到日志文件,便于排查。

二、备份脚本编写

创建脚本 /opt/scripts/backup.sh:

#!/bin/bash

# ===== 配置区 =====
BACKUP_SRC="/your/data/path"        # 需要备份的数据目录
BACKUP_DST="/opt/backups"           # 本地备份存放目录
KEEP_DAYS=7                         # 本地保留天数
LOG_FILE="/opt/scripts/backup.log"  # 日志文件
DATE=$(date +%Y-%m-%d_%H-%M-%S)
FILENAME="backup_${DATE}.tar.gz"

# ===== 开始备份 =====
echo "[$(date '+%F %T')] 备份开始: ${BACKUP_SRC}" >> ${LOG_FILE}

mkdir -p ${BACKUP_DST}

tar -czf ${BACKUP_DST}/${FILENAME} -C "$(dirname ${BACKUP_SRC})" "$(basename ${BACKUP_SRC})"

if [ $? -eq 0 ]; then
    SIZE=$(du -h ${BACKUP_DST}/${FILENAME} | awk '{print $1}')
    echo "[$(date '+%F %T')] 备份成功: ${FILENAME} (大小: ${SIZE})" >> ${LOG_FILE}
else
    echo "[$(date '+%F %T')] 备份失败!" >> ${LOG_FILE}
    exit 1
fi

# ===== 清理过期备份 =====
find ${BACKUP_DST} -name "backup_*.tar.gz" -mtime +${KEEP_DAYS} -delete
echo "[$(date '+%F %T')] 已清理 ${KEEP_DAYS} 天前的旧备份" >> ${LOG_FILE}

赋予执行权限并手动跑一次验证:

chmod +x /opt/scripts/backup.sh
/opt/scripts/backup.sh
cat /opt/scripts/backup.log

几个细节说明:

  • tar -C 参数:先切换到父目录再打包,这样解压出来的是目录本身而不是一长串绝对路径,恢复时更干净;
  • -mtime +7 -delete:find 一行搞定过期清理,比手写循环靠谱;
  • 每步操作都写日志,出问题时可以快速定位是打包失败还是清理失败。

三、Crontab 定时调度

编辑 root 用户的定时任务:

crontab -e

添加一行,每天凌晨 3 点执行:

0 3 * * * /opt/scripts/backup.sh >> /opt/scripts/cron.log 2>&1

保存后确认任务已生效:

crontab -l

踩坑提醒:如果你在脚本里用了 docker 命令(比如先 docker stop 再备份),crontab 环境下的 PATH 和登录 shell 不同,经常出现「手动能跑、定时就失败」的问题。解决办法是在 crontab 顶部补一行 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin,或者脚本内全部使用绝对路径。

四、rsync 异地同步

本地备份只能防误删,防不了整盘故障。rsync 把备份同步到另一台服务器(或同厂商不同可用区的机器),才算真正的容灾。

4.1 配置免密登录

ssh-keygen -t ed25519
ssh-copy-id user@备份服务器IP

4.2 同步脚本

在 backup.sh 末尾追加同步逻辑,或单独写一个 sync_backup.sh:

#!/bin/bash
REMOTE="user@备份服务器IP:/opt/remote_backups/"
LOCAL="/opt/backups/"

rsync -avz --delete ${LOCAL} ${REMOTE}

if [ $? -eq 0 ]; then
    echo "[$(date '+%F %T')] 异地同步成功" >> /opt/scripts/backup.log
else
    echo "[$(date '+%F %T')] 异地同步失败,请检查网络与凭据" >> /opt/scripts/backup.log
fi
  • -a:归档模式,保留权限、时间戳等属性;
  • -z:传输时压缩,节省带宽;
  • --delete:让远端与本地保持一致(本地已清理的旧备份远端也删掉,远端保留周期可按需在远端再配置一层)。

同样加入 crontab,错开几分钟执行:

10 3 * * * /opt/scripts/sync_backup.sh >> /opt/scripts/cron.log 2>&1

4.3 验证恢复能力

**备份不演练等于没备份。**找一次空闲时间,把备份包在临时目录解压,确认数据完整:

mkdir /tmp/restore_test
tar -xzf /opt/backups/backup_xxx.tar.gz -C /tmp/restore_test
diff -r /tmp/restore_test/your_data /your/data/path

能完整恢复,这套方案才算闭环。

五、进阶优化方向

这套方案够用之后,还可以按需演进:

  1. 对象存储归档:如果有华为云 OBS 等对象存储,可用 obsutil 或 S3 兼容工具把备份再推一份到云端,进一步降低成本(冷存储价格很低);
  2. 备份加密:数据敏感的话,打包后用 openssl enc -aes-256-cbc 加密,密钥与备份分开存放;
  3. 通知告警:脚本结尾接一个 webhook(如企业微信机器人),备份失败时主动推送,而不是被动翻日志;
  4. 数据库场景:如果应用用了 MySQL/PostgreSQL,不能直接 tar 数据目录,应改用 mysqldump / pg_dump 逻辑导出后再打包。

六、总结

回顾整套方案:

  • 一个脚本:Shell 打包 + 自动清理,几十行代码;
  • 一个定时任务:Crontab 每日调度,全自动无人值守;
  • 一次异地同步:rsync 到备用服务器,实现双重容灾。

自托管的最大风险不是服务挂了(重启就能恢复),而是数据没了。花半小时搭好这套备份体系,之后每天凌晨自动运行,是性价比最高的运维投入。

后续我还会分享自托管服务的监控告警和应用升级回滚实践,欢迎关注交流。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。