Docker记录:误删宿主机挂载目录导致 PostgreSQL 数据丢失

Docker记录:误删宿主机挂载目录导致 PostgreSQL 数据丢失

最近在使用 Docker 部署 PostgreSQL 时踩了一个坑:因为对 -v 参数理解不够深入,误删了宿主机上的挂载目录,结果容器内的数据"凭空消失"了。
这个过程中,还存在其他操作错误,这篇博客记录一下这个问题的来龙去脉,希望能帮助其他朋友避开同样的坑。

1. Docker启动PostgreSQL服务

我的项目分为一期和二期,代码文件夹名暂且叫做period1和period2。一期开发的时候,我用docker启动postgreSQL服务。

代码目录在/home/root/period1/

bash 复制代码
sudo docker run -d \
  --name db_ai \
  -e POSTGRES_PASSWORD=123456 \
  -e POSTGRES_DB=db1 \
  -e POSTGRES_USER=postgre_db \
  -v /home/root/period1/postgres_data:/var/lib/postgresql \
  -p 5432:5432 \
  postgres:latest

命令本身没问题,服务也正常启动。我在这个postgres docker容器中,建立了一期的数据表。

二期开发的时候,我建了period2文件夹来存二期的代码,使其不影响一期服务。代码目录在/home/root/period2。并且,我在docker中另建了一张二期的数据表 ,将数据在软件层面隔离。并且认为,只要我不删这个docker容器,数据就会妥妥的一直在里面。

2. 我删了什么?

二期顺利上线了,该清清一期的旧数据了。我做了两件事:

  1. 我进入postgres docker容器,将Period1 data表删除;
  2. 我将一期的代码删除,代码目录在/home/root/period1/;

3. Ooops!问题来了

我用rm -rf删掉了一期整个代码目录:/home/root/period1

然后悲剧发生了:二期的代码服务中,postgres数据库无法正常使用,查postgres docker状态已经自动退出。

我想着,退出就退出吧,重启一下服务就行了。结果发现重启后,之前没删的二期数据库、表都不存在了!

回到上一节,我删了什么?第1删表不会有问题,那问题就出现在2删了代码目录。我使用的docker启动postgreSQL服务的命令中,-v /宿主机路径:/var/lib/postgresql实际上是将docker容器内路径映射到宿主机路径中,数据实际存储在宿主机目录/home/root/period1/postgres_data中,二期使用的同一个docker,相当于二期的数据也在这个目录中。当我执行rm -rf删除/home/root/period1等于直接删了数据库的所有物理文件(表数据、索引、事务日志等)。当我重启容器后,容器发现找不到/home/root/period1/postgres_data,会自动执行initdb初始化一个新的空白数据库实例。

赶紧尝试恢复文件!时间一分一秒过去,要知道,当我删了这个目录,相当于计算机中的一块内存被释放,那么其他服务、日志在磁盘的写入都有可能会覆盖这块内存,就无力回天了。AI告诉我:赶紧卸载这块分区,阻止任何新的写入操作,避免已删除的数据块被覆盖!

但问题又出现了,卸载分区失败。WHY?/home/root/并不是独立的数据分区 ,而是系统根分区!

意味着,系统本身在不断写入日志、临时文件等,导致卸载失败。如果我在这个分区上直接强行运行恢复工具,可能导致系统崩溃。遂放弃恢复,只能重传数据。

4.问题核心:为什么删掉宿主机目录后,容器数据就访问不了?

这又要讲到docker的挂载方式,我使用的是Bind Mount挂载方式,容器不保存数据的副本!

类比:把一个U盘(宿主机目录)插在电脑上(docker容器)。电脑里的文件(数据库数据)实际存储在U盘上,我把U盘拔掉并格式化(rm -rf),电脑里的"文件快捷方式"还在,但指向的物理储存已经没了,所以电脑打不开这些文件。如果我当时用Docker volume或容器内部存储,情况都会不一样。

Docker volume挂载示例:

bash 复制代码
# 创建 volume
sudo docker volume create postgres_data

# 使用 volume
sudo docker run -d \
  --name postgres_ai \
  -e POSTGRES_PASSWORD=123456 \
  -e POSTGRES_DB=ai \
  -v postgres_data:/var/lib/postgresql/data \
  -p 5432:5432 \
  postgres:latest

Docker内部挂载示例:

bash 复制代码
sudo docker run -d \
  --name postgres_ai \
  -e POSTGRES_PASSWORD=123456 \
  -e POSTGRES_DB=ai \
  -p 5432:5432 \
  postgres:latest

但Docker内部挂载的话,如果把容器删了数据也会丢,不推荐。

5.总结

  1. Bind Mount是共享 而非复制,删了宿主机目录,容器虽然活着,但数据没了。
  2. 数据相关的文件不要放在项目代码中,并需要设独立分区。这样即使误删了,也有恢复的可能性。
  3. 服务器上每个项目相关的文件夹都要备份!确保备份数据和服务器上数据一致。
相关推荐
一直在努力学习的菜鸟9 小时前
PostgreSQL流复制和PostgreSQL高可用的区别
postgresql
我不会起名字32210 小时前
Redis 从 0 到 1(九):主库宕机 30 秒自动切主——1 主 2 从 3 哨兵 + Go 客户端
redis·docker·sentinel·高可用·哨兵
ss27311 小时前
PG实战笔记 | 09 PostgreSQL psql客户端基本操作
数据库·笔记·postgresql
姜鱼问生12 小时前
每次开机手动检查 6 样东西?我写了个 2 秒自检脚本
运维·网络·nginx·docker·容器
wangqiaowq12 小时前
PostgresSQL server Docker 安装部署
运维·docker·容器
程序员阿明13 小时前
docker搭建视频流服务go2rtc,webRTC
docker·容器·webrtc
TTATTC13 小时前
让 16 个 AI 员工在飞书群自我协同:基于 OpenClaw 的多 Agent 敏捷 Squad 拓扑与一人公司实操
docker·开源
TTATTC13 小时前
从分片续传到 SPI 插件化扩展:Free-FS 企业级文件系统核心架构与万能预览技术拆解
docker·开源
JavaPub-rodert14 小时前
Docker 容器为什么 stop 半天停不下来?讲透 PID 1、SIGTERM、SIGKILL、僵尸进程与 tini
运维·docker·容器
一直在努力学习的菜鸟16 小时前
PostgreSQL流复制实现主从数据同步
postgresql