侧边栏壁纸
  • 累计撰写 32 篇文章
  • 累计创建 55 个标签
  • 累计收到 2 条评论

目 录CONTENT

文章目录

Linux Namespace:Mount

Testerfans
2022-05-10 / 1 评论 / 27 点赞 / 7,535 阅读 / 7,152 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-06-29,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

本文演示 CentOS 7.6:Linux testerfans 3.10.0-1160.45.1.el7.x86_64

前言

Mount namespace在Linux 2.4.19加入内核中,是第一个被加入到Linux的namespace。有一点需要注意,由于当时没有计划加入其它namespace,所以取名为CLONE_NEWNS,而没有叫CLONE_NEWMOUNT,这个是和其他的namespace命名上有些区别,本章我们将具体了解一下mount namespace。

mount namespace概述

mount namespace使不同的挂载命名空间之间拥有自己的挂载点信息,为进程提供独立的文件系统视图,实现不同的namespace之间文件系统的挂载点隔离,不会相互影响。

当Linux系统启动后会创建一个初始的mnt namespace,在使用clone()或unshare()系统调用通过CLONE_NEWNS标志来创建新的mnt namespace时,这个新的mnt namespace将会拷贝一份clone()或unshare()调用方的挂载点列表。之后对A和A’命名空间下的挂载点进行更改彼此之间不会产生影响(后边介绍的subtrees实际会有影响),进程A’-1和A’-2对所在的A’命名空间下的mount信息可见。

内核将每个进程的挂载点信息保存在/proc/<pid>/{mountinfo,mounts,mountstats}三个文件中:

[root@testerfans proc]# ls -1 /proc/$$/mount*
/proc/12054/mountinfo
/proc/12054/mounts
/proc/12054/mountstats

mount namespace演示

接下来我们将在CentOS7.0上通弄过iso文件的挂载来演示mount namespace对文件系统的隔离。

安装mkisofs命令

在系统内通过mkisofs --version来检查是否有mkisofs命令,如果没有请先进行安装并确认安装成功。

[root@testerfans /]# yum install mkisofs
[root@testerfans /]# mkisofs --version
mkisofs 2.01 is not what you see here. This line is only a fake for too clever
GUIs and other frontend applications. In fact, this program is:
genisoimage 1.1.11 (Linux)

创建演示目录和文件

[root@testerfans ~]# sudo mkdir /demo && sudo chmod 777 /demo && cd $_
[root@testerfans demo]# mkdir -p iso1/subdir1
[root@testerfans demo]# mkdir -p iso2/subdir2
[root@testerfans demo]# mkisofs -o 1.iso ./iso1
[root@testerfans demo]# mkisofs -o 2.iso ./iso2
[root@testerfans demo]# ls
1.iso  2.iso  iso1  iso2

创建挂载点

[root@testerfans /]# mkdir /mnt/iso1  /mnt/iso2
[root@testerfans /]# ls /mnt/
iso1  iso2

演示

为了方便对比效果,我们将终端拆分成两个窗口,左侧为shell1,右侧为shell2。

  • 在shell1中将1.iso挂载到/mnt/iso1目录下。
#-------------------------------shell1-------------------------------
[root@testerfans demo]# mount 1.iso /mnt/iso1/
mount: /dev/loop0 is write-protected, mounting read-only
  • 在shell2中执行 sudo unshare -m:
#-------------------------------shell2-------------------------------
[root@testerfans ~]# unshare -m
  • 对比两个挂载命名空间在两个 shell 中分别执行 readlink /proc/$$/ns/mnt 命令,对比查到的inode number。

如图显示,两个shell的mnt命名空间不同。

  • 在两个 shell 中再分别执行mount | grep 1.iso,对比两个命名空间的挂载点信息是否是拷贝的。

如图显示,两个shell完成了挂载点信息的拷贝。

  • 在 shell2 中卸载1.iso并将2.iso挂载到/mnt/iso2。
#-------------------------------shell2-------------------------------
[root@testerfans demo]# mount 2.iso /mnt/iso2
[root@testerfans demo]# umount /mnt/iso1
[root@testerfans demo]# mount | grep iso

如图显示,在shell2内执行umount /mnt/iso1和mount 2.iso /mnt/iso2并未影响shell1内的挂载点信息,说明两个shell的mnt namespace是隔离的。

shared subtrees介绍

Linux的每个挂载点都具有一个决定该挂载点是否共享子挂载点的属性,称为shared subtrees。该属性以决定某挂载点之下新增或移除子挂载点时,是否同步影响它【副本】挂载点,允许在命名空间之间自动、可控地传播挂载和卸载事件。共享子树特性是在 2006 年初,即大约挂载命名空间实现了三年后加入到Linux 2.6.15中的。

共享子树的作用

假设基于root namespace创建了一个mnt namespace(ns1),那么ns1将具有当前root namespace的挂载点信息拷贝。如果此时新插入了一块磁盘并对其分区格式化,然后在root namespace中对其进行挂载,默认情况下,在ns1中将看不到新挂载的文件系统。这种默认行为可以通过修改shared subtrees属性来改变。

其实,用户创建namespace,其目的一般是希望创建完全隔离的运行环境,所以默认情况下,拷贝挂载点信息时不会拷贝shared subtrees属性,而是将mount namespace中的所有挂载点的shared subtrees属性设置为private。在mnt namespace的示例中,我们演示了两个mnt namespace的隔离可以说明这一点:

  • 在shell1所在的ns中新增或者移除挂载点不会影响shell2所在的ns。
  • 在shell2所在的ns中新增或者移除挂载点同样不会影响shell1所在的ns。

unshare --propagation参数

上述这种默认的行为是可以进行改变的,使用unshare方法有 --propagation private|shared|slave|unchanged选项可以控制创建mnt namespace挂载点的共享方式,具体可以通过unshanre(1)查看具体介绍。

  • private:表示新创建的mnt namespace中的挂载点的shared subtrees属性都设置为private,即ns1和ns2的挂载点互不影响。
  • shared:表示新创建的mnt namespace中的挂载点的shared subtrees属性都设置为shared,即ns1或ns2中新增或移除子挂载点都会同步到另一方。
  • slave:表示新创建的mnt namespace中的挂载点的shared subtrees属性都设置为slave,即ns1中新增或移除子挂载点会影响ns2,但ns2不会影响ns1。
  • unchanged:表示拷贝挂载点信息时也拷贝挂载点的shared subtrees属性,也就是说挂载点A原来是shared,在mnt namespace中也将是shared。
  • 不指定–progapation选项时,创建的mount namespace中的挂载点的shared subtrees默认值是private。

使用mnt namespace的数据进行命令演示。

  • 准备验证数据。
#-------------------------------shell1-------------------------------
[root@testerfans demo] dd if=/dev/zero bs=1M count=32 of=./disk1.img
[root@testerfans demo] dd if=/dev/zero bs=1M count=32 of=./disk2.img
[root@testerfans demo] mkfs.ext2 ./disk1.img
[root@testerfans demo] mkfs.ext2 ./disk2.img
  • 创建挂载点。
#-------------------------------shell1-------------------------------
[root@testerfans demo] mkfdir /mnt/disk1
[root@testerfans demo] mkfdir /mnt/disk2
  • 将disk1.img和disk2.img分别以shared和private挂载到/mnt/disk1和/mnt/disk2

挂载时使用参数具体可以参考mount(8)介绍。

#-------------------------------shell1-------------------------------
[root@testerfans demo]# sudo mount --make-shared disk1.img /mnt/disk1           
[root@testerfans demo]# sudo mount --make-private disk2.img /mnt/disk2 
  • 重新打开一个shell2窗口执行unshare -m --propagation shared。
#-------------------------------shell2-------------------------------
[root@testerfans ~]# unshare -m --propagation shared
  • 查看两个shell的mntspace信息情况。
$ readlink /proc/$$/ns/mnt
$ cat /proc/self/mountinfo |grep disk| sed 's/ - .*//'

image-1652265117893

如图显示,我们可以看到subtrees属性为private的挂载点/mnt/disk2在使用unshare -m --propagation shared命令后,在新的命名空间内变成了shared类型。所以 --propagation private|shared|slave|unchanged 选项是在调用unshare()方法创建mnt ns的时候改变调用方挂载信息拷贝的subtrees属性为我们指定的类型,就像上面例子演示的一样。

删除mnt namespace演示数据

移除挂载点并删除demo目录及演示文件
关闭shell2
shell1中执行

#-------------------------------shell1-------------------------------
$ umount /mnt/iso1 /mnt/disk1 /mnt/disk2
$ rm -rf /mnt/iso* /mnt/disk*
$ cd / && rm -rf /demo

创建演示目录和文件

$ sudo mkdir /demo && sudo chmod 777 /demo && cd $_ &&  mkdir disk1 disk2
$ dd if=/dev/zero bs=1M count=32 of=./disk1.img
$ dd if=/dev/zero bs=1M count=32 of=./disk2.img
$ dd if=/dev/zero bs=1M count=32 of=./disk3.img
$ dd if=/dev/zero bs=1M count=32 of=./disk4.img
$ mkfs.ext2 ./disk1.img
$ mkfs.ext2 ./disk2.img
$ mkfs.ext2 ./disk3.img
$ mkfs.ext2 ./disk4.img
$ ls
disk1  disk1.img  disk2  disk2.img  disk3.img  disk4.img

演示

为了方便对比效果,我们将终端拆分成两个窗口,左侧为shell1,右侧为shell2。

  • 在shell1中执行挂载操作,分别以shared和private方式挂载disk1和disk2。
#-------------------------------shell1-------------------------------
[root@testerfans demo]# sudo mount --make-shared disk1.img ./disk1
[root@testerfans demo]# sudo mount --make-private disk2.img ./disk2
  • 在shell2中执行unshare -m --propagation unchanged。
#-------------------------------shell2-------------------------------
[root@testerfans ~]# unshare -m --propagation unchanged

表示拷贝挂载点信息时也拷贝挂载点的shared subtrees属性,也就是说挂载点A原来是shared,在mnt namespace中也将是shared

  • 对比两个挂载命名空间,在两个 shell 中分别执行 readlink /proc/$$/ns/mnt 命令,对比查到的inode number。

如图显示,两个shell的mnt命名空间不同。

  • 在两个 shell 执行如下指令,确认–propagation unchanged是否生效。
[root@testerfans demo]# cat /proc/self/mountinfo |grep disk| sed 's/ - .*//'

如图显示,两个shell完成了挂载点信息和subtrees属性的拷贝。

  • 在shell2中改变挂载信息,验证shared和private属性作用,分别在disk1和disk2目录下创建两个子目录,并且把disk3和disk4挂载到对应的目录。
#-------------------------------shell2-------------------------------
[root@testerfans demo]# mkdir ./disk1/disk3 ./disk2/disk4
[root@testerfans demo]# mount disk3.img ./disk1/disk3
[root@testerfans demo]# mount disk4.img ./disk2/disk4
  • 通过cat /proc/self/mountinfo |grep disk| sed ‘s/ - .*//’ 查看挂载点信息。

如图显示,在shell2中变更了挂载点之后,shell1中的挂载点信息也发生了变化。

  1. shared类型的 disk1下新增的disk3挂载点信息同步到了shell1的ns。
  2. private类型的disk2下新增的disk4挂载点信息未同步到shell1的ns。
  • 在shell1中改变挂载信息,验证shared和private属性作用。
[root@testerfans demo]# umount ./disk1/disk3 

如图显示,在shell1中umount了shared类型disk1/disk3的挂载点之后,shell2的ns挂载信息也发生了变化。

删除mnt namespace演示数据

移除挂载点并删除demo目录及演示文件
shell2执行退出shell2命名空间

#-------------------------------shell2-------------------------------
$ exit

shell1执行

#-------------------------------shell1-------------------------------
[root@testerfans demo]# umount ./disk1
[root@testerfans demo]# umount ./disk2
[root@testerfans demo]# cd / && rm -rf demo/

总结

通过本篇对mnt ns和subtree的试验,我们简单了解了mnt ns的原理和使用方式,直观的理解了什么是Linux的mnt namespace。后续我们将继续探索其他的命名空间的原理。


本文参考:
mount(8)
unshanre(1)
Linux Namespace:Mount
Linux namespace之:mount namespace
命名空间介绍之八:挂载命名空间和共享子树

27

评论区