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. 服务器上每个项目相关的文件夹都要备份!确保备份数据和服务器上数据一致。
相关推荐
虎头金猫6 天前
4K 视频总卡在公网带宽?用 N1 + OpenList 把网盘播放链路重新理顺
运维·服务器·网络·python·容器·beautifulsoup·pandas
分布式存储与RustFS6 天前
MinIO 官方 Docker 镜像被移除:依赖它的项目该怎么办
docker·云原生·devops·对象存储·minio·分布式存储
geovindu6 天前
sql: Transaction & Concurrency Patterns using postgresql 18
postgresql·数据库开发·数据库架构
玉&心6 天前
通过Arthas在线诊断K8S中的内存及JVM等使用情况
docker·k8s·arthas
xing-xing6 天前
Docker容器中Nginx站点根目录网页配置访问
nginx·docker
赵文宇(温玉)6 天前
CoreDNS的hosts插件的缺行配置导致k8s集群异常
容器·kubernetes·rancher
guo_wen_qiang6 天前
上传本地镜像到harbor中
docker·容器·持续部署
羑悻的小杀马特6 天前
Dockerfile 全景指南:从入门编写dockerfile到生产环境镜像优化实战,一步步带你从啃透制作指令到镜像制作落地!
docker·dockerfile·镜像制作
BianHuanShiZhe6 天前
docker常见命令
docker
thinking_talk6 天前
WorkBuddy应用生成背后的数据层:腾讯云PG
postgresql·腾讯云·云数据库