Linux Namespace系列(04):mount namespaces (CLONE_NEWNS)

Mount namespace用來隔離文件系統的掛載點, 使得不一樣的mount namespace擁有本身獨立的掛載點信息,不一樣的namespace之間不會相互影響,這對於構建用戶或者容器本身的文件系統目錄很是有用。shell

當前進程所在mount namespace裏的全部掛載信息能夠在/proc/[pid]/mounts、/proc/[pid]/mountinfo和/proc/[pid]/mountstats裏面找到。ubuntu

Mount namespaces是第一個被加入Linux的namespace,因爲當時沒想到還會引入其它的namespace,因此取名爲CLONE_NEWNS,而沒有叫CLONE_NEWMOUNT。segmentfault

每一個mount namespace都擁有一份本身的掛載點列表,當用clone或者unshare函數建立新的mount namespace時,新建立的namespace將拷貝一份老namespace裏的掛載點列表,但從這以後,他們就沒有關係了,經過mount和umount增長和刪除各自namespace裏面的掛載點都不會相互影響。bash

本篇全部例子都在ubuntu-server-x86_64 16.04下執行經過函數

演示

#--------------------------第一個shell窗口----------------------
#先準備兩個iso文件,用於後面的mount測試
dev@ubuntu:~$ mkdir iso
dev@ubuntu:~$ cd iso/
dev@ubuntu:~/iso$ mkdir -p iso01/subdir01
dev@ubuntu:~/iso$ mkdir -p iso02/subdir02
dev@ubuntu:~/iso$ mkisofs -o ./001.iso ./iso01
dev@ubuntu:~/iso$ mkisofs -o ./002.iso ./iso02
dev@ubuntu:~/iso$ ls
001.iso  002.iso  iso01  iso02
#準備目錄用於mount
dev@ubuntu:~/iso$ sudo mkdir /mnt/iso1 /mnt/iso2

#查看當前所在的mount namespace
dev@ubuntu:~/iso$ readlink /proc/$$/ns/mnt
mnt:[4026531840]

#mount 001.iso 到 /mnt/iso1/
dev@ubuntu:~/iso$ sudo mount ./001.iso /mnt/iso1/
mount: /dev/loop1 is write-protected, mounting read-only

#mount成功
dev@ubuntu:~/iso$ mount |grep /001.iso
/home/dev/iso/001.iso on /mnt/iso1 type iso9660 (ro,relatime)

#建立並進入新的mount和uts namespace
dev@ubuntu:~/iso$ sudo unshare --mount --uts /bin/bash
#更改hostname並從新加載bash
root@ubuntu:~/iso# hostname container001
root@ubuntu:~/iso# exec bash
root@container001:~/iso#

#查看新的mount namespace
root@container001:~/iso# readlink /proc/$$/ns/mnt
mnt:[4026532455]

#老namespace裏的掛載點的信息已經拷貝到新的namespace裏面來了
root@container001:~/iso# mount |grep /001.iso
/home/dev/iso/001.iso on /mnt/iso1 type iso9660 (ro,relatime)

#在新namespace中mount 002.iso
root@container001:~/iso# mount ./002.iso /mnt/iso2/
mount: /dev/loop0 is write-protected, mounting read-only
root@container001:~/iso# mount |grep iso
/home/dev/iso/001.iso on /mnt/iso1 type iso9660 (ro,relatime)
/home/dev/iso/002.iso on /mnt/iso2 type iso9660 (ro,relatime)

#umount 001.iso
root@container001:~/iso# umount /mnt/iso1
root@container001:~/iso# mount |grep iso
/home/dev/iso/002.iso on /mnt/iso2 type iso9660 (ro,relatime)

#/mnt/iso1目錄變爲空
root@container001:~/iso# ls /mnt/iso1
root@container001:~/iso#

#--------------------------第二個shell窗口----------------------
#打開新的shell窗口,老namespace中001.iso的掛載信息還在
#而在新namespace裏面mount的002.iso這裏看不到
dev@ubuntu:~$ mount |grep iso
/home/dev/iso/001.iso on /mnt/iso1 type iso9660 (ro,relatime)
#iso1目錄裏面也有內容
dev@ubuntu:~$ ls /mnt/iso1
subdir01
#說明兩個namespace中的mount信息是隔離的

Shared subtrees

在某些狀況下,好比系統添加了一個新的硬盤,這個時候若是mount namespace是徹底隔離的,想要在各個namespace裏面用這個硬盤,就須要在每一個namespace裏面手動mount這個硬盤,這個是很麻煩的,這時Shared subtrees就能夠幫助咱們解決這個問題。oop

關於Shared subtrees的詳細介紹請參考Linux mount (第二部分),裏面有他的詳細介紹以及bind nount的例子。測試

演示

對Shared subtrees而言,mount namespace和bind mount的狀況差很少,這裏就簡單演示一下shared和private兩種類型spa

#--------------------------第一個shell窗口----------------------
#準備4個虛擬的disk,並在上面建立ext2文件系統,用於後續的mount測試
dev@ubuntu:~/iso$ cd && mkdir disks && cd disks
dev@ubuntu:~/disks$ dd if=/dev/zero bs=1M count=32 of=./disk1.img
dev@ubuntu:~/disks$ dd if=/dev/zero bs=1M count=32 of=./disk2.img
dev@ubuntu:~/disks$ dd if=/dev/zero bs=1M count=32 of=./disk3.img
dev@ubuntu:~/disks$ dd if=/dev/zero bs=1M count=32 of=./disk4.img
dev@ubuntu:~/disks$ mkfs.ext2 ./disk1.img
dev@ubuntu:~/disks$ mkfs.ext2 ./disk2.img
dev@ubuntu:~/disks$ mkfs.ext2 ./disk3.img
dev@ubuntu:~/disks$ mkfs.ext2 ./disk4.img
#準備兩個目錄用於掛載上面建立的disk
dev@ubuntu:~/disks$ mkdir disk1 disk2
dev@ubuntu:~/disks$ ls
disk1  disk1.img  disk2  disk2.img  disk3.img  disk4.img


#顯式的分別以shared和private方式掛載disk1和disk2
dev@ubuntu:~/disks$ sudo mount --make-shared ./disk1.img ./disk1
dev@ubuntu:~/disks$ sudo mount --make-private ./disk2.img ./disk2
dev@ubuntu:~/disks$ cat /proc/self/mountinfo |grep disk| sed 's/ - .*//'
164 24 7:1 / /home/dev/disks/disk1 rw,relatime shared:105
173 24 7:2 / /home/dev/disks/disk2 rw,relatime

#查看mount namespace編號
dev@ubuntu:~/disks$ readlink /proc/$$/ns/mnt
mnt:[4026531840]

#--------------------------第二個shell窗口----------------------
#從新打開一個新的shell窗口
dev@ubuntu:~$ cd ./disks
#建立新的mount namespace
#默認狀況下,unshare會將新namespace裏面的全部掛載點的類型設置成private,
#因此這裏用到了參數--propagation unchanged,
#讓新namespace裏的掛載點的類型和老namespace裏保持一致。
#--propagation參數還支持private|shared|slave類型,
#和mount命令的那些--make-private參數同樣,
#他們的背後都是經過調用mount(...)函數傳入不一樣的參數實現的
dev@ubuntu:~/disks$ sudo unshare --mount --uts --propagation unchanged /bin/bash
root@ubuntu:~/disks# hostname container001
root@ubuntu:~/disks# exec bash
root@container001:~/disks# 

#確認已是在新的mount namespace裏面了
root@container001:~/disks# readlink /proc/$$/ns/mnt
mnt:[4026532463]

#因爲前面指定了--propagation unchanged,
#因此新namespace裏面的/home/dev/disks/disk1也是shared,
#且和老namespace裏面的/home/dev/disks/disk1屬於同一個peer group 105
#由於在不一樣的namespace裏面,因此這裏掛載點的ID和原來namespace裏的不同了
root@container001:~/disks# cat /proc/self/mountinfo |grep disk| sed 's/ - .*//'
221 177 7:1 / /home/dev/disks/disk1 rw,relatime shared:105
222 177 7:2 / /home/dev/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/ - .*//'
221 177 7:1 / /home/dev/disks/disk1 rw,relatime shared:105
222 177 7:2 / /home/dev/disks/disk2 rw,relatime
223 221 7:3 / /home/dev/disks/disk1/disk3 rw,relatime shared:107
227 222 7:4 / /home/dev/disks/disk2/disk4 rw,relatime

#--------------------------第一個shell窗口----------------------
#回到第一個shell窗口

#能夠看出因爲/home/dev/disks/disk1是shared,且兩個namespace裏的這個掛載點都屬於peer group 105,
#因此在新namespace裏面掛載的disk3,在老的namespace裏面也看的到
#可是看不到disk4的掛載信息,那是由於/home/dev/disks/disk2是private的
dev@ubuntu:~/disks$ cat /proc/self/mountinfo |grep disk| sed 's/ - .*//'
164 24 7:1 / /home/dev/disks/disk1 rw,relatime shared:105
173 24 7:2 / /home/dev/disks/disk2 rw,relatime
224 164 7:3 / /home/dev/disks/disk1/disk3 rw,relatime shared:107

#咱們能夠隨時修改掛載點的propagation type
#這裏咱們經過mount命令將disk3改爲了private類型
dev@ubuntu:~/disks$ sudo mount --make-private /home/dev/disks/disk1/disk3
dev@ubuntu:~/disks$ cat /proc/self/mountinfo |grep disk3| sed 's/ - .*//'
224 164 7:3 / /home/dev/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/ - .*//'
223 221 7:3 / /home/dev/disks/disk1/disk3 rw,relatime shared:107

關於mount命令和mount namespace的配合,裏面有不少技巧,後面若是須要用到更復雜的用法,會再作詳細的介紹。.net

參考

相關文章
相關標籤/搜索