Docker挂载文件,宿主机修改后容器里文件没有同步更新
问题描述
使用 Docker 时,有时需要挂载一个宿主机目录或者文件。但是有时候发现通过 vi 或者 vim 修改完宿主机上的文件之后,容器中对应的文件并没有变化,看不到修改的内容。
问题分析
Docker 中,mount volume 的原理是借用了 Linux Namespace 中的 Mount NameSpace 来隔离系统中不同进程的挂载点视图,实际文件是没有变化。比如,在container中,bash 实际就是一个运行在宿主机上的进程,被 Docker 用 Linux 分别隔离了 Mount Namespace、UTS Namespace、IPC Namespace、PID Namespace、Network Namespace 和 User Namespace,使得它看上去好像运行在了一个独立的、相对隔离的系统上,但实际它的一切资源都是宿主机在不同 Namespace 中的一个投影,文件也不例外。
Linux中,证明文件是否相同的根本途径是,判断其 inode,如果两个文件的inode相同,两个文件必定为同一文件,从而两个文件的内容也必然相同。
可以使用下面任意一个命令来查看文件inode:
stat /path/to/file
ls -i /path/to/file
Linux 默认情况下,vi 或 vim 为了防止在修改文件的过程中,由于磁盘或者系统出现问题而导致当前被修改的文件的损坏,它做了类似如下逻辑:
- 复制出一个需要修改文件的副本,命名为在原来文件的基础上增加 “.swp” 后缀以及 “.” 前缀。
- 修改内容保存到有 .swp 后缀的文件,并 flush 到磁盘
- 执行 :wq 就会交换原文件和 swp 文件的名称
- 删除临时 swp 文件
从上面可以看出,原来的文件已经被删除,虽然新保存的文件名与原先的相同,但 inode 值是不同的。而容器还是会一直记录以前的文件,保持着与原先 inode 值一样的副本。只有当 restart 容器时,容器才会重新读取新的文件。宿主机上修改的内容才会更新。
解决办法
1. 方法一
使用 echo 修改文件,而不是使用 vim 或者 vi。
2. 方法二
使用 cat 重定向来修改文件,而不是使用 vim 或者 vi。
cp /tmp/nginx.conf /tmp/nginx.conf2
vi /tmp/nginx.conf2
cat /tmp/nginx.conf2 > /tmp/nginx.conf
3. 方法三(不推荐)
修改 vim 配置。执行 vim 命令,输入 :scriptnames
查看 vim 配置文件路径,这边配置文件路径是 /etc/vimrc
,在配置文件最后添加如下两行。
set backup
set backupcopy=yes
这样可以解决问题,不过也有一个很大的副作用,那就是每次用vim编辑文件保存之后,vim会生成一个类似该被修改文件,但末尾增加了一个"~“后缀,用以保存修改之前的文件内容。此方法不推荐。
4. 方法四 (推荐)
修改文件权限,文件默认权限是 644,把权限修改为 666。修改完权限后,再次通过 vim 修改并保存后,原文件的 inode 不会发生变化
chmod 666 /root/test.txt
5. 方法五 (推荐)
挂载目录,不要挂载文件。挂载目录不会出现宿主机文件更新,而容器中文件没有更新。
参考链接: