6月19日 19:34

Docker 容器灾难恢复计划要备份和演练什么?

Docker 容器灾难恢复计划,不能只写一句“定期备份镜像和数据卷”。真正出问题时,决定恢复速度的往往不是镜像在不在,而是配置能不能还原、数据是不是一致、依赖服务有没有顺序、账号密钥是否还能用,以及团队是否知道第一步该做什么。

一个可执行的 Docker 灾备方案,至少要回答三个问题:丢了什么能恢复、多久能恢复、最多能接受丢多少数据。

先定清楚 RTO 和 RPO

灾难恢复计划先别急着写命令,先定两个指标:

  • RTO(恢复时间目标):服务中断后,最多允许多久恢复。例如官网 30 分钟、内部报表 4 小时。
  • RPO(恢复点目标):最多允许丢多少数据。例如订单库最多丢 5 分钟数据,日志系统可以丢 1 小时。

这两个值会直接影响备份频率、存储成本和架构复杂度。RPO 要求越小,越不能只靠每天一次的文件备份,通常需要数据库主从、增量备份、对象存储版本控制或跨区域复制。RTO 要求越短,就越依赖自动化脚本、预热环境和清晰的恢复 runbook。

Docker 灾备到底要备份什么

很多事故恢复失败,是因为只备份了镜像,却漏掉了运行时配置和数据。Docker 环境至少要覆盖下面几类资产。

镜像和镜像仓库

镜像可以用 docker save 导出:

bash
docker save -o app-web.tar registry.example.com/app/web:2026-06-01 docker load -i app-web.tar

docker save/load 更适合少量镜像或离线环境兜底,不适合作为长期主备方案。它不会替你管理镜像版本、扫描漏洞或清理过期层,也不解决服务如何重新跑起来。更稳妥的方式是维护私有镜像仓库,并备份 registry 存储后端、访问凭证、复制策略和保留规则。

编排配置和启动参数

恢复容器不能靠记忆。下面这些配置都应该进入版本管理或安全备份:

  • docker-compose.yml.env、override 文件;
  • Kubernetes 的 Deployment、StatefulSet、Service、Ingress、ConfigMap、Secret、PVC 等 YAML;
  • 容器启动参数,例如端口映射、网络、挂载路径、健康检查、重启策略;
  • Nginx、网关、服务发现、负载均衡配置;
  • 定时任务、消费者、后台 worker 的启动方式;
  • CI/CD 部署脚本和环境变量模板。

如果历史服务没有 compose 文件,可以用下面的命令把现有容器配置先导出来,作为整理依据:

bash
docker inspect app-web > app-web.inspect.json

docker inspect 更像事故调查记录,真正可维护的恢复配置应该沉淀为 Compose、Helm Chart、Kustomize 或 Terraform 等可重复执行的文件。

数据卷、挂载目录和上传文件

容器本身应该尽量无状态,真正要命的是 volume、数据库和用户上传文件。Docker volume 可以用临时容器打包:

bash
docker run --rm -v app_data:/data -v /backup:/backup alpine tar czf /backup/app_data_$(date +%F).tar.gz -C /data .

恢复时反向解包:

bash
docker run --rm -v app_data:/data -v /backup:/backup alpine tar xzf /backup/app_data_2026-06-01.tar.gz -C /data

如果 volume 中存的是数据库文件,不建议在数据库运行时直接 tar 目录。MySQL、PostgreSQL、MongoDB、Redis 都应该使用各自的备份工具或快照机制,例如 mysqldumppg_dump、WAL 归档、逻辑备份、存储卷快照等。

数据库、外部依赖和密钥

应用能不能恢复,还取决于 MySQL、PostgreSQL、Redis、消息队列、对象存储、CDN、DNS、证书、OAuth 回调地址、支付和短信服务。建议维护一张依赖关系图:哪个容器依赖哪个数据库、队列、存储桶、域名和密钥。恢复时先恢复底层依赖,再恢复业务服务。

.env、Kubernetes Secret、TLS 证书、JWT 密钥、数据库密码不能和普通配置一样随便放进仓库。它们需要加密备份,并明确谁有权限解密。灾备演练时要验证密钥是否能被正确拉取,而不是只验证文件存在。

恢复流程要写成 runbook

灾难发生时,没人愿意在凌晨临时翻聊天记录。恢复流程应该写成 runbook,按步骤执行:

  1. 确认事故范围:单容器异常、宿主机损坏、机房故障,还是镜像仓库不可用。
  2. 冻结现场信息:保留日志、容器 inspect、宿主机磁盘和网络状态。
  3. 准备目标环境:确认 Docker 版本、内核参数、磁盘挂载、网络、防火墙、时区和系统依赖。
  4. 恢复镜像:优先从镜像仓库拉取固定 tag 或 digest,必要时使用 docker load
  5. 恢复配置:应用 compose、Kubernetes manifests、环境变量、Secret、证书和网关配置。
  6. 恢复数据:先恢复数据库,再恢复 volume、上传文件、对象存储索引等业务数据。
  7. 按依赖顺序启动服务:数据库、缓存、队列、后端服务、前端网关、定时任务依次恢复。
  8. 验证功能:检查健康接口、登录、下单、上传、异步任务、回调等关键路径。
  9. 切换流量:通过 DNS、负载均衡、网关或 Kubernetes Service 将流量切到恢复环境。
  10. 复盘记录:记录实际 RTO、实际 RPO、失败步骤和需要补齐的自动化脚本。

容器状态是 running 不代表业务已经恢复。真正的验证应该来自业务探针,例如能否创建订单、能否写入数据库、队列是否消费、文件是否能访问。

高可用设计不能等灾难后再补

备份解决的是“坏了以后能不能回来”,高可用解决的是“坏的时候能不能少中断”。Docker 单机部署至少要配置重启策略、健康检查、磁盘和 Docker daemon 监控,并把日志采集到集中系统。

如果业务要求更高,应该考虑多节点和跨区域:使用 Kubernetes、Docker Swarm 或云容器服务做多副本调度;数据库采用主从复制、跨可用区部署或托管数据库;镜像仓库做跨区域复制;对象存储开启版本控制和跨区域复制;流量入口支持 DNS Failover 或负载均衡故障转移。

跨区域灾备要特别小心数据一致性。应用服务跨区域比较容易,数据库跨区域才是难点。同步复制延迟低但成本高,异步复制便宜但可能丢数据,这要回到 RPO 来取舍。

备份是否可用,必须靠演练证明

没有恢复演练的备份,只能算心理安慰。建议至少做三类测试:备份完整性检查、局部恢复演练、全链路灾备演练。演练时要记录实际 RTO、实际 RPO、失败步骤、人工操作和业务验证结果。

如果每次演练都要靠某个老员工“凭经验操作”,这本身就是风险。灾备计划应该让新同事也能按文档恢复到可用状态。

监控和告警也属于灾备的一部分

灾备不是从服务挂掉才开始。建议监控容器重启次数、退出码、健康检查状态、宿主机 CPU/内存/磁盘/inode、Docker daemon 状态、镜像仓库拉取失败率、数据库复制延迟、备份任务成功率、队列积压和关键接口成功率。

备份任务也要有告警。最糟糕的情况不是备份失败,而是备份失败了三个月没人知道。

常见坑

  1. 只备份容器,不备份数据卷:容器能启动,但业务数据没了。
  2. 只备份数据,不备份配置:数据在,但服务跑不起来。
  3. 镜像使用 latest 标签:恢复时拉到的可能不是事故前版本。
  4. 数据库热备方式不对:直接压缩运行中的数据目录,恢复后数据损坏。
  5. Secret 没有备份或无法解密:服务启动后连不上数据库和第三方接口。
  6. 没有依赖顺序:应用先启动,数据库和队列没恢复,导致大量报错。
  7. 没有恢复验证:容器显示 running,但核心业务路径不可用。
  8. 备份和生产在同一台机器:宿主机磁盘坏了,备份也一起没了。

一份可落地的 Docker 灾备清单

  • RTO、RPO 已按业务等级定义;
  • 镜像使用固定 tag 或 digest,并有可用镜像仓库;
  • Compose、Kubernetes manifests、环境变量模板进入版本管理;
  • Secret、证书、Token 有加密备份和恢复权限说明;
  • volume、上传文件、对象存储有独立备份策略;
  • 数据库使用官方工具或可靠快照备份;
  • 依赖关系图清楚标出数据库、队列、缓存、外部接口;
  • 恢复 runbook 写明执行顺序、命令、负责人和验证方式;
  • 备份任务、复制延迟、容器健康状态都有监控告警;
  • 至少定期做一次局部恢复演练,核心系统做全链路演练。

Docker 容器灾难恢复计划的重点,不是把所有命令都背下来,而是把“能不能恢复”变成一件可验证、可重复、可交接的事。镜像、配置、数据、密钥、依赖和演练缺一不可。

标签:Docker