Docker 基础体系 · 第 18/70 篇。示例以现代 Docker Engine、BuildKit 与 Compose 规范为基础,并明确 Linux 容器边界。
Docker 数据备份与主机迁移:卷、数据库、一致性和恢复演练
Docker 容器本身通常是可替换的,真正需要保护的是容器外部的状态:数据库文件、上传文件、队列数据、证书、配置和恢复所需的镜像与版本信息。主机迁移也不是“把容器复制到另一台机器”,而是把运行所需的不可替代状态以可验证的方式导出,在目标主机重新创建运行环境,再通过恢复演练证明结果可用。
这类工作需要同时回答四个问题:
- 数据实际存放在哪里?
- 备份时是否处于一致状态?
- 新主机是否能重建相同的运行环境?
- 恢复后如何证明业务数据正确,而不是仅仅证明容器启动成功?
一、先区分容器、镜像、卷和主机文件
1. 容器文件系统不是可靠的数据存储
镜像由只读层组成,容器启动时再叠加一个可写层。容器内未挂载到外部存储的文件写入这个可写层:
镜像只读层
+
容器可写层
+
Volume / Bind Mount / tmpfs
删除容器时,容器可写层通常随容器一起删除。重新创建同一个镜像的容器,也不会恢复原容器可写层中的文件。
因此,下面这些位置的持久性不同:
| 存储位置 | 容器删除后 | 主机重启后 | 是否适合备份业务数据 |
|---|---|---|---|
| 镜像只读层 | 保留在镜像中 | 保留 | 只适合静态程序和依赖 |
| 容器可写层 | 丢失 | 通常保留 | 不适合 |
| named volume | 保留 | 保留 | 适合,但需单独备份 |
| bind mount | 保留在主机目录 | 保留 | 适合 |
| tmpfs | 丢失 | 丢失 | 不适合持久数据 |
这里的“保留”并不等于“已经备份”。named volume 和 bind mount 只是在本机仍然存在;磁盘损坏、误删、勒索软件或主机丢失仍会导致数据不可恢复。
二、三种常见挂载方式的备份边界
1. Volume
Docker 管理的 named volume 由 Docker volume driver 管理。Linux 默认 local driver 的数据通常位于:
/var/lib/docker/volumes/<volume-name>/_data
但这个路径是常见实现,不应当被当作跨 driver、跨发行版的稳定接口。使用 NFS、云盘或第三方 volume plugin 时,数据甚至可能根本不在本机这个目录下。
创建并查看 volume:
docker volume create wrblog_data
docker volume inspect wrblog_data
典型输出结构类似:
[
{
"Name": "wrblog_data",
"Driver": "local",
"Mountpoint": "/var/lib/docker/volumes/wrblog_data/_data",
"Scope": "local"
}
]
备份时应通过 Docker 挂载 volume,而不是直接假设其宿主机路径:
mkdir -p ./backup
docker run --rm \
--mount type=volume,src=wrblog_data,dst=/data,readonly \
--mount type=bind,src="$PWD/backup",dst=/backup \
alpine:3.20 \
sh -c 'tar czpf /backup/wrblog_data.tgz -C /data .'
命令的因果关系是:
src=wrblog_data让 Docker 找到 volume。/data是容器内访问卷内容的路径。readonly防止备份工具意外修改源数据。/backup映射到主机目录,使归档文件离开 Docker volume。tar -C /data .归档的是卷内文件内容,而不是/data目录本身。
恢复到一个新 volume:
docker volume create wrblog_data_restore
docker run --rm \
--mount type=volume,src=wrblog_data_restore,dst=/data \
--mount type=bind,src="$PWD/backup",dst=/backup \
alpine:3.20 \
sh -c 'tar xpf /backup/wrblog_data.tgz -C /data'
恢复后检查:
docker run --rm \
--mount type=volume,src=wrblog_data_restore,dst=/data,readonly \
alpine:3.20 \
sh -c 'find /data -maxdepth 2 -type f -printf "%M %u:%g %s %p\n" | head'
这个方法适用于普通文件、上传目录和应用生成文件,但不自动保证数据库文件的一致性。数据库需要单独讨论。
2. Bind mount
bind mount 直接把主机路径映射到容器:
services:
app:
image: example/app:1.0
volumes:
- type: bind
source: /srv/wrblog/uploads
target: /var/lib/app/uploads
它的优点是路径透明,主机上的备份工具、文件系统快照和权限管理都可以直接使用。缺点是环境耦合更强:
- 目标主机必须创建相同或等价的目录;
- UID、GID、ACL、SELinux 标签可能不同;
- 相对路径受 Compose 项目工作目录影响;
- 备份程序若运行在别的主机上,必须明确复制这个主机目录。
普通文件复制至少应考虑权限、符号链接、时间戳和 ACL。例如 Linux 上可以使用:
rsync -aHAX --numeric-ids \
/srv/wrblog/uploads/ \
./backup/uploads/
其中:
-a保留常见文件属性;-H保留硬链接;-A保留 POSIX ACL;-X保留扩展属性;--numeric-ids不把 UID/GID 映射成备份机上的用户名和组名。
目标主机恢复时:
rsync -aHAX --numeric-ids \
./backup/uploads/ \
/srv/wrblog/uploads/
如果使用 SELinux,还需要根据目标主机策略重新确认文件标签;仅保留 Unix 权限并不保证容器能访问文件。
3. tmpfs
tmpfs 把文件放在内存或内核管理的临时存储中:
services:
app:
image: example/app:1.0
tmpfs:
- /tmp
容器停止、删除或主机重启后,tmpfs 中的数据都会消失。它适合:
- 临时编译目录;
- 缓存;
- 短期会话文件;
- 不希望写入磁盘的中间数据。
它不适合数据库、上传文件、队列持久化和恢复所需的状态。对 tmpfs 做 tar 备份只能备份“当前仍存在的临时内容”,不能改变其非持久属性。
三、卷名、Compose 项目和迁移时的命名问题
Compose 中声明:
volumes:
db_data:
services:
db:
image: postgres:16
volumes:
- db_data:/var/lib/postgresql/data
实际卷名通常会受到 Compose project name 影响,例如项目目录名为 wrblog 时可能生成:
wrblog_db_data
因此在迁移前不要凭记忆写卷名,应查看实际绑定关系:
docker compose ps
docker compose config
docker inspect "$(docker compose ps -q db)"
docker volume ls
如果希望卷名不受项目目录影响,可以显式指定:
volumes:
db_data:
name: wrblog_postgres_data
这使实际卷名固定为 wrblog_postgres_data。但固定名称不是跨主机同步机制;目标主机仍然需要手工创建或恢复这个卷。
还要区分两种操作:
docker compose down
默认会删除容器和网络,但通常保留命名卷。
docker compose down -v
会删除 Compose 声明的命名卷,数据可能直接丢失。这个命令只能在已经确认有可用备份、且明确希望销毁卷时使用。
四、备份的核心:崩溃一致性和应用一致性
1. 什么是一致性
备份一致性可以抽象为:恢复后的数据状态应该满足应用或数据库定义的不变量。
设数据库状态为 ,事务提交会把状态从 变为 。一个一致备份应当对应某个合法状态:
或者包含能够把数据恢复到合法状态的日志:
如果备份同时复制了一个事务提交前的表文件和提交后的索引文件,就可能得到:
这就是逻辑上不存在的混合状态。文件数量完整、tar 命令成功,都不能证明备份一致。
2. 崩溃一致性
崩溃一致性指的是:系统仿佛在某个瞬间突然断电,恢复后数据库依靠自身日志完成回滚或重做。
它通常依赖:
- 数据库的 WAL、redo log 或 journal;
- 文件系统或存储快照的原子语义;
- 数据库对
fsync和持久化顺序的正确使用。
Docker 本身不提供数据库一致性。docker pause 也不是数据库快照协议;它只是冻结容器进程,不能替代数据库的 flush、checkpoint 或快照协调。
3. 应用一致性
应用一致性要求备份反映应用认可的业务状态。例如订单系统中:
订单已标记为 paid
但支付流水表没有对应记录
即使两个表在文件层面都没有损坏,业务上仍然是不一致的。
获得应用一致性的常见方式是:
- 停止所有写入;
- 等待正在执行的请求完成;
- 执行数据库原生备份;
- 备份上传文件等外部状态;
- 记录版本、时间点和校验信息;
- 恢复写入。
对于可以短暂停机的系统,这是最容易验证的方案。无法停机时,则需要数据库原生的一致性快照、事务快照或存储层快照协议。
五、数据库不能简单当作普通目录复制
1. 为什么在线复制数据库目录危险
以 PostgreSQL 为例,数据目录包括表文件、索引、控制文件、WAL 和其他元数据。数据库运行时,一个事务可能经历:
- 修改数据页;
- 写入 WAL;
- 更新索引;
- 提交事务;
- 延迟刷盘。
如果此时直接执行:
tar czf postgres-data.tgz /var/lib/postgresql/data
可能复制到不同时间点的数据页和索引页。即使 PostgreSQL 启动时能完成恢复,也不能把未经支持的文件复制当作可靠的物理备份方法。
正确选择通常是:
- 使用
pg_dump、pg_dumpall等逻辑备份; - 使用 PostgreSQL 支持的物理备份和 WAL 归档方案;
- 使用已与数据库协同的存储快照;
- 或先停止数据库,再复制完整数据目录。
2. PostgreSQL 逻辑备份示例
假设 Compose 文件如下:
services:
db:
image: postgres:16
environment:
POSTGRES_USER: wrblog
POSTGRES_DB: wrblog
POSTGRES_PASSWORD: change-this-in-secret-management
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:
name: wrblog_postgres_data
先确认数据库可连接:
docker compose exec -T db \
pg_isready -U wrblog -d wrblog
预期结果类似:
/var/run/postgresql:5432 - accepting connections
导出数据库:
mkdir -p backup/2025-01-01
docker compose exec -T db \
pg_dump -U wrblog -d wrblog --format=custom \
> backup/2025-01-01/wrblog.dump
--format=custom 生成 PostgreSQL 自定义格式,适合使用 pg_restore 选择性恢复和并行恢复。这个文件包含数据库对象和数据,但不自动包含整个 PostgreSQL 集群的全局对象,例如角色和表空间定义。
导出全局对象:
docker compose exec -T db \
pg_dumpall -U wrblog --globals-only \
> backup/2025-01-01/globals.sql
检查归档是否可读取:
pg_restore --list backup/2025-01-01/wrblog.dump | head
如果主机没有 PostgreSQL 客户端,可以使用一次性容器:
docker run --rm \
--network container:"$(docker compose ps -q db)" \
-v "$PWD/backup/2025-01-01:/backup" \
-e PGPASSWORD='change-this-in-secret-management' \
postgres:16 \
pg_dump -h 127.0.0.1 -U wrblog -d wrblog \
--format=custom -f /backup/wrblog.dump
生产环境不应把真实密码直接写入 shell 历史;示例中的密码只表示连接所需的前置条件,应改用受控的 secret 文件、凭据注入或短生命周期环境变量。
3. 逻辑备份的一致性边界
pg_dump 在数据库内部建立一致性快照,因此导出期间其他事务通常可以继续运行。它得到的是某个数据库级一致视图,而不是简单逐表复制。
但是它仍有边界:
pg_dump不备份角色等集群全局对象;- 大对象、扩展、外部表和外部依赖需要单独确认;
- 备份完成后新增的数据不在该备份中;
- 数据库外的上传目录、对象存储和消息队列不在其中;
- 跨数据库的业务事务不能仅靠单库
pg_dump获得全局一致性。
如果业务同时写 PostgreSQL 和上传目录,必须设计业务级关联。例如先写入临时文件,数据库事务提交后再把文件标记为可见;恢复时对“无数据库记录的孤儿文件”和“数据库有记录但文件缺失”分别检查。
4. MySQL 类数据库的差异
MySQL 的 mysqldump --single-transaction 适合事务型 InnoDB 表,因为它建立一致性读视图;但它不能自动解决所有表引擎和 DDL 并发问题:
- MyISAM 等非事务表不能通过事务快照获得同样保证;
- 导出期间执行
ALTER TABLE可能影响结果或阻塞; - 触发器、事件、存储过程和用户权限需要确认导出选项;
- 对大规模数据库,物理备份工具可能比逻辑导出更适合。
因此,“使用数据库官方备份工具”不是一个固定命令,而是要根据数据库引擎、版本、复制拓扑和恢复目标选择对应机制。
六、可接受的文件级卷备份流程
对于非数据库文件,或者已经停止数据库后的完整卷复制,可以使用以下顺序。
1. 先停止写入者
docker compose stop app
如果要复制数据库数据目录,再停止数据库:
docker compose stop db
查看状态:
docker compose ps
停止命令成功只表示 Docker 已向容器发送停止请求并完成等待,不等于应用内部一定完成了业务 flush。应检查日志:
docker compose logs --tail=100 app db
若应用捕获 SIGTERM 并优雅退出,日志中通常会出现关闭连接、完成 flush 或数据库正常停止等信息。若容器被强制终止,文件级备份的可靠性需要重新评估。
2. 导出卷并计算校验和
docker run --rm \
--mount type=volume,src=wrblog_postgres_data,dst=/data,readonly \
--mount type=bind,src="$PWD/backup/2025-01-01",dst=/backup \
alpine:3.20 \
sh -c 'tar czpf /backup/postgres-volume.tgz -C /data .'
sha256sum backup/2025-01-01/postgres-volume.tgz \
> backup/2025-01-01/SHA256SUMS
校验和用于检测传输损坏和文件替换,不用于证明内容具有数据库一致性。一个被错误复制但没有损坏的 tar 文件,仍然会产生正确的 SHA-256。
3. 重新启动服务
docker compose start db
docker compose start app
如果数据库使用的是逻辑备份,通常不需要再同时依赖一个在线复制的数据目录。若采用停机后的物理目录恢复,则必须保证目标数据库镜像版本、架构、配置、权限和数据目录格式兼容。
七、主机迁移需要迁移的不只是卷
迁移对象至少包括以下几类状态:
应用镜像
Compose 文件与环境变量
密钥和证书
named volume / bind mount 数据
数据库逻辑或物理备份
反向代理和网络配置
定时任务、监控和日志策略
恢复所需的 Docker 与数据库版本
镜像不包含卷,卷也不包含镜像。执行:
docker image save myapp:1.4 -o myapp-1.4.tar
只会导出镜像层和镜像元数据,不会导出容器挂载的 volume 或 bind mount 文件。
更常见的方式是把镜像推送到镜像仓库:
docker buildx build \
--platform linux/amd64 \
-t registry.example.com/wrblog/app:1.4 \
--push .
BuildKit 可以提供可重复构建、缓存和多平台镜像构建能力,但构建缓存不是业务数据备份。缓存丢失只会让构建变慢,不能替代数据库和上传文件备份。
如果没有镜像仓库,也可以离线传输:
docker save registry.example.com/wrblog/app:1.4 \
| gzip > backup/2025-01-01/wrblog-app-1.4.tar.gz
目标主机导入:
gunzip -c backup/2025-01-01/wrblog-app-1.4.tar.gz \
| docker load
目标主机应先确认:
docker version
docker compose version
docker info
重点检查:
- CPU 架构是否匹配;
- Docker Engine 是否支持所使用的 Compose 字段和存储 driver;
- volume driver 是否已安装;
- bind mount 目录是否存在;
- 防火墙、端口和 DNS 是否一致;
- 数据库镜像主版本是否与备份方案兼容。
八、一个完整的迁移时序
典型的单主机迁移可以表示为:
sequenceDiagram
participant Old as 旧主机
participant Store as 备份存储
participant New as 新主机
participant Check as 验证环境
Old->>Old: 固定代码、镜像和 Compose 配置版本
Old->>Old: 停止写入或建立数据库一致性窗口
Old->>Store: 导出数据库逻辑备份
Old->>Store: 导出上传目录和其他卷
Old->>Store: 上传校验和、配置清单和版本信息
New->>Store: 下载备份并校验 SHA-256
New->>New: 导入镜像、创建卷和目录
New->>New: 恢复文件、初始化数据库
New->>Check: 启动隔离验证环境
Check->>Check: 执行健康检查和业务数据校验
Check-->>New: 验证通过
Old->>Old: 停止旧主机对外写入
New->>New: 切换流量
New->>Check: 记录恢复耗时和验证结果
关键是先在新主机恢复并验证,再切换流量。直接“备份后立刻改 DNS”会把恢复错误暴露给真实用户,且回滚时可能出现新旧主机双写。
一个保守的切换顺序是:
- 降低 DNS TTL 或准备负载均衡切换;
- 关闭旧主机写入;
- 完成最后一次数据库备份和文件同步;
- 在新主机恢复;
- 执行健康检查和业务校验;
- 切换流量;
- 保留旧主机为只读或停机状态,直到观察窗口结束。
九、恢复数据库的端到端示例
以下示例采用新卷恢复 PostgreSQL,而不是覆盖原卷。这样可以降低误操作风险。
1. 创建并恢复到新卷
docker volume create wrblog_postgres_restore
docker run --rm \
--mount type=volume,src=wrblog_postgres_restore,dst=/data \
--mount type=bind,src="$PWD/backup/2025-01-01",dst=/backup \
postgres:16 \
bash -c 'tar xpf /backup/postgres-volume.tgz -C /data'
如果归档来自停机后的 PostgreSQL 数据目录,恢复文件后要确认目录属主。官方 PostgreSQL 镜像通常要求数据目录由容器内的 postgres 用户拥有,但具体 UID 应以镜像为准。可以通过临时容器查看:
docker run --rm \
--mount type=volume,src=wrblog_postgres_restore,dst=/var/lib/postgresql/data \
postgres:16 \
bash -c 'id postgres; stat -c "%U:%G %a %n" /var/lib/postgresql/data'
不要仅凭宿主机上的用户名判断权限,因为容器内的 UID/GID 才是内核实际检查的数值。
2. 使用逻辑备份恢复
更可控的方式是创建一个全新的 PostgreSQL 数据目录,让数据库先正常初始化,再导入逻辑备份。
启动临时数据库:
docker run -d --name wrblog-pg-restore \
-e POSTGRES_USER=wrblog \
-e POSTGRES_PASSWORD='restore-only-password' \
-e POSTGRES_DB=wrblog \
-p 55432:5432 \
postgres:16
等待数据库就绪:
until docker exec wrblog-pg-restore \
pg_isready -U wrblog -d wrblog
do
sleep 1
done
恢复全局对象和数据库:
cat backup/2025-01-01/globals.sql \
| docker exec -i \
-e PGPASSWORD='restore-only-password' \
wrblog-pg-restore \
psql -U wrblog -d postgres
然后恢复数据库对象:
docker exec -i \
-e PGPASSWORD='restore-only-password' \
wrblog-pg-restore \
pg_restore -U wrblog -d wrblog \
--no-owner --exit-on-error \
< backup/2025-01-01/wrblog.dump
--exit-on-error 使出现错误时立即失败,而不是导入一部分后仍返回成功。--no-owner 适用于恢复环境中的角色与源环境不同的场景;如果权限模型要求保留原属主,则应先创建对应角色,并谨慎决定是否去掉该选项。
恢复后检查:
docker exec \
-e PGPASSWORD='restore-only-password' \
wrblog-pg-restore \
psql -U wrblog -d wrblog \
-c 'SELECT count(*) FROM important_table;'
验证不能只执行 SELECT 1。至少应检查:
- 关键表行数或业务计数;
- 最近一条订单、文章或任务;
- 外键和唯一约束;
- 应用登录;
- 写入一条测试数据并读取;
- 上传文件与数据库记录的对应关系;
- 定时任务和后台消费者是否能正常运行。
十、恢复演练不是“把备份解压一次”
恢复演练的目标是测量并验证两个指标:
- RPO(Recovery Point Objective):最多能接受丢失多长时间的数据;
- RTO(Recovery Time Objective):故障发生后,最多允许多长时间恢复服务。
例如:
业务要求:RPO ≤ 15 分钟,RTO ≤ 60 分钟
实际演练:最后备份距故障 8 分钟,服务恢复耗时 42 分钟
结果:满足目标
如果只有备份任务成功日志,没有真正恢复并启动业务,RPO 和 RTO 都只是猜测。
一次可重复的恢复演练
在与生产隔离的 Linux 主机或虚拟机上执行:
mkdir restore-drill
cd restore-drill
sha256sum -c ../backup/2025-01-01/SHA256SUMS
预期应看到:
postgres-volume.tgz: OK
wrblog.dump: OK
然后按生产 Compose 文件部署,但使用独立的:
- 项目名;
- 端口;
- 数据库卷名;
- 密钥;
- 外部依赖地址。
例如:
docker compose -p wrblog-drill up -d
恢复完成后记录:
date -Is
docker compose -p wrblog-drill ps
docker compose -p wrblog-drill logs --tail=200
再执行业务验证。演练应记录以下中间结果:
- 备份文件大小和校验和;
- 下载、解压和导入耗时;
- 数据库恢复开始与结束时间;
- 每个服务的启动时间;
- 关键数据校验结果;
- 失败时的日志和恢复动作;
- 最终 RPO 与 RTO。
如果验证中途发现备份缺少角色、证书、上传目录或配置,不应把问题归因于“演练环境不同”。这通常说明备份清单不完整。
十一、权限、属主和安全属性
容器进程使用的是 Linux 内核看到的 UID/GID,而不是容器中显示的用户名。假设宿主机目录属于 UID 1001:
sudo chown -R 1001:1001 /srv/wrblog/uploads
容器内应用也必须以 UID 1001 运行,或者通过组权限获得访问权。恢复后出现:
Permission denied
常见诊断顺序是:
docker inspect <container>
docker exec <container> id
docker exec <container> ls -ln /path
namei -l /srv/wrblog/uploads
其中 ls -ln 显示数字 UID/GID,避免用户名映射造成误判;namei -l 可以检查路径中每一级目录是否允许遍历。
备份本身也包含敏感信息:
- 数据库中的用户资料;
- API token;
- session;
- 私钥和证书;
- 业务源代码;
- 可能包含密码的配置文件。
因此备份应至少做到:
chmod 600 backup/2025-01-01/*
实际生产系统还应使用加密归档、受限对象存储、密钥轮换、保留周期和删除保护。加密密钥不能与备份放在同一个故障域,否则主机丢失时可能同时丢失数据和解密能力。
十二、常见失败方式及其原因
1. 只备份镜像
镜像只能恢复程序和基础文件,不能恢复:
- named volume;
- bind mount;
- 数据库提交状态;
- 运行时生成的上传文件;
- 外部密钥和证书。
表现通常是容器能启动,但数据库为空或用户上传文件全部消失。
2. 直接复制 /var/lib/docker
直接复制整个 Docker 数据根目录并不是通用迁移方法。它依赖:
- Engine 版本和存储驱动;
- overlay2 元数据;
- volume driver;
- 容器 ID 和网络状态;
- 主机路径、权限和内核行为。
正确方法是重新部署镜像和 Compose 配置,再通过受控方法恢复卷数据。
3. 在线 tar 数据库目录
tar 本身成功只表示文件读取成功,不代表数据库在逻辑上处于一致状态。失败表现可能包括:
- 数据库启动恢复失败;
- 索引损坏;
- 启动后查询报错;
- 更隐蔽的数据缺失或业务关系不一致。
数据库应使用原生备份、支持的物理备份,或先停止数据库再复制。
4. 恢复后直接删掉旧卷
如果把恢复数据写入旧卷,恢复失败后很难区分:
- 原始数据;
- 已恢复数据;
- 部分导入数据;
- 人工修复产生的数据。
使用新卷或新 Compose project 先验证,确认通过后再切换,是更容易回滚的状态转换。
5. 只检查容器健康状态
健康检查可能只执行:
curl -f http://localhost:8080/health
这只能说明进程和基础接口可用,不能说明:
- 数据库记录完整;
- 外部文件存在;
- 消息队列没有重复消费;
- 权限模型正确;
- 新写入能持久化。
恢复验证必须包含业务数据和持久化路径。
十三、备份方案的选择
可以用下面的判断逻辑区分方案:
数据是否持久化?
├─ 否:tmpfs 或容器可写层,不纳入持久备份
└─ 是
├─ 数据库?
│ ├─ 可停机:停止写入后做原生备份或文件级备份
│ └─ 不可停机:逻辑备份、物理备份或协调快照
└─ 普通文件?
├─ Volume:通过临时容器挂载后归档
└─ Bind mount:使用保留属性的主机文件工具
小型服务常见的可接受方案是:
- 镜像进入版本化仓库;
- Compose 文件进入 Git;
- PostgreSQL 使用定期
pg_dump; - 上传目录使用 tar、rsync 或对象存储版本;
- 每份备份带 SHA-256;
- 每月在隔离主机恢复一次。
大型数据库或严格低 RPO 系统则可能需要:
- 连续 WAL/binlog 归档;
- 增量物理备份;
- 复制节点;
- 存储快照;
- 定期时间点恢复验证。
复制不是备份:误删数据可能迅速复制到所有副本。快照也不是自动一致:没有数据库协调时,快照可能只是崩溃一致性。高可用解决的是服务连续性,备份恢复解决的是数据回到过去某个可用状态,两者不能互相替代。
十四、最终应交付一份可执行的恢复手册
一份真正可用的运行手册不应只写“执行备份脚本”,而应包含:
Docker Engine 和 Compose 版本
镜像名称、标签和架构
Compose 文件及配置来源
每个 Volume、Bind Mount、tmpfs 的用途
数据库备份命令和恢复命令
备份存储位置、保留策略和加密方式
UID/GID、ACL、SELinux 等权限要求
外部依赖:对象存储、DNS、证书、邮件、队列
校验和验证方法
切换流量和回滚步骤
最近一次恢复演练结果
备份策略的完成标准不是“定时任务没有报错”,而是:
缺少其中任一项,主机迁移时都可能出现“服务启动了,但系统已经不是原来的系统”。
系列导航与关联阅读
- 系列入口:Docker 完整学习路线:从镜像与容器到安全、可观测和生产交付
- 上一篇:Docker 健康检查与优雅关闭:PID 1、Probe、Stop Signal 和超时
- 下一篇:Docker 故障排查:启动失败、网络、磁盘、OOM、构建和 Daemon
- 延伸:Docker 存储:Volume、Bind Mount、tmpfs、权限和备份恢复
- 延伸:Docker 生产交付体系:CI、灰度、回滚、容量和运行手册
官方资料
本文依据 Docker、OCI 与 CNCF 官方文档重新梳理;正文与生产检查清单由 WR BLOG 编写。

评论
0 条讨论