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 ...
随机推荐
- Web前端:博客美化:四、网易云音乐单曲播放器
1.页面定制CSS代码 /*3.音乐播放器*/ .content-wrap { overflow-y: scroll; -webkit-overflow-scrolling: touch; } /* ...
- 测者的性测试手册:SWAP的监控
swap是什么 swap是磁盘上的一块区域,可以使一个磁盘分区,也可以是一个文件,也可能是一个两种的组合.当物理内存资源紧张的时候,操作系统(Linux)会将一些不常访问的数据放到swap里.为其他常 ...
- 堆栈的应用——用JavaScript描述数据结构
栈(stack)又名堆栈,它是一种运算受限的线性表.其限制是仅允许在表的一端进行插入和删除运算.这一端被称为栈顶,相对地,把另一端称为栈底. 一.实现一个栈类Stack 基于堆栈的特性,可以用数组做线 ...
- pyHook和pythoncom的安装
pyHook包为Windows中的全局鼠标和键盘事件提供回调.Python应用程序为用户输入事件注册事件处理程序,例如鼠标左键,鼠标左键,按键等,并设置键盘和/或鼠标挂钩.底层C库报告的信息包括事件的 ...
- Troubleshooting SQL Server RESOURCE_SEMAPHORE Waittype Memory Issues
前言: 本文是对博客https://www.mssqltips.com/sqlservertip/2827/troubleshooting-sql-server-resourcesemaphore-w ...
- 完全数java
完全数:小于本身的所有因子的和(包括1) public class test01 { public static void main(String[] args) { Scanner scanner= ...
- [Hive_add_9] Hive 的存储格式
0. 说明 Hive 的存储格式 | textfile | sequencefile | rcfile | orc | parquet | 1. Hive的存储格式 1.1 textfile 行式存储 ...
- Qt的事件
Qt的事件机制 事件过滤器: 可以让一个对象侦听拦截另外一个对象的事件. 实现原理: 在所有Qt对象的基类:QObject中有一个 类型为:QObjectList 名字为:eventFilters 的 ...
- Java入门(四):运算符优先级、关键字与保留字
上次介绍了Java的运算符,今天来介绍下运算符的优先级,以及Java的关键字.保留字. 一.运算符优先级 序号 运算符 名称 目数 结合性 说明 1 [ ] 方括号 从左向右 优先级最高 . 点号 双 ...
- python requests简介
更为强大的库requests是为了更加方便地实现爬虫操作,有了它 , Cookies .登录验证.代理设置等操作都不是 . 一.安装requests模块(cmd窗口执行) pip3 install r ...