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. 服务器上每个项目相关的文件夹都要备份!确保备份数据和服务器上数据一致。
相关推荐
wzq11_6661 小时前
Kubernetes集群——存储管理
云原生·容器·kubernetes
隔窗听雨眠4 小时前
云数仓向PostgreSQL生态延伸的技术动因与工程代价
postgresql·数据库架构·云数仓
Peter-OK1 天前
PostgreSQL学习笔记(入门-进阶-精通说明)
笔记·学习·postgresql
闲云自留地1 天前
K8s 的记忆大脑!ETCD 集群部署、etcdctl 命令与备份恢复全通关
容器·kubernetes·etcd
孙克旭_1 天前
k8s基础组件与创建资源
运维·docker·容器·kubernetes
java_logo2 天前
Docker 部署 EmulatorJS:轻松搭建浏览器复古游戏平台
游戏·docker·容器·复古游戏·轩辕镜像·emulatorjs·红白机
吴声子夜歌2 天前
Kubernetes权威指南——网络原理(一)
网络·容器·kubernetes
方便面不加香菜2 天前
Docker Container --容器及容器的操作案例详解
运维·docker·容器
无人生还别怕2 天前
如何搭建docker仓库(轻量级)registry
linux·运维·docker·云原生·容器·registry·openanolisos
YYYing.3 天前
【K8s系列 (一) 】Docker与容器(上篇)
docker·云原生·容器·kubernetes