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. 服务器上每个项目相关的文件夹都要备份!确保备份数据和服务器上数据一致。
相关推荐
PGCCC_2 小时前
PostgreSQL 报 no pg_hba.conf entry?认证配置 pg_hba.conf 一次讲透
postgresql
Harry Lei2 小时前
长期记忆系统的设计与实现
spring boot·postgresql·embedding
cui_hao_nan3 小时前
Docker 学习 5
docker·容器
A黄俊辉A3 小时前
两分钟上手docker
运维·docker·容器
程序员老赵5 小时前
Docker 部署 go2rtc:轻松搭建摄像头多协议流媒体平台
前端·docker·直播
努力努力再努力wz6 小时前
【Docker入门系列】:从架构演进到容器化:一文建立 Docker、虚拟化与 Namespace 的底层心智模型
运维·开发语言·数据结构·c++·docker·容器·架构
吴佳浩 Alben6 小时前
多智能体系统的通信风暴与死锁治理:生产级降级与容灾方案
人工智能·docker·ai·容器·架构
玉&心7 小时前
在dockers desktop上面部署k8s的前端和后端
云原生·容器·kubernetes
wdfk_prog7 小时前
Docker 29 与 containerd image store:镜像为什么会保存两种形态
运维·docker·容器