在 UOS 如何实现自动将 U 盘挂载到指定目录中?这篇文章中,我描述了 UOS 自动挂载 U 盘到指定目录的方式,现有的发行版处理逻辑大致相同。
当挂载位置确定后,容器内的业务逻辑要访问 U 盘分区中的内容,看上去只需要映射宿主机目录到容器内就万事大吉了,实际测试却发现这种方式存在一个严重的问题,最后使用了 docker volume 来实现此需求,在本文中记录一下。
项目功能开发需要支持当 U 盘插入时自动将 U 盘挂载到某个业务文件夹中在 docker 容器内进行访问,需要调研实现方式。
在 docker 容器创建时映射 U 盘挂载目录的上级目录,在这个场景中其位置是 /media/user。
此问题是 docker 自身的逻辑,这个逻辑在我们的场景中带来的问题是 docker 容器内再也无法正常访问 U 盘挂载目录,那有什么方式能解决此问题呢?
下班路上突发奇想,如果有两个容器同时映射了同一个 docker volume,那其中一个退出另外一个在运行, docker 是否还会卸载 U 盘?
我的答案是不会,因为如果是这样的行为,那就对正常运行的容器功能造成了影响,实现侧可能实现为一个 reference,只有当没有人引用时才会卸载。
测试了下确实是这样的效果,于是创建了一个 docker 服务自动启动的最简容器,此容器映射了我们创建的 docker volume,此时业务容器退出也不会影响卷本身,这个容器的目的就是增加引用计数,就这样不完美的解决了这个问题。
虽然问题得到了解决,但是对于内部的原理并没有太多了解。不禁要问 volume 与直接映射宿主机目录的差别在哪里?
从观察到的现象上我发现有如下两点要素:
具体内部原理还需要进一步研究,解决此问题已经绰绰有余。
在本文描述的问题中,无论是使用 docker -v 映射宿主机目录还是 volume,都将宿主机上的特定目录 bind 到了容器中使用。在 U 盘动态插拔时,会在 bind 的目录下面触发挂载,它们两者最大的区别是对挂载后的新目录树处理不一样。
这实际是跟 mount bind shared subtrees 特性有关系。shared subtrees 允许在命名空间之间自动、可控地传播挂载和卸载事件。shared subtrees 有几种不同的挂载属性,如 shared mount、slave mount、private mount、unbindable mount,不同的属性有不同的效果。
更多信息可以访问 https://segmentfault.com/a/1190000006899213。
对某些技术原理的欠缺容易造成错误的判断,误认为它应该是怎么样,实际测试却发现它不是那样。有时候觉得问题已经无解了,其实只是自己对技术的掌握度相对欠缺不容易想到新的解决方案,此时应该跟同事讨论,看看大家有没有啥新的点子,对这些点子大胆尝试可能会有意料之外的结果。
https://segmentfault.com/a/1190000006899213
https://www.kernel.org/doc/Documentation/filesystems/sharesubtree.txt