背景
从宿主机挂载了/docker/etc/crontab到容器的/etc/crontab,修改/docker/etc/crontab 文件的内容,并没有同步到容器的/etc/crontab。同样,修改容器中的/etc/crontab 也不会同步到宿主机的/docker/etc/crontab。
挂载是没有问题的:
重启容器后,新修改的内容又会同步到容器里。那到底是为什么呢?
分析
容器挂载原理:
容器挂载文件,不是通过文件的路径挂载的,而是通过inode来挂载的。inode是linux的文件系统的一个文件编号,实际代表文件的位置。如果inode不一样,但是文件名一样,也代表不同的文件。
所以挂载是要看inode的值,只要这个值一直,挂载就一直有效。如果inode值变了,但是容器里的文件还是以前的inode值,那容器外的文件和容器内的文件就不是挂载的同一个文件,也就不存在同步关系了。
查看宿主机的文件的的inode值:
stat /docker/etc/crontab
如下图:
查看容器里的inode值:
stat /etc/crontab
如下图:
可以看到,Inode值都是8530980,所以目前是挂载成功的。此时文件的内容是会同步的。
但是,此时用vim修改宿主机的/docker/etc/crontab文件,结果发现没有同步到容器中的文件。
再次观察宿主机的文件的Inode值:
可以发现,修改/docker/etc/crontab文件内容后,Inode值变了。既然这个值变了,就说明当前这个文件已经不是挂载的那个文件里。所以新文件的内容自然和容器里的文件无关。
如果此时重启容器,就会以当前的/docker/etc/crontab(Inode为8531906)挂载到容器里,容器里查看也是Inode为8531906 的文件。
使用ls命令也可以查看inode值:
ls -i 文件名
如下,最左边的就是文件的inode值:
现在解释了为什么挂载的文件不同步的问题了。现在问题就是修改文件导致的Inode变化造成的。
很多编辑器有这么一个特点,当编辑保存文件时,编辑器并不是直接修改文件并保存,而是先创建一个新文件,把最新的内容保存到新文件,然后再用新文件替换掉旧文件。这就导致了Inode值变化了,因为文件变了,旧文件被删除了,新文件名和内容被复制过来了而已。
编辑文件的命令可能会这样的除了vim,还有sed命令。
注意,我这里说的是可能,并不是一定。当然还不止是这两个命令,所有编辑器都可能有。这个需要你手动操作后检查inode来确定。当然,vim也并不总是会这样的。
如果你将文件的权限改为777,再使用vim编辑,就不会用新文件来替换了。这里我没有深入研究,但是造成这个变化的,可能和文件权限有关。如果不是777,可能在写文件时有权限问题,所以vim才改为替换文件吧。
所以为了保持操作文件的方法不变,解决问题的最简单的办法就是将文件权限修改一下即可。
chmod 777 /docker/etc/crontab
然而就只能这样处理了吗?我尝试使用:
echo "22" >> /docker/etc/crontab
发现,inode值并没有变化,所以自然也会同步到容器里。只要我们直接操作文件,就没有问题。
以上说的是挂载的文件。如果挂载的是目录,目录内的文件就不会有这个问题,因为挂载点是目录,目录内的文件是通过目录的索引列表来记录的,不管目录内的inode如何变化都是可以找到的。当然,如果目录重建了,也会有这个问题。
但是请注意,/etc/crontab文件如何修改权限为777,则会导致系统定时任务提示:
crond[75248]: (root) BAD FILE MODE (/etc/crontab)
所有定时任务都不会执行了。所以修改权限的方法,需要注意,不适合这样的文件。
所以,你懂了吗?
总结
docker容器挂载的文件有时候在修改后不再同步,究其原因是挂载的文件已经不是原来的那个文件了。通过一系列的原理分析,终于找到了根本原因。解决办法也就很简单了。
来源: docker挂载的文件不能相互同步的问题解决办法-七秒鱼笔记