数据备份管理系统教程:MySQL/目录/InfluxDB/ETCD 备份到本地与 S3

数据库、服务器目录、InfluxDB、ETCD,各有一套备份办法:mysqldump、tar、influx backup、etcdctl snapshot,定时任务散落在 crontab 里,出问题了才发现备份早停了。system-backu(注意仓库名就是 system-backu,少了个 p,不是拼写错误)把这些收拢到一个带 Web 界面的备份系统里:数据源、存储目标、定时调度、保留策略、还原、运行历史,全部可视化操作,备份目标支持本地目录和 S3 兼容对象存储。这篇教程讲部署、配置和使用全流程。

一、项目简介

system-backu 是 git.cnbugs.com 上 AI-Agent 组织的一个开源项目(仓库地址 https://git.cnbugs.com/AI-Agent/system-backu),定位是带 Web 操作界面的数据备份管理系统。它支持把 MySQL 数据库、服务器目录、InfluxDB、ETCD 备份到本地目录或 S3 兼容对象存储(AWS S3 / MinIO / Ceph),支持手动触发、Cron 定时调度、备份保留策略,以及从备份还原。

后端是 Python 3.11 + FastAPI + SQLAlchemy 2 + APScheduler,前端是 Vite + React 18 + TypeScript + Ant Design 5,数据库用 SQLite(可平滑迁移 PostgreSQL)。部署上后端是 systemd 服务(8765 端口),前端是 Docker 容器里的 Nginx(5173 端口)。

二、功能特性

  • 多数据源:MySQL 数据库(mysqldump)、服务器目录(tar.gz)、InfluxDB、ETCD。
  • 多存储目标:本地目录、S3 兼容对象存储(AWS S3 / MinIO / Ceph)。
  • Cron 定时调度:标准 5 段 cron 表达式。
  • 备份还原:从备份恢复 MySQL 库 / 解压目录。
  • 保留策略:保留最近 N 个 + 保留 N 天,双重控制。
  • JWT 登录认证:RBAC 权限管理(admin/operator)。
  • 运行历史与日志:每次备份的执行详情、SHA256 校验、大小、耗时。
  • 敏感字段加密:密码、Token 在数据库中 Fernet 加密存储,前端永远看不到明文。
  • 文件浏览:存储目标下的备份文件列表查看。

三、技术架构

层技术选型说明
后端Python 3.11、FastAPI、SQLAlchemy 2、APSchedulersystemd 服务,8765 端口,入口 backend/app/main.py
前端Vite + React 18 + TypeScript + Ant Design 5Docker 容器(Nginx 反代),5173 端口
数据库SQLite(可平滑迁移 PostgreSQL)文件 /root/system-backu/data/backend/backup.db
存储本地目录 / S3 兼容对象存储aiofiles / aioboto3 异步读写
备份工具mysqldump、tar、influx CLI、etcdctl调用宿主机上的现成工具
敏感字段加密Fernet(cryptography 库)数据源密码、Token 加密后存库
数据库迁移Alembicbackend/alembic/,版本 0001/0002

架构上浏览器先到前端容器(Nginx 反代),再到后端服务,后端连 SQLite 和备份文件目录。所有数据都在宿主机上,容器重启不会丢失,备份文件通过文件系统直接访问和下载。备份文件的组织方式是按“任务名 / 日期 /”分目录存放。

四、适用场景

  • 业务数据库日常备份:MySQL 每天定时 mysqldump,保留最近 30 天,支持一键还原。
  • 配置文件与数据目录备份:/etc、应用数据目录定时打 tar.gz,推到 MinIO 或 S3。
  • ETCD 与 InfluxDB 备份:K8s 集群的 ETCD 快照、时序库的定期备份,统一在一个界面里管。
  • 小团队备份中枢:没有专职备份系统,几个服务、几个库,用一个 Web 界面管定时任务和保留策略。

五、环境准备

依赖工具要先装好,备份执行时后端会直接调用它们:

依赖用途安装方法
Python 3.11+后端运行系统自带或自行安装
Docker前端容器仅前端容器需要
mysqldump备份 MySQLmysql-client 包
etcdctl备份 ETCD随 ETCD 分发
influx CLI备份 InfluxDB随 InfluxDB 分发
# Debian/Ubuntu 装 mysql-client(提供 mysqldump)
apt install -y mysql-client

# RHEL/CentOS 装 mysql 客户端
dnf install -y mysql

# 确认工具都在 PATH 里
which mysqldump etcdctl influx
mysqldump --version
etcdctl version

六、部署:后端 systemd + 前端 Docker

第一步准备环境变量。项目根目录和 backend 目录下都有 .env.example 模板,复制成 .env 再编辑,至少设置三项:

cd /root/system-backu
cp .env.example .env

# 生成 SECRET_KEY(JWT 签名)
openssl rand -hex 32

# 生成 FERNET_KEY(敏感字段加密)
python3 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"

# 编辑 .env,至少设置这三项:
#   SECRET_KEY               — 上面生成的 64 位十六进制串
#   FERNET_KEY               — 上面生成的 Fernet key
#   INITIAL_ADMIN_PASSWORD   — 管理员初始密码(登录后可在页面修改)

第二步起后端(systemd 服务,开机自启):

cd /root/system-backu/backend
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

# 部署 systemd 服务
cp deploy/backup-backend.service /etc/systemd/system/
systemctl daemon-reload
systemctl enable backup-backend
systemctl start backup-backend

# 查看状态和日志
systemctl status backup-backend --no-pager
journalctl -u backup-backend -f

第三步起前端(Docker 容器):

cd /root/system-backu
docker compose up -d frontend

# 确认容器在跑
docker ps --filter name=frontend
docker logs -f system-backu-frontend-1

访问地址:前端管理界面 http://<服务器IP>:5173,后端 API http://<服务器IP>:8765,API 文档 http://<服务器IP>:8765/docs。首次登录用 admin / INITIAL_ADMIN_PASSWORD,登录后第一件事就是改密码。

七、使用流程:存储目标 → 任务 → 调度

第一次使用按这个顺序走,缺一步后面都建不了任务:

  • 第一步:建存储目标(Storages → 新建)。本地存储填宿主机上实际存在的目录,且后端进程要有读写权限;S3 存储填 Endpoint、Bucket、AccessKey、SecretKey。建完点一下测试连通性,通了再往下走。
  • 第二步:建备份任务(Jobs → 新建)。选数据源类型(MySQL / 目录 / InfluxDB / ETCD),填源信息(MySQL 填主机、端口、库名、账号密码;目录填要打包的路径),选存储目标,保存。
  • 第三步:手动触发或定时调度。Job 列表点 Run Now 立即跑一次,验证备份能成功;确认没问题后填 cron_expression(标准 5 段 cron 表达式,比如每天凌晨 2 点就是 0 2 * * *)启用定时调度。
  • 第四步:看运行历史。每次备份的执行详情、SHA256 校验值、文件大小、耗时都在 Runs 里,失败了点进去看日志。

本地存储的 path 必须是宿主机上实际存在的目录。README 里给的例子是把宿主机目录映射进部署路径(比如 /root/system-backu/data/backend/backups/),如果你把备份目录放在别处,要确认后端进程对它有读写权限,否则任务会失败。

八、备份还原

备份的价值在还原那一刻才体现出来。还原入口在前端 Restore 页面,也可以调 POST /api/restore。支持两种还原:MySQL 库还原(用备份的 mysqldump 文件恢复到目标库)、目录还原(把 tar.gz 解压到指定位置)。还原前注意两点:一是确认目标库/目标目录,MySQL 还原会覆盖目标库的数据;二是还原操作本身也会记一条运行记录,方便事后追溯。

建议每季度做一次还原演练:拿一个测试库,从备份里恢复,验证数据完整、应用能连上。只备不练的备份,等于没备。

九、保留策略

保留策略是“保留最近 N 个 + 保留 N 天”双重控制。两个条件同时起作用:比如保留最近 30 个、保留 30 天,超过 30 天的删掉,超过 30 个的也删掉(只留最新的 30 个)。策略在任务里配置,由后端的保留清理逻辑执行。

配保留策略要算一笔账:每天备份一次、每次 2GB、保留 30 天,本地磁盘至少要留 60GB 以上的余量;推 S3 的话按存储量和请求数计费,保留期越长费用越高。关键库的保留期可以放长,普通目录备份保留 7 天就够了。

十、API 端点与调用示例

端点说明
POST /api/auth/login登录获取 JWT
GET /api/storages存储目标列表
POST /api/storages创建存储目标
GET /api/storages/{id}/files列出存储目标下的备份文件
POST /api/storages/{id}/test测试存储目标连通性
GET /api/jobs备份任务列表
POST /api/jobs创建备份任务
POST /api/jobs/{id}/run手动触发备份
GET /api/runs运行历史
POST /api/restore从备份恢复
# 登录拿 Token
curl -s -X POST http://10.168.1.209:8765/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username": "admin", "password": "你的管理员密码"}'
# 返回里有 access_token,存下来
export TOKEN="eyJhbGciOi..."

# 列出备份任务
curl -s http://10.168.1.209:8765/api/jobs \
  -H "Authorization: Bearer $TOKEN" | python3 -m json.tool

# 手动触发一次备份(任务 id 为 1)
curl -s -X POST http://10.168.1.209:8765/api/jobs/1/run \
  -H "Authorization: Bearer $TOKEN"

# 查运行历史
curl -s "http://10.168.1.209:8765/api/runs" \
  -H "Authorization: Bearer $TOKEN" | python3 -m json.tool

# 列出某个存储目标下的备份文件
curl -s http://10.168.1.209:8765/api/storages/1/files \
  -H "Authorization: Bearer $TOKEN" | python3 -m json.tool

完整 API 文档见 http://<服务器>:8765/docs(Swagger,可在线测试)。注意示例里的 10.168.1.209 是 README 里的示例地址,换成你自己的服务器 IP。

十一、安全注意事项

  • FERNET_KEY 丢了就全完:数据源密码和 Token 是用 Fernet 加密后存数据库的,密钥丢了就解不出来,所有数据源配置都要重填。把 FERNET_KEY 和 SECRET_KEY 一起存到安全的地方(密码管理器或 secret manager),别只放在 .env 里。
  • 前端永远看不到明文:敏感字段编辑时回显 ***,这是设计如此,不是 bug。改密码要重新输入完整的新密码。
  • 单实例部署:内置 APScheduler,不要启动多个 backend 进程,否则出现重复调度(同一个任务被跑两遍)。gunicorn 多 worker、systemd 重复启动都要避免。
  • RBAC 只有两级:admin 和 operator,operator 能操作备份任务但不能改系统配置。给值班同事开 operator 就够了,admin 只给负责人。
  • 备份目录权限:本地存储的目录要限制访问权限,备份文件里有数据库明文 dump,权限放开等于把数据库送人。

十二、常见问题

现象原因与处理
MySQL 备份失败,报找不到 mysqldump宿主机没装 mysql-client;装上并确认 which mysqldump 能找到
任务显示成功但存储目标里没文件本地存储 path 不存在或后端没写权限;检查目录和权限,或用 POST /api/storages/{id}/test 测连通性
定时任务不执行后端是不是起了多个进程(重复调度会互相干扰);确认只有一个 backup-backend 在跑,cron 表达式是标准 5 段
前端打不开,后端正常前端容器没起来或端口不对;docker ps 查容器,docker logs 看 Nginx 报错
登录后提示密码错误INITIAL_ADMIN_PASSWORD 只在首次初始化时生效,改过密码后以新密码为准
磁盘满了保留策略没配或配得太松;收紧保留个数和天数,手动清理过期备份

十三、运维建议

  • 备份的备份:SQLite 数据库文件(/root/system-backu/data/backend/backup.db)和备份文件目录本身也要备份——备份系统自己的数据丢了,任务配置和运行历史全没了。
  • 盯着运行历史:每天看一眼 Runs,有失败的立即处理;失败的任务不会自动补跑(除非下次定时触发)。
  • 定期做还原演练:每季度至少一次,验证备份文件真的能恢复。
  • 监控磁盘:备份目录单独分区或单独磁盘,设磁盘使用率告警,避免备份把根分区写满。
  • 升级流程:先停 backend 服务,git pull 拉新代码,跑 Alembic 迁移(alembic upgrade head),重装依赖,前端 docker compose up -d --build frontend,再启动验证。

总结一下:system-backu 把 MySQL、目录、InfluxDB、ETCD 四种备份收进一个 Web 界面,本地目录和 S3 双存储目标、Cron 定时调度、保留策略、还原和运行历史一应俱全。部署记住:后端 systemd(8765)、前端 Docker(5173),SECRET_KEY、FERNET_KEY、INITIAL_ADMIN_PASSWORD 三个环境变量先配好;用起来记住:先建存储目标、再建任务、Run Now 验证、最后上定时调度;运维记住:只起一个 backend 进程、定期做还原演练。

发表回复

后才能评论