Docker基礎: Linux核心名稱空間之(1) mnt namespace
作為開源Container技術代表的Docker,它跟Linux核心的Namespace和Cgroup兩大特性密不可分。物有本末,事有終始。知所先後,則近道矣。理解Linux的這兩大特性將有助於我們更深入的理解Docker。在前面的文章中,我們曾經體驗過如何使用chroot和LXC,在本文中我們將會使用unshare命令來演示Linux核心的MNT Namespace是如何動作的。
Namespace的歷史
Namespace並不是Linux才推出的東西,早在很久之前,Unix上就有類似的東西,而HPUX和Solaris商用的Conatiner更是以前就有推出。而在Linux的2.6之後的版本Namespace就逐步的被加了進來。
Linux Namespace的6大型別
項番 | 型別 | 功能說明 |
---|---|---|
No.1 | MNT Namespace | 提供磁碟掛載點和檔案系統的隔離能力 |
No.2 | IPC Namespace | 提供程序間通訊的隔離能力 |
No.3 | Net Namespace | 提供網路隔離能力 |
No.4 | UTS Namespace | 提供主機名隔離能力 |
No.5 | PID Namespace | 提供程序隔離能力 |
No.6 | User Namespace | 提供使用者隔離能力 |
Ubuntu版本
root@ubuntu :~# uname -a
Linux ubuntu 4.4.0-31-generic #50-Ubuntu SMP Wed Jul 13 00:07:12 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
root@ubuntu:~#
事前確認
確認當前程序PID
root@ubuntu:~# echo $$
32968
root@ubuntu:~#
確認當前程序的各個namespace
root@ubuntu:~# ls -l /proc/$$/ns
total 0
lrwxrwxrwx 1 root root 0 Sep 15 10:23 cgroup -> cgroup:[4026531835]
lrwxrwxrwx 1 root root 0 Sep 15 10:23 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 root root 0 Sep 15 10:23 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 root root 0 Sep 15 10:23 net -> net:[4026531957]
lrwxrwxrwx 1 root root 0 Sep 15 10:23 pid -> pid:[4026531836]
lrwxrwxrwx 1 root root 0 Sep 15 10:23 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Sep 15 10:23 uts -> uts:[4026531838]
root@ubuntu:~#
內容說明
項番 | 內容說明 |
---|---|
No.1 | linux會在/proc下建立所對應的程序相關的資訊,ns則為Namespace的資訊 |
No.2 | $$為當前程序PID,/proc/$$/ns下的Namespace的個數回隨著Linux核心的高低不同顯示的個數不同,因為Linux所支援的Namespace不是一次到位的 |
No.3 | mnt:[4026531840],不同的Namespace都有不同的編號,比如32968的mnt的namespace的編號就是4026531840 |
No.4 | 關於Cgroup會單獨在後面進行說明 |
沒有隔離的mount
首先我們來看一下沒有隔離的mount是怎樣動作的,為了簡單起見使用tmpfs這種基於記憶體的檔案系統來模擬。
事前準備
root@ubuntu:~# mkdir /tmp/testnoisolation
mount tmpfs
root@ubuntu:~# mount -t tmpfs tmpfs /tmp/testnoisolation
root@ubuntu:~# cd /tmp/testnoisolation
root@ubuntu:/tmp/testnoisolation#
建立檔案
root@ubuntu:/tmp/testnoisolation# touch aaa bbb ccc ddd
root@ubuntu:/tmp/testnoisolation# ll
total 4
drwxrwxrwt 2 root root 120 Sep 15 10:56 ./
drwxrwxrwt 13 root root 4096 Sep 15 10:55 ../
-rw-r--r-- 1 root root 0 Sep 15 10:56 aaa
-rw-r--r-- 1 root root 0 Sep 15 10:56 bbb
-rw-r--r-- 1 root root 0 Sep 15 10:56 ccc
-rw-r--r-- 1 root root 0 Sep 15 10:56 ddd
root@ubuntu:/tmp/testnoisolation#
確認
在新起一個終端來確認目錄/tmp/testnoisolation的資訊
admin01@ubuntu:~$ echo $$
33414
admin01@ubuntu:~$ ls -l /tmp/testnoisolation
total 0
-rw-r--r-- 1 root root 0 Sep 15 10:56 aaa
-rw-r--r-- 1 root root 0 Sep 15 10:56 bbb
-rw-r--r-- 1 root root 0 Sep 15 10:56 ccc
-rw-r--r-- 1 root root 0 Sep 15 10:56 ddd
admin01@ubuntu:~$
有隔離的mount
事前準備
root@ubuntu:~# mkdir /tmp/testisolation
使用unshare隔離mnt namespace
雖然也可以使用Linux核心提供的系統函式寫簡單的程式來實現,但是多少有點喧賓奪主的感覺。linux已經提供了非常貼心的unshare命令,只需要下面一行語句我們就能重新啟動一個bash的程序,而在其中的mnt namespace是被隔離的。
root@ubuntu:~# echo $$
32968
root@ubuntu:~# unshare --mount /bin/bash
root@ubuntu:~#
好像沒有任何變化,其實這個已經不是剛才我們的32968程序了,而是一個新的程序,通過確認$$就能確認
root@ubuntu:~# echo $$
33447
root@ubuntu:~#
再來確認一下,33447和32968兩個程序的關係,我們能清楚地看到這是父子關係的兩個程序,雖然都是bash
admin01@ubuntu:~$ ps -ef |grep 32968 |grep -v grep
root 32968 32967 0 10:16 pts/0 00:00:00 -su
root 33447 32968 0 11:09 pts/0 00:00:00 /bin/bash
admin01@ubuntu:~$ pstree 32968
bashqqqbash
admin01@ubuntu:~$
mount tmpfs
root@ubuntu:~# echo $$
33447
root@ubuntu:~# mount -t tmpfs tmpfs /tmp/testisolation
root@ubuntu:~# cd /tmp/testisolation
root@ubuntu:/tmp/testisolation#
建立檔案
root@ubuntu:/tmp/testisolation# touch aaa bbb ccc ddd
root@ubuntu:/tmp/testisolation# ll
total 4
drwxrwxrwt 2 root root 120 Sep 15 11:15 ./
drwxrwxrwt 14 root root 4096 Sep 15 11:02 ../
-rw-r--r-- 1 root root 0 Sep 15 11:15 aaa
-rw-r--r-- 1 root root 0 Sep 15 11:15 bbb
-rw-r--r-- 1 root root 0 Sep 15 11:15 ccc
-rw-r--r-- 1 root root 0 Sep 15 11:15 ddd
root@ubuntu:/tmp/testisolation#
確認
在新起一個終端來確認目錄/tmp/testisolation的資訊,沒有任何資訊。
admin01@ubuntu:~$ ll /tmp/testisolation
total 8
drwxr-xr-x 2 root root 4096 Sep 15 11:02 ./
drwxrwxrwt 14 root root 4096 Sep 15 11:02 ../
admin01@ubuntu:~$
新mnt Namespace編號
/proc/$$/ns下面會列出當前的namespace資訊,我們來看看一下這個使用unshare隔離了mnt namespace的資訊
root@ubuntu:~# ls -l /proc/33447/ns
total 0
lrwxrwxrwx 1 root root 0 Sep 15 11:25 cgroup -> cgroup:[4026531835]
lrwxrwxrwx 1 root root 0 Sep 15 11:11 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 root root 0 Sep 15 11:11 mnt -> mnt:[4026532506]
lrwxrwxrwx 1 root root 0 Sep 15 11:11 net -> net:[4026531957]
lrwxrwxrwx 1 root root 0 Sep 15 11:11 pid -> pid:[4026531836]
lrwxrwxrwx 1 root root 0 Sep 15 11:11 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Sep 15 11:11 uts -> uts:[4026531838]
root@ubuntu:~#
與之前進行比較,我們可以清晰地發現,除了mnt的namespace編號從4026531840變為4026532506之外,其餘都沒有改變。這也是使用unshare -m或者unshare –mnt所實現的隔離,建立了新的namespace。
和chroot的比較
在比較原始的chroot中,畫地為牢之後,是無法掙脫其所指定的根的,雖然有效但是略顯粗暴。而namespace則自由的多,起碼可以自由的動作,當然不只是這一點區別,但是這一點是最為直觀能看出來的
root@ubuntu:/tmp/testisolation# pwd
/tmp/testisolation
root@ubuntu:/tmp/testisolation# cd ../testnoisolation/
root@ubuntu:/tmp/testnoisolation# ll
total 4
drwxrwxrwt 2 root root 120 Sep 15 10:56 ./
drwxrwxrwt 14 root root 4096 Sep 15 11:17 ../
-rw-r--r-- 1 root root 0 Sep 15 10:56 aaa
-rw-r--r-- 1 root root 0 Sep 15 10:56 bbb
-rw-r--r-- 1 root root 0 Sep 15 10:56 ccc
-rw-r--r-- 1 root root 0 Sep 15 10:56 ddd
root@ubuntu:/tmp/testnoisolation#