从挂载失误操作中抢救数据库

发布于 12 天前  226 次阅读


记一次 MariaDB 数据恢复:从挂载失误操作中抢救数据库

🧨 事故复盘

某天我发现部署在 Docker Compose 下的 MariaDB 容器没有挂载数据卷。于是我就顺手地在 docker-compose.yml 中加了挂载:

本意是把容器里的数据库同步到宿主机目录 ./mariadb_website/data

然而忽略了一个Docker 最基础的知识点

Docker 的挂载是单向的,如果目标目录(宿主机侧)已有内容为空或不存在,会覆盖容器内已有的数据。

于是我愉快地喜提:数据库数据被覆盖清空,WordPress 整站塌了。

🔁 如何恢复

💡 先说结论

Docker 默认会把未挂载的数据目录放在宿主机的 /var/lib/docker/volumes/ 中。

当你没有显式指定 volumes: 时,Docker 会自动为容器的数据目录创建一个匿名 volume,数据库数据就保存在其中。

类似下图所示:

其中 nginx_website 是我显式命名的卷,而 e2b.../_data 就是 Docker 自动创建的匿名卷。

🛠️ 恢复流程

  1. 找到 MariaDB 的匿名数据卷

    查看 /var/lib/docker/volumes/,根据创建时间大小、**volume 内容结构(是否包含 ibdata1ib_logfile0 等)**来判断是否为 MariaDB 数据。

  2. 将数据复制回新挂载目录

    cp -a /var/lib/docker/volumes/db_volume/_data ./mariadb_website/data
  3. 修复权限(MariaDB 容器默认使用 uid 999 的 mysql 用户)

    sudo chown -R 999:999 ./mariadb_website/data
  4. 重启 docker compose up -d,WordPress 页面恢复,世界再次美好。

🔍 Docker 挂载机制与底层理解

匿名卷的来源

当容器第一次创建时,如果你没有定义挂载目录,Docker 会在 /var/lib/docker/volumes/ 下自动创建一个匿名卷,挂载到如 /var/lib/mysql

只有在你 docker rmdocker compose down 并使用 --volumes 参数时,该匿名卷才会被删除。

容器的存储结构(OverlayFS 简述)

容器是由以下组成:

  • 多层 只读镜像层(Image Layers)
  • 一个可写层(Write Layer),也叫diff 层

如果没有挂载卷,数据将写入容器的 diff 层中,一旦容器删除,diff 层也会被删除。

而使用 volume(无论匿名还是命名)可以实现容器之间共享数据,且这里的数据是持久化存储的,volume 生命周期独立于容器

diff 层能否恢复数据?

理论上,Docker 容器的 diff 层位于 /var/lib/docker/overlay2/<ID>/diff,你可以进去查找,但数据是非结构化的,InnoDB 文件格式复杂、数据碎片化严重。

✅ 结论:diff 层不适合恢复数据库。专业恢复需靠数据快照、数据库导出或挂载卷备份。

✅ 总结 & 建议

操作前 checklist ✅ 注意事项 ⚠️
确保 volumes: 明确挂载了数据目录 不挂载数据目录会生成匿名卷
建议使用命名卷,便于管理和恢复 bind mount 操作失误会覆盖容器内数据
定期备份 volume(docker volume backup diff 层 数据无法可靠恢复
使用 docker volume inspect 确认挂载路径 删除容器不等于删除 volume

希望本文对你在 Docker + 数据服务部署中踩过的坑能提供一点参考价值。如果你也踩过类似的坑,欢迎评论区交流。

(全文完)


一沙一世界,一花一天堂。君掌盛无边,刹那成永恒。