1. mount namespace
mount namespace 通過隔離文件系統掛載點對隔離文件系統提供支持。使用 unshare 構造 mount namespace 如下:
root@chunqiu:~/chunqiu/docker/mount# dd if=/dev/zero bs=1M count=32 of=./disk1.img
root@chunqiu:~/chunqiu/docker/mount# dd if=/dev/zero bs=1M count=32 of=./disk2.img
root@chunqiu:~/chunqiu/docker/mount# mkfs.ext4 ./disk1.img
root@chunqiu:~/chunqiu/docker/mount# mkfs.ext4 ./disk2.img
root@chunqiu:~/chunqiu/docker/mount# ls
disk1 disk1.img disk2 disk2.img
root@chunqiu:~/chunqiu/docker/mount# mount disk1.img disk1
root@chunqiu:~/chunqiu/docker/mount# df -hT
Filesystem Type Size Used Avail Use% Mounted on
/dev/loop0 ext4 27M 395K 25M 2% /root/chunqiu/docker/mount/disk1
root@chunqiu:~/chunqiu/docker/mount# readlink /proc/$$/ns/mnt
mnt:[4026531840]
開啟另一個 shell 窗口,並創建 mount namespace:
root@chunqiu:~# unshare --mount /bin/bash
root@chunqiu:~# readlink /proc/$$/ns/mnt
mnt:[4026532206]
root@chunqiu:~# df -hT
Filesystem Type Size Used Avail Use% Mounted on
/dev/loop0 ext4 27M 395K 25M 2% /root/chunqiu/docker/mount/disk1
root@chunqiu:~/chunqiu/docker/mount# mount disk2.img disk2
root@chunqiu:~/chunqiu/docker/mount# df -hT
Filesystem Type Size Used Avail Use% Mounted on
/dev/loop0 ext4 27M 395K 25M 2% /root/chunqiu/docker/mount/disk1
/dev/loop1 ext4 27M 395K 25M 2% /root/chunqiu/docker/mount/disk2
root@chunqiu:~/chunqiu/docker/mount# touch disk1/demo; touch disk2/demo
回到原 mount namespace:
root@chunqiu:~/chunqiu/docker/mount# df -hT
Filesystem Type Size Used Avail Use% Mounted on
/dev/loop0 ext4 27M 395K 25M 2% /root/chunqiu/docker/mount/disk1
root@chunqiu:~/chunqiu/docker/mount# ls disk1
demo
root@chunqiu:~/chunqiu/docker/mount# ls disk2
可以看到,通過 mount namespace 實現了文件系統的隔離:
- 每個 mount namespace 都擁有一份自己的掛載點列表,創建新 mount namespace 時,新創建的 mount namespace 將拷貝一份老 mount namespace 的掛載點列表給自己。
- 默認情況下所有掛載狀態是私有的。
- mount namespace 實現了文件系統的隔離。上例中子文件系統 disk2 不會映射到父 mount namespace,同樣的文件系統下創的文件對父 mount namespace 隔離。
1.1 掛載傳播
上例中介紹了默認情況下所有掛載狀態是私有的。那么,如果父 mount namespace 掛載了一張硬盤,在子 mount namespace 是不可見的,需要在子 mount namespace 中重新 mount。而掛載傳播(mount propagation) 解決了這個問題。它定義了掛載對象之間的關系,系統用這些關系決定了掛載對象中的掛載事件如何傳播到其它掛載對象。
掛載傳播的詳細信息可參閱 man mount,這里以共享和私有掛載為例查看這兩種掛載方式是如何影響子 mount namespace 的:
root@chunqiu:~/chunqiu/docker/mount# ls
disk1 disk1.img disk2 disk2.img
root@chunqiu:~/chunqiu/docker/mount# mount --make-shared disk1.img ./disk1
root@chunqiu:~/chunqiu/docker/mount# mount --make-private disk2.img ./disk2
root@chunqiu:~/chunqiu/docker/mount# df -hT
Filesystem Type Size Used Avail Use% Mounted on
/dev/loop0 ext4 27M 383K 25M 2% /root/chunqiu/docker/mount/disk1
/dev/loop1 ext4 27M 395K 25M 2% /root/chunqiu/docker/mount/disk2
root@chunqiu:~/chunqiu/docker/mount# cat /proc/self/mountinfo |grep disk| sed 's/ - .*//'
54 25 7:0 / /root/chunqiu/docker/mount/disk1 rw,relatime shared:40
55 25 7:1 / /root/chunqiu/docker/mount/disk2 rw,relatime
開啟另一個 shell 窗口,並創建 mount namespace:
root@chunqiu:~# unshare --mount --propagation unchanged /bin/bash
root@chunqiu:~# df -hT
Filesystem Type Size Used Avail Use% Mounted on
/dev/loop0 ext4 27M 383K 25M 2% /root/chunqiu/docker/mount/disk1
/dev/loop1 ext4 27M 395K 25M 2% /root/chunqiu/docker/mount/disk2
root@chunqiu:~# cat /proc/self/mountinfo |grep disk| sed 's/ - .*//'
/* disk1 是 shared 是因為 unshare 指明了 propagation unchanged,如果未指定,默認是私有的 */
116 63 7:0 / /root/chunqiu/docker/mount/disk1 rw,relatime shared:40
118 63 7:1 / /root/chunqiu/docker/mount/disk2 rw,relatime
在原 mount namespace 中創建“硬盤”並模仿掛載事件:
root@chunqiu:~/chunqiu/docker/mount# dd if=/dev/zero bs=1M count=32 of=./disk3.img
root@chunqiu:~/chunqiu/docker/mount# dd if=/dev/zero bs=1M count=32 of=./disk4.img
root@chunqiu:~/chunqiu/docker/mount# mkfs.ext4 ./disk3.img
root@chunqiu:~/chunqiu/docker/mount# mkfs.ext4 ./disk4.img
root@chunqiu:~/chunqiu/docker/mount# mkdir disk2/disk4
root@chunqiu:~/chunqiu/docker/mount# mkdir disk1/disk3
root@chunqiu:~/chunqiu/docker/mount# mount disk3.img disk1/disk3/
root@chunqiu:~/chunqiu/docker/mount# mount disk4.img disk2/disk4/
查看子 mount namespace 的掛載信息:
root@chunqiu:~# df -hT
Filesystem Type Size Used Avail Use% Mounted on
/dev/loop0 ext4 27M 384K 25M 2% /root/chunqiu/docker/mount/disk1
/dev/loop1 ext4 27M 396K 25M 2% /root/chunqiu/docker/mount/disk2
/dev/loop2 ext4 27M 395K 25M 2% /root/chunqiu/docker/mount/disk1/disk3
可以看到共享的掛載傳播方式,文件系統內的掛載事件會映射到子 mount namespace 而私有的掛載傳播方式則不會。