欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  网络运营

Linux Bind Mount 和 Mount Propagation

程序员文章站 2022-03-19 15:01:16
文章目录什么是绑定挂载Shared Subtreespeer grouppropagation type测试bind mount下的挂载传播查看propagation type和peer groupshared、private mountslave mount测试mount namespace下的挂载传播shared subtrees什么是绑定挂载我们知道Linux 每个常规的文件都有inode,inode可以理解为文件的索引节点,其保存了文件的元信息。其实在Linux VFS中,inode stru...

什么是绑定挂载

我们知道Linux 每个常规的文件都有inode,inode可以理解为文件的索引节点,其保存了文件的元信息。

其实在Linux VFS中,inode struct是作为其四大对象之一,还有一个我们常见的较多dentry object

用来访问文件的那个路径,叫做一个dentry(理解为目录项)。比如/tmp/foo。 (dentry 指向 inode

目录是一个保存目录中dentry的inode(目录保存了其下所有dentry和inode的映射),这个inode也有自己的dentry。

软链接(soft_link)是一个独立的inode,它的内容是被链接的dentry

硬链接(hard_link)不是一个inode,它是一个dentry,指向链接对象inode的另一个dentry

Linux Bind Mount 和 Mount Propagation

bind_mount是在dentry之上覆盖了一层dentry(是的,bind_mount可以同时作用在目录和普通文件身上)也就是你通过这个dentry访问inode的时候,你再也访问不到原来的inode了,它指向了被你bind_mount的对象的inode。比如你原来有两个dentry:/tmp/a和/tmp/b,你做mount --bind /tmp/a /tmp/b后,你访问/tmp/b,修改的是原来/tmp/a的inode的内容,你umount后,/tmp/b中原来的内容不会改变,改变的是/tmp/a中的内容

Linux Bind Mount 和 Mount Propagation
有趣的是,当你用mount(或者mount --bind)查看你建立的bind mount链接的时候,它不会显示被你链接的对象文件,而是显示那个文件所在的mount point,比如你mount --bind a b然后你看mount的结果,它可能显示的是:

/dev/sda1 on /home/rancher/test2/b type ext4 (rw,relatime,data=ordered)

这是mount这个构架的原始设计导致的,它仅仅记录每个真正的mountpoint,而不是bind的时候的文件,要知道实际的binding是什么,可以查看这个文件:/proc/self/mountinfo。

所以,ln -s和mount --bind是不同的。前者要求应用程序“知道”这是个链接,后者应用程序会“以为”这个文件是个真正的普通文件。(这也就意味着软连接有一定的局限性,有的应用程序无法通过软连接访问资源,但是使用Bind mount则会像访问正常文件一样

bind可以起到很多ln不能实现的效果(当然,前提是你有root权限)。比如你要修改一个只读文件系统的内容,比如你的/etc/hostname是只读的,你想临时修改,可以在/tmp目录下写一个/tmp/hostname,然后做mount --bind /etc/hostname /tmp/hostname,然后修改后者,就可以了。

bind mount是用挂载文件或目录信息遮盖了挂载的文件或目录,当不需要时,可以通过umount卸载,恢复原文件或目录的信息。(其实也就是一个设备 挂到了多个挂载点)

 # ls -li uts*
583819234 -rw-r--r--. 1 root root 4 1月  23 16:55 uts
606248334 -rw-r--r--. 1 root root 2 1月  23 10:44 uts2
 # mount --bind ./uts2 ./uts
 # ls -li uts*
606248334 -rw-r--r--. 1 root root 2 1月  23 10:44 uts
606248334 -rw-r--r--. 1 root root 2 1月  23 10:44 uts2
#把uts bind-> uts2 上

uts的inode变成了uts2的inode id,所有访问uts的io都会转移到uts2上;并且在mount中能查看到bind mount信息。

 # mount
...
/dev/mapper/rhel_rhel82-root on /home/zhoub/uts type xfs (rw,relatime,seclabel,attr2,inode64,noquota)

Shared Subtrees

Shared subtrees就是一种控制子挂载点能否在其他地方被看到的技术,它只会在bind mount和mount namespace中用到,属于不怎么常用的功能。

如果bind在一起的两个目录下的子目录再挂载了设备的话,他们之间还能相互看到子目录里挂载的内容吗? 比如在第一个目录下的子目录里面再mount了一个设备,那么在另一个目录下面能看到这个mount的设备里面的东西吗?答案是要看bind mountpropagation type。那什么是propagation type呢?

peer grouppropagation type都是随着shared subtrees一起被引入的概念,下面分别对他们做一个介绍。

peer group

peer group就是一个或多个挂载点的集合,他们之间可以共享挂载信息。目前在下面两种情况下会使两个挂载点属于同一个peer group(前提条件是挂载点的propagation type是shared)

  • 利用mount --bind命令,将会使源和目的挂载点属于同一个peer group,当然前提条件是‘源’必须要是一个挂载点。(mount --bind ./uts2 ./uts,将uts dentry bind 到 uts2上,uts2为源挂载点
  • 当创建新的mount namespace时,新namespace会拷贝一份老namespace的挂载点信息,于是新的和老的namespace里面的相同挂载点就会属于同一个peer group。

propagation type

每个挂载点都有一个propagation type标志, 由它来决定当一个挂载点的下面创建和移除挂载点的时候,是否会传播到属于相同peer group的其他挂载点下去,也即同一个peer group里的其他的挂载点下面是不是也会创建和移除相应的挂载点.现在有4种不同类型的propagation type:

  • MS_SHARED: 从名字就可以看出,挂载信息会在同一个peer group的不同挂载点之间共享传播. 当一个挂载点下面添加或者删除挂载点的时候,同一个peer group里的其他挂载点下面也会挂载和卸载同样的挂载点
  • MS_PRIVATE: 跟上面的刚好相反,挂载信息根本就不共享,也即private的挂载点不会属于任何peer group
  • MS_SLAVE: 跟名字一样,信息的传播是单向的,在同一个peer group里面,master的挂载点下面发生变化的时候,slave的挂载点下面也跟着变化,但反之则不然,slave下发生变化的时候不会通知master,master不会发生变化。
  • MS_UNBINDABLE: 这个和MS_PRIVATE相同,只是这种类型的挂载点不能作为bind mount的源,主要用来防止递归嵌套情况的出现。这种类型不常见,本篇将不介绍这种类型,有兴趣的同学请参考这里的例子

还有一些概念需要澄清一下:

  • propagation type是挂载点的属性,每个挂载点都是独立的
  • 挂载点是有父子关系的,比如挂载点/和/mnt/cdrom,/mnt/cdrom都是‘/’的子挂载点,‘/’是/mnt/cdrom的父挂载点
  • 默认情况下,如果父挂载点是MS_SHARED,那么子挂载点也是MS_SHARED的,否则子挂载点将会是MS_PRIVATE,跟爷爷挂载点没有关系

测试bind mount下的挂载传播

# 准备四个虚拟disk,并创建ext2文件系统,用于mount测试
[root@edu3 opt]# mkdir disks
[root@edu3 opt]# cd disks/
[root@edu3 disks]# ls
[root@edu3 disks]# dd if=/dev/zero bs=1M count=32 of=./disk1.img
32+0 records in
32+0 records out
33554432 bytes (34 MB) copied, 0.0186718 s, 1.8 GB/s
[root@edu3 disks]# dd if=/dev/zero bs=1M count=32 of=./disk2.img
32+0 records in
32+0 records out
33554432 bytes (34 MB) copied, 0.0186746 s, 1.8 GB/s
[root@edu3 disks]# dd if=/dev/zero bs=1M count=32 of=./disk3.img
32+0 records in
32+0 records out
33554432 bytes (34 MB) copied, 0.0190978 s, 1.8 GB/s
[root@edu3 disks]# dd if=/dev/zero bs=1M count=32 of=./disk4.img
32+0 records in
32+0 records out
33554432 bytes (34 MB) copied, 0.0206275 s, 1.6 GB/s
mkfs.ext2 ./disk1.img 
mkfs.ext2 ./disk2.img
mkfs.ext2 ./disk3.img
mkfs.ext2 ./disk4.img

#准备两个目录用于挂载上面创建的disk
[root@edu3 disks]# mkdir disk1 disk2
[root@edu3 disks]# ls
disk1  disk1.img  disk2  disk2.img  disk3.img  disk4.img

#确保根目录的propagation type是shared
[root@edu3 disks]#  mount --make-shared /


“/proc/[pid]/mountinfo”,文件,挂载信息,格式为36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue,以空格作为分隔符,从左到右各字段的意思分别是唯一挂载ID、父挂载ID、文件系统的设备主从号码、文件系统中挂载的根节点、相对于进程根节点的挂载点、挂载权限等挂载配置、可选配置、短横线表示前面可选配置的结束、文件系统类型、文件系统特有的挂载源或者为none、额外配置。

查看propagation type和peer group

默认情况下,子挂载点会继承父挂载点的propagation type

# 显示的以shared 方式挂载disk1, private方式挂载disk2
[root@edu3 disks]# mount --make-shared ./disk1.img ./disk1
[root@edu3 disks]# mount --make-private ./disk2.img ./disk2

#mountinfo比mounts文件包含有更多的关于挂载点的信息
#这里sed主要用来过滤掉跟当前主题无关的信息
#shared:1094表示挂载点/home/dev/disks/disk1是以shared方式挂载,且peer group id为1094
#而挂载点/home/dev/disks/disk2没有相关信息,表示是以private方式挂载
[root@edu3 disks]# cat /proc/self/mountinfo |grep disk | sed 's/ - .*//'
784 68 7:0 / /opt/disks/disk1 rw,relatime shared:1094
1724 68 7:1 / /opt/disks/disk2 rw,relatime

#分别在disk1和disk2目录下创建目录disk3和disk4,然后挂载disk3,disk4到这两个目录(不显示指定 挂载传播类型)
[root@edu3 disks]# mkdir ./disk1/disk3 ./disk2/disk4
[root@edu3 disks]# mount ./disk3.img ./disk1/disk3
[root@edu3 disks]# mount ./disk4.img ./disk2/disk4

#查看挂载信息,第一列的数字是挂载点ID,第二例是父挂载点ID,
#从结果来看,784和1737的类型都是shared,而1724和1764的类型都是private的,
#说明在默认mount的情况下,子挂载点会继承父挂载点的propagation type,但是 peer group 是不同的
[root@edu3 disks]# cat /proc/self/mountinfo |grep disk| sed 's/ - .*//'
784 68 7:0 / /opt/disks/disk1 rw,relatime shared:1094
1724 68 7:1 / /opt/disks/disk2 rw,relatime
1737 784 7:2 / /opt/disks/disk1/disk3 rw,relatime shared:1110  #父挂载点是disk1
1764 1724 7:3 / /opt/disks/disk2/disk4 rw,relatime  #父挂载点是disk2

注意,子挂载点继承了父挂载点的 propagation type,但是其peer group不同

shared、private mount

# umount disk3,disk4,创建bind1,bind2用于bind测试
[root@edu3 disks]# umount disk1/disk3/
[root@edu3 disks]# umount disk2/disk4/

#bind的方式挂载disk1到bind1,disk2到bind2

[root@edu3 disks]# mkdir bind1 bind2
[root@edu3 disks]# sudo mount --bind ./disk1 ./bind1
[root@edu3 disks]# sudo mount --bind ./disk2 ./bind2

#查看挂载信息,显然默认情况下bind1和bind2的propagation type继承自父挂载点68(/),注意,这里是继承挂载点,而不是继承目录,因为/opt/disks不是挂载点,都是shared。
#由于bind2的源挂载点disk2是private的,所以bind2没有和disk2在同一个peer group里面,
#而是重新创建了一个新的peer group,这个group里面就只有它一个。
#因为784和1737都是shared类型且是通过bind方式mount在一起的,所以他们属于同一个peer group 1094。

[root@edu3 disks]# cat /proc/self/mountinfo |grep disk| sed 's/ - .*//'
784 68 7:0 / /opt/disks/disk1 rw,relatime shared:1094
1724 68 7:1 / /opt/disks/disk2 rw,relatime
1737 68 7:0 / /opt/disks/bind1 rw,relatime shared:1094
1764 68 7:1 / /opt/disks/bind2 rw,relatime shared:1117

#ID为68的挂载点为根目录的挂载点
[root@edu3 disks]# cat /proc/self/mountinfo |grep ^68| sed 's/ - .*//'  
68 1 253:0 / / rw,relatime shared:1

#这时disk3和disk4目录都是空的
[root@edu3 disks]# tree -L 3
.
├── bind1
│   ├── disk3
│   └── lost+found
├── bind2
│   ├── disk4
│   └── lost+found
├── disk1
│   ├── disk3
│   └── lost+found
├── disk1.img
├── disk2
│   ├── disk4
│   └── lost+found
├── disk2.img
├── disk3.img
└── disk4.img

#重新挂载disk3和disk4
[root@edu3 disks]# clear
[root@edu3 disks]# mount ./disk3.img ./disk1/disk3
[root@edu3 disks]# mount ./disk4.img ./disk2/disk4
[root@edu3 disks]# tree -L 3
.
├── bind1
│   ├── disk3
│   │   └── lost+found
│   └── lost+found
├── bind2
│   ├── disk4
│   └── lost+found
├── disk1
│   ├── disk3
│   │   └── lost+found
│   └── lost+found
├── disk1.img
├── disk2
│   ├── disk4
│   │   └── lost+found
│   └── lost+found
├── disk2.img
├── disk3.img
└── disk4.img
#由于disk1/和bind1/属于同一个peer group,
#所以在挂载了disk3后,在两个目录下都能看到disk3下的内容
#而新生成的挂载点  disk1/disk3 和 bind1/disk3 继承了父挂载点disk1和bind1的 传播类型,由于父挂载点时一个peer group, 则disk1/disk3  和 bind1/disk3 也是一个peer group
#而disk2/是private类型的,所以在他下面挂载disk4不会通知bind2,
#于是bind2下的disk4目录是空的

#再看看disk3,虽然1914和1915的父挂载点不一样(784,1737),但由于他们父挂载点属于同一个peer group(1094),
#且disk3是以默认方式挂载的,所以他们属于同一个peer group 1125
[root@edu3 disks]# cat /proc/self/mountinfo |egrep "disk3"| sed 's/ - .*//'
1914 784 7:2 / /opt/disks/disk1/disk3 rw,relatime shared:1125
1915 1737 7:2 / /opt/disks/bind1/disk3 rw,relatime shared:1125

#umount bind1/disk3后,disk1/disk3也相应的自动umount掉了
[root@edu3 disks]# umount bind1/disk3
[root@edu3 disks]# cat /proc/self/mountinfo |grep disk3
[root@edu3 disks]# cat /proc/self/mountinfo |egrep "disk3"| sed 's/ - .*//'
[root@edu3 disks]# 

#bind mount方式 连接的两个挂载点不是父子关系,而是同属于一个peer group,当前,前提是两个挂载点都是shared

slave mount

#umount除disk1的所有其他挂载点
[root@edu3 disks]# mount|grep disk
/opt/disks/disk1.img on /opt/disks/disk1 type ext2 (rw,relatime)
/opt/disks/disk2.img on /opt/disks/disk2 type ext2 (rw,relatime)
/opt/disks/disk1.img on /opt/disks/bind1 type ext2 (rw,relatime)
/opt/disks/disk2.img on /opt/disks/bind2 type ext2 (rw,relatime)
/opt/disks/disk4.img on /opt/disks/disk2/disk4 type ext2 (rw,relatime)
[root@edu3 disks]# umount disk2/disk4/
[root@edu3 disks]# umount bind1
[root@edu3 disks]# umount bind2
[root@edu3 disks]# umount disk2
[root@edu3 disks]# mount|grep disk    
/opt/disks/disk1.img on /opt/disks/disk1 type ext2 (rw,relatime)

#分别显式的用shared和slave的方式bind disk1
# 将bind1 --> disk1 , bind2-->bind1
[root@edu3 disks]# mount --bind --make-shared ./disk1 ./bind1
[root@edu3 disks]# mount --bind --make-slave ./bind1 ./bind2

#784、1724和1737都属于同一个peer group,
#master:1094表示/opt/disks/bind2 是peer group 1094的slave
[root@edu3 disks]# cat /proc/self/mountinfo |grep disk| sed 's/ - .*//'
784 68 7:0 / /opt/disks/disk1 rw,relatime shared:1094
1724 68 7:0 / /opt/disks/bind1 rw,relatime shared:1094
1737 68 7:0 / /opt/disks/bind2 rw,relatime master:1094

#mount disk3到disk1的子目录disk3下
[root@edu3 disks]# mount ./disk3.img ./disk1/disk3/
#其他两个目录bin1和bind2里面也挂载成功,说明master发生变化的时候,slave会跟着变化
[root@edu3 disks]# cat /proc/self/mountinfo |grep disk| sed 's/ - .*//'
784 68 7:0 / /opt/disks/disk1 rw,relatime shared:1094
1724 68 7:0 / /opt/disks/bind1 rw,relatime shared:1094
1737 68 7:0 / /opt/disks/bind2 rw,relatime master:1094
1764 784 7:1 / /opt/disks/disk1/disk3 rw,relatime shared:1116
1828 1737 7:1 / /opt/disks/bind2/disk3 rw,relatime master:1116
1765 1724 7:1 / /opt/disks/bind1/disk3 rw,relatime shared:1116

#umount disk3,然后mount disk3到bind2目录下
[root@edu3 disks]#  umount ./disk1/disk3/
[root@edu3 disks]# mount ./disk3.img ./bind2/disk3/

#由于bind2的propagation type是slave,所以disk1和bind1两个挂载点下面不会挂载disk3
#从1764的类型可以看出,当父挂载点1737是slave类型时,默认情况下其子挂载点1764是private类型

[root@edu3 disks]# cat /proc/self/mountinfo |grep disk| sed 's/ - .*//'
784 68 7:0 / /opt/disks/disk1 rw,relatime shared:1094
1724 68 7:0 / /opt/disks/bind1 rw,relatime shared:1094
1737 68 7:0 / /opt/disks/bind2 rw,relatime master:1094
1764 1737 7:1 / /opt/disks/bind2/disk3 rw,relatime


如果用到了bind mount和mount namespace,在挂载设备的时候就需要注意一下父挂载点是否和其他挂载点有peer group关系,如果有且父挂载点是shared,就说明你挂载的设备除了在当前挂载点可以看到,在父挂载点的peer group的下面也可以看到

单独mount --make-slave disk2.img disk2/ 意义不大

这只是表明disk2这个挂载点是slave类型,其bind到一个上级之后,才能和上级进行单向传播

测试mount namespace下的挂载传播

Mount namespace用来隔离文件系统的挂载点(配合chroot 隔离文件系统视图之后,可以完全隔离文件系统信息), 使得不同的mount namespace拥有自己独立的挂载点信息,不同的namespace之间不会相互影响,这对于构建用户或者容器自己的文件系统目录非常有用

当前进程所在mount namespace里的所有挂载信息可以在/proc/[pid]/mounts、/proc/[pid]/mountinfo和/proc/[pid]/mountstats里面找到。

Mount namespaces是第一个被加入Linux的namespace,由于当时没想到还会引入其它的namespace,所以取名为CLONE_NEWNS,而没有叫CLONE_NEWMOUNT

每个mount namespace都拥有一份自己的挂载点列表,当用clone或者unshare函数创建新的mount namespace时,新创建的namespace将拷贝一份老namespace里的挂载点列表,但从这之后,他们就没有关系了,通过mount和umount增加和删除各自namespace里面的挂载点都不会相互影响。

新的ns和旧的ns在文件系统上还是公用的(因为挂载点信息一样),所以一旦删除了文件,会影响到宿主机ns,所以容器要搭配chroot 来实现jail效果

#第一个shell窗口
[root@edu3 iso]# pwd
/opt/iso

[root@edu3 iso]# mkdir -p iso01/subdir01
[root@edu3 iso]# mkdir -p iso02/subdir02
[root@edu3 iso]# mkisofs -o ./001.iso ./iso01
[root@edu3 iso]# mkisofs -o ./002.iso ./iso02
[root@edu3 iso]# ls
001.iso  002.iso  iso01  iso02

#查看当前进程所在的mnt ns
[root@edu3 iso]# readlink /proc/$$/ns/mnt
mnt:[4026531840]

#mount 001.iso 到 /mnt/iso1/
[root@edu3 iso]# mount ./001.iso /mnt/iso1/
mount: /dev/loop0 is write-protected, mounting read-only
[root@edu3 iso]# tree -L 2 /mnt/iso1
/mnt/iso1
└── subdir01
1 directory, 0 files
#可以看到,iso1下的内容被 mount到 /mnt/iso1
[root@edu3 iso]# mount |grep /001.iso
/opt/iso/001.iso on /mnt/iso1 type iso9660 (ro,relatime,nojoliet,check=s,map=n,blocksize=2048)

#创建并进入新的mount和uts namespace
[root@edu3 iso]# unshare --mount --uts /bin/bash
[root@edu3 iso]# hostname container001
# 重新执行bash,因为bash在登录的时候才会读取 hostname
[root@edu3 iso]# exec bash
[root@container001 iso]# 

#查看新的mount namespace,发现文件已经变了
[root@container001 iso]# readlink /proc/$$/ns/mnt
mnt:[4026534201]

##老namespace里的挂载点的信息已经拷贝到新的namespace里面来了
[root@container001 iso]# mount |grep /001.iso
/opt/iso/001.iso on /mnt/iso1 type iso9660 (ro,relatime,nojoliet,check=s,map=n,blocksize=2048)
[root@container001 iso]# tree -L 2 /mnt/iso1/
/mnt/iso1/
└── subdir01

1 directory, 0 files

#在新namespace中mount 002.iso
[root@container001 iso]# mount ./002.iso /mnt/iso2/
mount: /dev/loop1 is write-protected, mounting read-only
[root@container001 iso]# mount |grep iso
/opt/iso/001.iso on /mnt/iso1 type iso9660 (ro,relatime,nojoliet,check=s,map=n,blocksize=2048)
/opt/iso/002.iso on /mnt/iso2 type iso9660 (ro,relatime,nojoliet,check=s,map=n,blocksize=2048)

# /mnt/iso2有内容
[root@container001 iso]#  tree -L 3 /mnt/iso2
/mnt/iso2
└── subdir02

#umount 001.iso
[root@container001 iso]# umount /mnt/iso1
[root@container001 iso]# mount |grep iso   
/opt/iso/002.iso on /mnt/iso2 type iso9660 (ro,relatime,nojoliet,check=s,map=n,blocksize=2048)

# 在新ns中看不到/mnt/iso1内容了
[root@container001 iso]# tree -L 3 /mnt/iso1
/mnt/iso1

#--------------------------第二个shell窗口----------------------
#打开新的shell窗口,老namespace中001.iso的挂载信息还在
#而在新namespace里面mount的002.iso这里看不到

[root@edu3 iso]# mount |grep iso
/opt/iso/001.iso on /mnt/iso1 type iso9660 (ro,relatime,nojoliet,check=s,map=n,blocksize=2048)
#/mnt/iso1有内容,iso2没内容
[root@edu3 iso]# tree -L 3 /mnt/iso1
/mnt/iso1
└── subdir01
1 directory, 0 files
[root@edu3 iso]# tree -L 3 /mnt/iso2
/mnt/iso2
0 directories, 0 files
#说明两个namespace中的mount信息是隔离的

shared subtrees

在某些情况下,比如系统添加了一个新的硬盘,这个时候如果mount namespace是完全隔离的,想要在各个namespace里面用这个硬盘,就需要在每个namespace里面手动mount这个硬盘,这个是很麻烦的,这时Shared subtrees就可以帮助我们解决这个问题。

参数和bind mount 差不多,下面演示shared和private类型

#--------------------------第一个shell窗口----------------------
#准备4个虚拟的disk,并在上面创建ext2文件系统,用于后续的mount测试
[root@edu3 opt]# mkdir disks
[root@edu3 opt]# cd disks/
[root@edu3 disks]# dd if=/dev/zero bs=1M count=32 of=./disk1.img
32+0 records in
32+0 records out
33554432 bytes (34 MB) copied, 0.0186718 s, 1.8 GB/s
[root@edu3 disks]# dd if=/dev/zero bs=1M count=32 of=./disk2.img
32+0 records in
32+0 records out
33554432 bytes (34 MB) copied, 0.0186746 s, 1.8 GB/s
[root@edu3 disks]# dd if=/dev/zero bs=1M count=32 of=./disk3.img
32+0 records in
32+0 records out
33554432 bytes (34 MB) copied, 0.0190978 s, 1.8 GB/s
[root@edu3 disks]# dd if=/dev/zero bs=1M count=32 of=./disk4.img
32+0 records in
32+0 records out
33554432 bytes (34 MB) copied, 0.0206275 s, 1.6 GB/s

mkfs.ext2 ./disk1.img 
mkfs.ext2 ./disk2.img
mkfs.ext2 ./disk3.img
mkfs.ext2 ./disk4.img

#准备两个目录用于挂载上面创建的disk
[root@edu3 disks]# mkdir disk1 disk2
[root@edu3 disks]# ls
disk1  disk1.img  disk2  disk2.img  disk3.img  disk4.img

#显式的分别以shared和private方式挂载disk1和disk2
[root@edu3 disks]# mount --make-shared ./disk1.img ./disk1
[root@edu3 disks]# mount --make-private ./disk2.img ./disk2
[root@edu3 disks]# cat /proc/self/mountinfo |grep disk| sed 's/ - .*//'
784 68 7:0 / /opt/disks/disk1 rw,relatime shared:1087
1624 68 7:1 / /opt/disks/disk2 rw,relatime

#查看mount namespace编号
[root@edu3 disks]# readlink /proc/$$/ns/mnt
mnt:[4026531840]

#--------------------------第二个shell窗口----------------------
[root@edu3 iso]# cd /opt/disks/
#创建新的mount namespace
#默认情况下,unshare会将新namespace里面的所有挂载点的类型设置成private,
#所以这里用到了参数--propagation unchanged,
#让新namespace里的挂载点的类型和老namespace里保持一致。
#--propagation参数还支持private|shared|slave类型,
#和mount命令的那些--make-private参数一样,
#他们的背后都是通过调用mount(...)函数传入不同的参数实现的

[root@edu3 disks]# unshare --mount --uts --propagation unchanged /bin/bash
[root@edu3 disks]# hostname container001
[root@edu3 disks]# exec bash
[root@container001 disks]# readlink /proc/$$/ns/mnt
mnt:[4026534209]


#由于前面指定了--propagation unchanged,
#所以新namespace里面的/opt/disks/disk1也是shared(其实就是同一个挂载点的信息复制),
#且和老namespace里面的/opt/disks/disk1属于同一个peer group 1087
#因为在不同的namespace里面,所以这里挂载点的ID和原来namespace里的不一样了
[root@container001 disks]# cat /proc/self/mountinfo |grep disk| sed 's/ - .*//'
3297 1725 7:0 / /opt/disks/disk1 rw,relatime shared:1087
3310 1725 7:1 / /opt/disks/disk2 rw,relatime

#分别在disk1和disk2目录下创建disk3和disk4,然后挂载disk3,disk4到这两个目录
[root@container001 disks]# mkdir ./disk1/disk3 ./disk2/disk4
[root@container001 disks]# mount ./disk3.img ./disk1/disk3/
[root@container001 disks]# mount ./disk4.img ./disk2/disk4/
[root@container001 disks]# cat /proc/self/mountinfo |grep disk| sed 's/ - .*//'
3297 1725 7:0 / /opt/disks/disk1 rw,relatime shared:1087
3310 1725 7:1 / /opt/disks/disk2 rw,relatime
3311 3297 7:2 / /opt/disks/disk1/disk3 rw,relatime shared:1103
3496 3310 7:3 / /opt/disks/disk2/disk4 rw,relatime

#--------------------------第一个shell窗口----------------------
#回到第一个shell窗口
#可以看出由于/home/dev/disks/disk1是shared,且两个namespace里的这个挂载点都属于peer group 1087,
#所以在新namespace里面挂载的disk3,在老的namespace里面也看的到
#但是看不到disk4的挂载信息,那是因为/opt/disks/disk2是private的
[root@edu3 disks]# cat /proc/self/mountinfo |grep disk| sed 's/ - .*//'
784 68 7:0 / /opt/disks/disk1 rw,relatime shared:1087
1624 68 7:1 / /opt/disks/disk2 rw,relatime
3313 784 7:2 / /opt/disks/disk1/disk3 rw,relatime shared:1103
#而且两个ns中的父挂载点在一个 peer group,所以两个ns中的 子挂载点也是同一个peer group 1103

#我们可以随时修改挂载点的propagation type
#这里我们通过mount命令将disk3改成了private类型
[root@edu3 disks]# cat /proc/self/mountinfo |grep disk3| sed 's/ - .*//'
3313 784 7:2 / /opt/disks/disk1/disk3 rw,relatime

#--------------------------第二个shell窗口----------------------
#回到第二个shell窗口,disk3的propagation type还是shared,
#表明在老的namespace里面对propagation type的修改不会影响新namespace里面的挂载点
[root@container001 disks]# cat /proc/self/mountinfo |grep disk3| sed 's/ - .*//'
3311 3297 7:2 / /opt/disks/disk1/disk3 rw,relatime shared:1103

参考链接:
Linux Namespace系列04
Linux Mount(第二部分)

本文地址:https://blog.csdn.net/weixin_40864891/article/details/107330218