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 ...
随机推荐
- DAY9(PYTHON)
li=[{'usename':'xiaowang'}, {'} ] board=['张三','李四','王大麻子'] while 1: usename = input('用户名:') if usena ...
- SELinux app权限配置
摘要:1.SEAndroidapp分类SELinux(或SEAndroid)将app划分为主要三种类型(根据user不同,也有其他的domain类型):1)untrusted_app 第三方app,没 ...
- Android 线程交互
在Android开发过程中,耗时操作是不允许写在主线程(UI线程)中的,以免由于等待时间过长而发生ANR.所以耗时操作需要创建子线程来完成,然而往往这些操作都需要与主线程进行通讯交互(例如更新主线程的 ...
- spring4笔记----spring生命周期属性
init-method : 指定bean的初始化方法-spring容器会在bean的依赖关系注入完成后调用该方法 destroy-method :指定bean销毁之前的方法-spring容器将会在销毁 ...
- ajax参数
$.ajax({ type: "GET", url: "Login.ashx", dataType: "text", cache: fals ...
- Sql Server 按格式输出日期
SELECT dbo.fn_Data(getdate(),'yyyymmdd') CREATE FUNCTION [dbo].[fn_Data] (@date as datetime, @format ...
- innerHTML的使用
inerHTML是html标签的属性,成对出现的标签大多数都有这个属性,用来设置或获取位于对象起始和结束标签 内的HTML.(获取HTML当前标签的起始和结束里面的内容)不包括标签本身. ...
- VMware 15 pro虚拟机
VMware虚拟机都到VMware Workstation 15 Pro,真快,VMware 14还没用好
- LeetCode算法题-Find All Numbers Disappeared in an Array(Java实现)
这是悦乐书的第232次更新,第245篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第99题(顺位题号是448).给定一个整数数组,其中1≤a[i]≤n(n =数组的大小) ...
- LeetCode算法题-Reverse Bits(Java实现)
这是悦乐书的第185次更新,第187篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第44题(顺位题号是190).给定32位无符号整数,求它的反转位.例如: 输入:4326 ...