Linux Namespace : Mount
Mount namespace 为进程提供独立的文件系统视图。简单点说就是,mount namespace 用来隔离文件系统的挂载点,这样进程就只能看到自己的 mount namespace 中的文件系统挂载点。
进程的 mount namespace 中的挂载点信息可以在 /proc/[pid]/mounts、/proc/[pid]/mountinfo 和 /proc/[pid]/mountstats 这三个文件中找到。
每个 mount namespace 都有一份自己的挂载点列表。当我们使用 clone 函数或 unshare 函数并传入 CLONE_NEWNS 标志创建新的 mount namespace 时, 新 mount namespace 中的挂载点其实是从调用者所在的 mount namespace 中拷贝的。但是在新的 mount namespace 创建之后,这两个 mount namespace 及其挂载点就基本上没啥关系了(除了 shared subtree 的情况),两个 mount namespace 是相互隔离的。
本文我们将通过 demo 演示如何对通过 mount namespace 对文件系统进行隔离,以及 shared subtree 在 mount namespace 中的使用方式。本文的演示环境为 ubuntu 16.04。
演示文件系统的隔离
我们通过 iso 文件的挂载来演示 mount namespace 对文件系统的隔离。下面先创建演示用的文件和目录:
$ sudo mkdir /demo && sudo chmod /demo && cd $_
$ mkdir -p iso1/subdir1
$ mkdir -p iso2/subdir2
$ mkisofs -o .iso ./iso1
$ mkisofs -o .iso ./iso2

然后再准备两个充当挂载点:
$ sudo mkdir /mnt/iso1 /mnt/iso2
第一步,我们打开两个 bash shell,为了方便区分,分别把它们称为为 shell1 和 shell2。在 shell1 中执行挂载操作,把 1.iso 挂载到 /mnt/iso1 目录:
$ sudo mount .iso /mnt/iso1

第二步,先在 shell2 中执行 sudo unshare -m,然后在两个 shell 中分别执行 readlink /proc/$$/ns/mnt 命令:

图中左侧为 shell1,右侧为 shell2。可以看出它们的 mount namespace 是不同的。
第三步,通过 mount 命令查看两个 mount namespace 中的挂载点信息:

此时,在这两个 mount namespace 中,挂载点信息是相同的。
第四步,我们在 shell2 中执行一些 mount 和 umount 操作:
$ mount .iso /mnt/iso2
$ umount /mnt/iso1

再查之下发现两个 mount namespace 中的挂载点信息已经完全不一样了,这就说明 mount namespace 之间的挂载点信息是隔离的(也就是文件系统是隔离的)。
演示 shared subtree 功能
Mount namespace 实现了挂载点的隔离,但对于某些应用场景,会让我们用起来很不爽。比如系统新添加了一个磁盘设备,我们打算让所有的 mount namespace 都挂载它。过去的做法只能是在每个 mount namespace 中都挂载一遍,很显然,这太不方便了。于是在 Linux 内核 2.6.15 引入了 shared subtree 的概念来解决这个问题。Shared subtree 的核心是允许在 mount namespace 之间自动地或者是受控地传播 mount 和 umount 事件。
简单起见,本文只演示 shared subtree 中 shared 和 private 两种传播类型在 mount namespace 中的表现。我们可以简单的认为 shared 类型的传播方式可以在满足条件的情况下把 mount 和 umount 事件传播给其它的挂载点,而 private 类型的传播方式则不会把 mount 和 umount 事件传播给其它的挂载点。关于 shared subtree 的详细内容,请参考 shared subtree 文档。关于 shared subtree 与 mount namespace 结合使用的详细信息,请参考 mount namespace 文档。
我们通过虚拟磁盘文件的挂载来演示 shared subtree 在 mount namespace 中的表现。下面先创建演示用的文件和目录:
$ sudo mkdir /demo && sudo chmod /demo && cd $_
$ dd if=/dev/zero bs=1M count= of=./disk1.img
$ dd if=/dev/zero bs=1M count= of=./disk2.img
$ dd if=/dev/zero bs=1M count= of=./disk3.img
$ dd if=/dev/zero bs=1M count= of=./disk4.img
$ mkfs.ext2 ./disk1.img
$ mkfs.ext2 ./disk2.img
$ mkfs.ext2 ./disk3.img
$ mkfs.ext2 ./disk4.img
$ mkdir disk1 disk2

第一步,我们打开两个 bash shell,为了方便区分,分别把它们称为为 shell1 和 shell2。在 shell1 中执行挂载操作,分别以 shared 和 private 方式挂载 disk1 和 disk2:
$ sudo mount --make-shared disk1.img ./disk1
$ sudo mount --make-private disk2.img ./disk2
第二步,在 shell2 中执行 sudo unshare -m --propagation unchanged,然后在两个 shell 中分别执行 readlink /proc/$$/ns/mnt 命令:

图中左侧为 shell1,右侧为 shell2。可以看出它们的 mount namespace 是不同的。默认情况下,unshare 会将新 namespace 里面的所有挂载点的类型设置成 private,所以我们使用参数 --propagation unchanged 让新 namespace 里的挂载点的类型和老 namespace 里保持一致。--propagation 参数还支持 private|shared|slave 类型,和 mount 命令的那些 --make-private 参数一样,它们实际上都是通过调用 mount 函数并传入不同的参数实现的。
第三步,分别在 shell1 和 shell2 中执行 cat /proc/self/mountinfo |grep disk| sed 's/ - .*//' 命令查看挂载点信息:

此时两个 mount namespace 中的挂载点信息是相同的。由于在挂载 /demo/disk1 时应用了 --make-shared 参数,所以上图 shell1 中 /demo/disk1 的挂载方式显示为 shared。又因为在 shell2 中执行 unshare 命令时设置了 --propagation unchanged 参数,所以上图中 shell2 中 /demo/disk1 的挂载方式也显示为 shared(*不设置 --propagation unchanged 参数则为 private 方式*)。
第四步,在 shell2 中分别在 disk1 目录下创建 disk3 目录,在 disk2 目录下创建 disk4 目录,并把 disk3.img 挂载到 ./disk1/disk3 目录,把 disk4.img 挂载到 ./disk2/disk4 目录:
$ mkdir ./disk1/disk3 ./disk2/disk4
$ mount disk3.img ./disk1/disk3
$ mount disk4.img ./disk2/disk4
然后使用分别在 shell1 和 shell2 中使用 cat /proc/self/mountinfo |grep disk| sed 's/ - .*//' 命令查看挂载点信息:

这次 shell1 中的挂载点信息和 shell2 中的挂载点信息是不一样的。因为 /demo/disk1 的挂载方式为 shared,所以它的子挂载点 /demo/disk1/disk3 被传播到了 shell1 所在的 mount namespace 中。而 /demo/disk2 的挂载方式为 private,所以它的子挂载点 /demo/disk2/disk4 不会被传播。
OK,这就完成了 shared subtree 在 mount namespace 间传播挂载点信息的基本功能演示,希望这个小 demo 可以帮助大家了解一点 shared subtree 相关的内容。
总结
要把 mount namespace 介绍清楚显然不是本文的目的,因为单是 shared subtree 在 mount namespace 中的使用方式就够我们好好的研究一番了。所以,本文只是希望以最少的概念加上最简单的 demo 来说明什么是 mount namespace、它可以用来干什么以及如何快速的实验一下。
参考:
Linux Namespace系列(04):mount namespaces (CLONE_NEWNS)
Linux Namespace分析——mnt namespace的实现与应用
Mount namespace man page
Applying mount namespaces
Linux Namespace : Mount的更多相关文章
- 理解Docker(3):Docker 使用 Linux namespace 隔离容器的运行环境
本系列文章将介绍Docker的有关知识: (1)Docker 安装及基本用法 (2)Docker 镜像 (3)Docker 容器的隔离性 - 使用 Linux namespace 隔离容器的运行环境 ...
- Docker之Linux Namespace
Linux Namespace 介绍 我们经常听到说Docker 是一个使用了Linux Namespace 和 Cgroups 的虚拟化工具,但是什么是Linux Namespace 它在Docke ...
- Docker基础技术:Linux Namespace(下)
在 Docker基础技术:Linux Namespace(上篇)中我们了解了,UTD.IPC.PID.Mount 四个namespace,我们模仿Docker做了一个相当相当山寨的镜像.在这一篇中,主 ...
- Docker基础技术:Linux Namespace(上)
时下最热的技术莫过于Docker了,很多人都觉得Docker是个新技术,其实不然,Docker除了其编程语言用go比较新外,其实它还真不是个新东西,也就是个新瓶装旧酒的东西,所谓的The New “O ...
- Docker 基础技术:Linux Namespace(下)
导读 在Docker基础技术:Linux Namespace(上篇)中我们了解了,UTD.IPC.PID.Mount 四个namespace,我们模仿Docker做了一个相当相当山寨的镜像.在这一篇中 ...
- Docker 基础技术之 Linux namespace 详解
Docker 是"新瓶装旧酒"的产物,依赖于 Linux 内核技术 chroot .namespace 和 cgroup.本篇先来看 namespace 技术. Docker 和虚 ...
- Docker 基础技术之 Linux namespace 源码分析
上篇我们从进程 clone 的角度,结合代码简单分析了 Linux 提供的 6 种 namespace,本篇从源码上进一步分析 Linux namespace,让你对 Docker namespace ...
- Linux Namespace : UTS
UTS namespace 用来隔离系统的 hostname 以及 NIS domain name.UTS 据称是 UNIX Time-sharing System 的缩写. hostname 与 N ...
- Linux Namespace : 简介
在初步的了解 docker 后,笔者期望通过理解 docker 背后的技术原理来深入的学习和使用 docker,接下来的几篇文章简单的介绍下 linux namespace 的概念以及基本用法. na ...
随机推荐
- Apache 配置方法(虚拟目录、域名、虚拟主机等)
基本配置 Define SRVROOT "C:/Apache24" #宏定义一个主站点目录常量ServerRoot "${SRVROOT}" ...
- 服务端如何获取客户端请求IP地址
服务端获取客户端请求IP地址,常见的包括:x-forwarded-for.client-ip等请求头,以及remote_addr参数. 一.remote_addr.x-forwarded-for.cl ...
- python3接收、解析邮件
邮件接收 python3可以使用poplib.POP3进行邮件接收,具体如下: import poplib from email.parser import Parser def get_email( ...
- element-ui的table动态生成表头和数据,且表中数据可编辑
1.实现表头的动态渲染 2.表头label和prop字段都要定义 3.去判断显示那个数据表 4.实现双击的时候在可编辑 // 双击修改 弹出input tableDbEdit(row, column, ...
- vue分页组件二次封装---每页请求特定数据
关键步骤: 1.传两个参数:pageCount (每页条数).pageIndex (页码数): 2.bind方法的调用 <!-- 这部分是分页 --> <div class=&quo ...
- 当年写的如何成为一名MSSQL DBA
很多开发人员都想成为一名数据库培训,也有很多人一开始就把自己定位成为一名DBA,DBA究竟需要掌握些什么知识和技能呢?以下是我 做DBA工作和面试DBA时,整理的一些DBA方面的三十个问 ...
- c/c++ 浅拷贝
c/c++ 浅拷贝 编译器合成的拷贝构造函数和=重载函数,只是做如下处理: 对象1.成员变量a = 对象2.成员变量a 如果成员变量a是指针,执行完拷贝构造函数或者*=重载函数**后,对象1和对象2的 ...
- 远程连接ubuntu的MongoDB遇到的坑
首先连接不上,先查看云服务器上的安全组是否添加了对应的端口 如果打开了,那么久查看MongoDB是否允许远程连接 # mongod.conf # for documentation of all op ...
- WPF自定义控件(四)の自定义控件
在实际工作中,WPF提供的控件并不能完全满足不同的设计需求.这时,需要我们设计自定义控件. 这里LZ总结一些自己的思路,特性如下: Coupling UITemplate Behaviour Func ...
- UVA1374-Power Calculus(迭代加深搜索)
Problem UVA1374-Power Calculus Accept:323 Submit:2083 Time Limit: 3000 mSec Problem Description I ...