容器化部署Postgresql挂载数据卷失效容器化部署Po

容器化部署Postgresql挂载数据卷失效

Volume

docker镜像启动的容器是在可读层上加一层可写层作为容器应用持久化文件的地址。这时的可写层生命周期是与容器相同的,这意味着,如果容器被删除,可写层也会被删除,可写层上的文件就会消失。

为了实现一些文件能够真正持久化到物理磁盘上,docker提供了Volume这一技术,挂载linux的inode文件。Volume是将实际的物理磁盘映射到容器内的指定目录或文件下,使容器内的应用在该目录下的读写都是对磁盘本身的目录或文件进行操作。

比如:将宿主机的/home/data挂载到容器内的/var/lib/data,这样,容器内的应用读取/var/lib/data下的文件信息,实际上是读取宿主机/home/data目录下的文件,应用在/var/lib/data目录下写文件,实际上也是写到/home/data中。

注意:如果映射的是文件,修改宿主机的文件内容可能不会同步到容器内,因为一些编辑器实际上是备份、替换,而不是将修改的信息保存到源文件中。这样,修改后的文件inode并不是源文件,源文件并没有修改,只是不在磁盘上显示了。所以容器中的文件并不会同步新的文件。可以通过挂载目录而不是挂载具体文件来解决这一问题。

Postgresql

在容器化部署Postgresql时,为了将数据持久化,我们也需要将数据挂载出来。根据官方文档显示,PGDATA的默认地址是/var/lib/postgresql/data,我们需要将PGDATA挂载出来。

第一次,我挂载了/var/lib/postgresql这个地址,并没有指定到该地址下的data文件夹。因为我觉得子目录下的文件都一样能够持久化到磁盘上。但是我错了,初始化容器后,查看宿主机的目录,发现下面只有一个空的data文件夹,data文件夹下应该有的数据没有持久化到宿主机的指定目录下。查看容器内的目录发现data/下的文件确实存在,只是没有映射到宿主机上。

我在容器内data/文件夹下新建文件不会映射,在postgresql/下新建文件和文件夹都可以映射成功。这是为什么呢?

在查看官方的Dockerfile后,我找到了思路。

image-20211103111929319.png

Dockerfile中定义了一个卷,指定了/var/lib/postgresql/data这个地址,通过Dockerfile定义的卷使用的映射路径是docker默认的卷挂载地址/var/lib/docker/volumes。这就意味着,data文件夹挂载了/var/lib/docker/volumes/containerId/_data这个目录,所以data文件夹下的文件都在前面那个地址下。

那么问题来了,为什么不会映射postgresql这个文件夹的宿主机地址下只有一个空的文件夹呢?

初步猜测,宿主机中的data文件夹和容器内的文件夹并不是同一个,就像前面提到的修改文件那样,两个文件夹的inode是不是不一样的?

下面验证一下,我将宿主机的test1挂载到容器中/var/lib/postgresql下,将test2挂载到容器中/var/lib/postgresql/data下,并查看test1和test2的inode是不是和容器中postgresql文件夹data文件夹一样。

这是宿主机中的test1和test2的信息,以及test1/data的信息。

这是容器内对应目录的信息:

12312312312.png

可以看到,test1与postgresql的inode一样,test2与data的inode一样,而test1/data的inode和data是不一样的,可以说明test1/data和容器内postgresql/data确实不是一个文件夹。

原因是知道了,但这是怎么造成的,test1/data这个文件夹又是怎么生成的呢?

在网上找不到答案,猜测是因为容器内文件系统在初始化的时候就创建了/var/lib/postgresql/data,test1挂载了postgresql,所以test1/data是操作系统创建的,而test2挂载了/var/lib/postgresql/data,却没有修改test1/data下inode的值。

若是有人知道原因,请告诉我!