我正在运行一个Docker容器,其卷已安装到/etc
。
我使用以下命令创建容器:
$ docker container run -dt -v volume01:/etc alpine sh
81cf19f2c9ea23d79b900fe8f195fd333df376627710aa78f38f35cf565bfaf0
现在我看到卷目录中的某些文件的大小为0,例如/etc/hosts
文件:
# ls -ltrh /var/lib/docker/volumes/volume01/_data/hosts
-rwxr-xr-x 1 root root 0 26 nov 10:42 /var/lib/docker/volumes/volume01/_data/hosts
此文件实际上不是空的,如果我检查容器中/etc/hosts
的大小,则它不是0:
$ docker exec -ti 81cf19f2c9ea ls -lt /etc/hosts
-rw-r--r-- 1 root root 174 Nov 26 09:42 /etc/hosts
知道为什么会这样吗?
谢谢!
答案 0 :(得分:1)
您观察到的效果非常有趣。为了说明这一点,让我们看一些事实。
第一:Docker以一种非常特殊的方式处理了很少的文件(/etc/hosts
,/etc/hostname
和/etc/resolv.conf
),因为它们包含与网络相关的设置对于不同的容器应该有所不同。
Docker为每个容器生成这些文件,并将它们保存在主机系统上。容器的文件系统具有以下文件的绑定挂载:
$ docker run alpine /bin/sh -c 'mount | grep etc'
/dev/sda1 on /etc/resolv.conf type ext4 (rw,relatime)
/dev/sda1 on /etc/hostname type ext4 (rw,relatime)
/dev/sda1 on /etc/hosts type ext4 (rw,relatime)
第二:在执行绑定挂载之前,Docker必须确保它们的目标存在(因为内核要求挂载点在挂载时存在)。这种东西在所谓的 init层中进行配置,这是一个只读层,它安装在图像文件系统的顶部并包含所需的文件。实际上,Docker只是删除了文件的原始版本(如果有),并在其位置创建了empty stubs。
要对此进行检查,请尝试运行特权容器和umount(8)
这些特殊文件中的任何一个:
$ docker run -it --privileged alpine
/ # cd /etc
/etc # ls -li hosts
3156636 -rw-r--r-- 1 root root 174 Nov 27 09:37 hosts
/etc # umount hosts
/etc # ls -li hosts
3156653 -rwxr-xr-x 1 root root 0 Nov 27 09:37 hosts
第三:alpine
图像本身具有这些文件,但是它们的内容是中性默认值:
$ docker save alpine | tar xO 51667c1dd92cb4d851a7d6413545f5883b758f87251387e70ba531a4562e389f/layer.tar | tar xO etc/hosts
127.0.0.1 localhost localhost.localdomain
::1 localhost localhost.localdomain
因此,映像文件系统包含这些文件的一个(默认)版本,容器文件系统的最高RO层(映像文件系统+ init层)具有这些文件的第二(空)版本,并且正在运行的容器的文件系统(图像文件系统+初始化层+ RW层+所有安装)具有这些文件的第三版。
现在,这些东西与音量有什么关系?
在创建和使用非绑定卷时,Docker使用位于容器中卷挂载点的文件填充卷_data
目录,即在您的示例中,运行时
docker container run -dt -v volume01:/etc alpine sh
Docker将容器的/etc
复制到/var/lib/docker/volumes/volume01/_data
。
问题是:上面讨论的特殊文件的哪个版本被复制?答案是:来自初始化层的存根,因为复制是从最顶层的容器创建之后执行的,而不是在运行时中执行的(安装了这些文件的“实际”版本时)。
因此,您在卷中观察到大小为零的/etc/hosts
,/etc/hostname
和/etc/resolv.conf
,尽管在运行时它们被这些文件的Docker管理版本的绑定挂载隐藏