跳到主要内容

Docker 应用备份与迁移:配置、数据目录和恢复顺序

区分 Compose 配置与应用数据,备份 SQLite 应用、数据库和上传文件,并在新 VPS 恢复。

迁移容器之前,先找数据在哪里

Compose 文件说明容器怎样启动,数据通常在绑定目录或命名卷。先打开 compose.yaml 查看 volumes,再用 docker inspect 对照实际挂载;镜像可以重新下载,数据库和上传文件需要自己保存。

bash;使用前请核对本文前提。
sudo docker compose ps
sudo docker inspect 容器名 --format "{{json .Mounts}}"

命名卷也要保存

Compose 项目不一定把数据放在当前目录。先用 docker compose config 查看 volumes,再用 docker volume inspect 查看实际卷;项目名前缀也会影响卷名。

数据库卷优先使用数据库工具导出。一般文件卷可在停止写入后挂到临时工具容器中打包,保存时保留目录、权限和所需配置;不要只复制 compose.yml。

小型 SQLite 应用可以停机后打包

下面适用于 Linux 上用 Bash、Docker Compose v2 和 GNU tar 维护的单实例应用:项目在 /srv/memos,SQLite 和附件都在真实目录 /srv/memos/data。先对照挂载改好路径;数据若在命名卷、外部数据库或符号链接指向的别处,不能直接套用。除 .env 外另有环境文件、密钥或挂载,也要一并保存。

命令会先检查 Compose,再建立一份不重名、仅 root 可访问的备份目录。停机后打包 compose.yaml、data 和存在的 .env;打包、读取归档或生成校验文件失败都会返回非零状态,并尝试重新启动原项目。失败目录保留,便于检查。

bash;使用前请核对本文前提。
sudo bash <<'BACKUP'
set -u
umask 077
cd /srv/memos || exit 1
if [ ! -f compose.yaml ] || [ ! -d data ] || [ -L compose.yaml ] || [ -L data ] || [ -L .env ]; then
  printf '%s\n' '请先核对 compose.yaml、data 和实际挂载,示例不处理符号链接。' >&2
  exit 1
fi
docker compose config --quiet || exit 1
backup_dir=$(mktemp -d /srv/memos-backup-$(date -u +%Y%m%d-%H%M%S)-XXXXXX) || exit 1
files=(compose.yaml data)
if [ -f .env ]; then files+=(.env); fi
if ! docker compose stop; then
  printf '%s\n' '停止服务失败,未开始打包;请检查服务状态。' >&2
  exit 1
fi
archive_ok=0
if tar -czf "$backup_dir/backup.tar.gz.partial" "${files[@]}" \
  && test -s "$backup_dir/backup.tar.gz.partial" \
  && tar -tzf "$backup_dir/backup.tar.gz.partial" >/dev/null \
  && mv "$backup_dir/backup.tar.gz.partial" "$backup_dir/backup.tar.gz" \
  && (cd "$backup_dir" && sha256sum backup.tar.gz > SHA256SUMS); then
  archive_ok=1
fi
start_ok=0
if docker compose start; then start_ok=1; fi
if [ "$archive_ok" -ne 1 ] || [ "$start_ok" -ne 1 ]; then
  printf '备份或重新启动失败,请检查服务与目录:%s\n' "$backup_dir" >&2
  exit 1
fi
printf '归档与校验文件已生成,已执行启动命令:%s\n' "$backup_dir"
BACKUP

命令结束后检查 docker compose ps 和应用登录、记录、附件,再把备份及 SHA256SUMS 复制到另一台机器或外部存储。启动命令成功不等于应用已恢复健康;若终端断开、进程被杀或主机掉电,仍要人工确认服务是否启动。

校验文件和归档可读只检查了这份文件,不能代替在空目录恢复并验证应用。不要直接打包持续写入的数据库文件;MySQL、PostgreSQL 使用各自的逻辑导出或一致性备份方式。

有数据库的应用分别保存什么

一组备份应同时包含数据库导出、上传目录、Compose、.env、密钥,以及软件和数据库版本。n8n 的凭据依赖原加密密钥,只有数据库可能仍无法使用。

数据库和上传文件,要来自同一个恢复点

应用正在上传文件时,数据库和目录分别复制可能产生不同时间点的副本。迁移前安排停写窗口:停止接收新任务、上传和 Webhook,等待正在执行的任务结束,再保存数据库与文件。保留数据库服务运行以执行逻辑导出,不能先停数据库再运行 pg_dump。

PostgreSQL 的 pg_dump 可以取得数据库一致快照,但它不能同时冻结应用文件目录。下面假定 Compose 服务名为 db,替换数据库账号与库名,并在停写后执行;dump 文件位于宿主机当前目录。备份目录应仅允许维护账号读取。

bash;使用前请核对本文前提。
umask 077
docker compose exec -T db pg_dump -U DB_USER -d DB_NAME -Fc > database.dump
test -s database.dump

命令成功并且文件非空仍需恢复验证。数据库版本、应用版本、Compose、.env、密钥和上传目录写入同一份备份记录。MySQL 或外部数据库使用对应官方一致性备份方法,不把 pg_dump 命令照搬过去。

先在新 VPS 恢复,再切换域名

新 VPS 安装 Docker 后,复制配置与数据并恢复正确权限。核对挂载路径、宿主机目录与命名卷,避免应用启动后在错误目录生成一份空数据库。先完成以下版本与恢复检查,再切换域名。

保留原数据再升级版本

先用原应用版本恢复,再按软件支持的路径升级。PostgreSQL 等数据库大版本不能直接换镜像读取旧数据目录,应使用逻辑导出恢复或对应升级工具。

异机恢复后,用真实业务动作检查

在隔离机器恢复匹配的数据库和文件后,先关闭预演副本的定时任务、通知和外部写入,确认不会重复发邮件或触发业务,再用原应用版本启动。用 --resolve 或受控临时域名检查 HTTPS,公网 DNS 先不切换。

检查登录、旧记录、附件下载、临时记录写入及后台任务。抽查文件校验和、数据库恢复退出状态和日志,再对照应用内数量与关键记录。首页可打开、容器 Up 或数据库能连接,都不能独立证明恢复完整。

恢复后怎样判断成功

正式切换后,再逐项启用所需通知、Webhook和定时任务,并检查外部服务白名单及回调地址。确认旧实例不再执行相同任务,避免新旧服务重复处理。

切换期间只有一份业务数据继续写入

预演通过后,旧实例停写,完成最后一份数据库和文件备份,再恢复到目标实例并切换域名或代理。DNS 缓存可能让请求仍到旧机器,旧入口应继续停写或转发到新入口,避免两个数据库分别产生新记录。

恢复完成后保留回退资料

切换前保留旧机器、旧解析、代理配置及迁移前备份。新实例尚未接收业务写入时,可以恢复旧入口;新实例已经有新记录时,应先停写并保存增量,再安排回迁,不能只把 DNS 改回去。

旧服务结束前,确认定时任务、回调和依赖都已迁走。清理容器不需要删除数据卷;docker compose down -v 会删除项目卷,不用于普通停止或镜像更新。

给文件备份增加异地仓库

Restic 可将配置、上传文件和数据库导出文件保存到 SFTP 仓库。仓库密码与 SSH 登录密钥分别保管;先完成一次备份,再从指定快照恢复到独立目录。

数据库使用自身的导出工具生成备份后再交给文件备份程序,避免直接归档持续写入的数据目录。保留策略先预览待删除的快照,再执行清理;备份任务同时记录退出状态与运行日志。

为文件备份选择带界面的工具

需要按计划上传文件并保留历史版本,可以用 Duplicati;需要目录快照、去重仓库与策略管理,可以用 Kopia。两者都先准备一致的数据库导出,再备份文件产物。

Kopia:重连备份仓库与恢复文件 →

迁移计划任务时避免重复执行

切换服务器前记录任务周期、目标位置与加密口令。最终同步完成后停掉旧任务,再由新实例接管;检查下一次自动任务和远端结果,恢复一份文件。