Linux Namespace提供了一種內核級別隔離系統資源的方法,經過將系統的全局資源放在不一樣的Namespace
中,來實現資源隔離的目的。不一樣Namespace
的程序,能夠享有一份獨立的系統資源。目前Linux中提供了六類系統資源的隔離機制,分別是:node
Mount
: 隔離文件系統掛載點UTS
: 隔離主機名和域名信息IPC
: 隔離進程間通訊PID
: 隔離進程的IDNetwork
: 隔離網絡資源User
: 隔離用戶和用戶組的ID下面簡單的介紹一下這些Namespace
的使用和功能。markdown
涉及到Namespace
的操做接口包括clone()
、setns()
、unshare()
以及還有/proc
下的部分文件。爲了使用特定的Namespace
,在使用這些接口的時候須要指定如下一個或多個參數:網絡
CLONE_NEWNS
: 用於指定Mount Namespace
CLONE_NEWUTS
: 用於指定UTS Namespace
CLONE_NEWIPC
: 用於指定IPC Namespace
CLONE_NEWPID
: 用於指定PID Namespace
CLONE_NEWNET
: 用於指定Network Namespace
CLONE_NEWUSER
: 用於指定User Namespace
下面簡單概述一下這幾個接口的用法。dom
能夠經過clone
系統調用來建立一個獨立Namespace
的進程,它的函數描述以下:ide
int clone(int (*child_func)(void *), void *child_stack, int flags, void *arg);
它經過flags
參數來控制建立進程時的特性,好比新建立的進程是否與父進程共享虛擬內存等。好比能夠傳入CLONE_NEWNS
標誌使得新建立的進程擁有獨立的Mount Namespace
,也能夠傳入多個flags使得新建立的進程擁有多種特性,好比:函數
flags = CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC;
傳入這個flags那麼新建立的進程將同時擁有獨立的Mount Namespace
、UTS Namespace
和IPC Namespace
。spa
在3.8內核開始,用戶能夠在/proc/$pid/ns
文件下看到本進程所屬的Namespace
的文件信息。例如PID爲2704進程的狀況以下圖所示:其中4026531839是
Namespace
的ID,若是兩個進程的Namespace
ID相同代表進程同處於一個命名空間中。這裏須要注意的是:只/proc/$pid/ns/
對應的Namespace
文件被打開,而且該文件描述符存在,即便該PID所屬的進程被銷燬,這個Namespace
會依然存在。能夠經過掛載的方式打開文件描述符:code
touch ~/mnt mount --bind /proc/2704/mnt ~/mnt
這樣就能夠保留住PID爲2704的進程的Mount Namespace
了,即便2704進程被銷燬或者退出,ID爲4026531840的Mount Namespace
依然會存在。對象
setns()
函數能夠把進程加入到指定的Namespace
中,它的函數描述以下:blog
int setns(int fd, int nstype);
它的參數描述以下:
fd
參數:表示文件描述符,前面提到能夠經過打開/proc/$pid/ns/
的方式將指定的Namespace
保留下來,也就是說能夠經過文件描述符的方式來索引到某個Namespace
。nstype
參數:用來檢查fd
關聯Namespace
是否與nstype
代表的Namespace
一致,若是填0的話表示不進行該項檢查。經過在程序中調用setns
來將進程加入到指定的Namespace
中。
unshare()
系統調用用於將當前進程和所在的Namespace
分離,並加入到一個新的Namespace
中,相對於setns()
系統調用來講,unshare()
不用關聯以前存在的Namespace
,只須要指定須要分離的Namespace
就行,該調用會自動建立一個新的Namespace
。unshare()
的函數描述以下:
int unshare(int flags);
其中flags
用於指明要分離的資源類別,它支持的flags
與clone
系統調用支持的flags
相似,這裏簡要的敘述一下幾種標誌:
CLONE_FILES
: 子進程通常會共享父進程的文件描述符,若是子進程不想共享父進程的文件描述符了,能夠經過這個flag來取消共享。CLONE_FS
: 使當前進程再也不與其餘進程共享文件系統信息。CLONE_SYSVSEM
: 取消與其餘進程共享SYS V信號量。CLONE_NEWIPC
: 建立新的IPC Namespace
,並將該進程加入進來。這裏須要注意的是:unshare()
和setns()
系統調用對PID Namespace
的處理不太相同,當unshare PID namespace時,調用進程會爲它的子進程分配一個新的PID Namespace
,可是調用進程自己不會被移到新的Namespace
中。並且調用進程第一個建立的子進程在新Namespace
中的PID爲1,併成爲新Namespace
中的init進程。setns()
系統調用也是相似的,調用者進程並不會進入新的PID Namespace,而是隨後建立的子進程會進入。爲何建立其餘的Namespace時unshare()
和setns()
會直接進入新的Namespace,而惟獨PID Namespace不是如此呢?由於調用getpid()
函數獲得的PID是根據調用者所在的PID Namespace而決定返回哪一個PID,進入新的PID namespace會致使PID產生變化。而對用戶態的程序和庫函數來講,他們都認爲進程的PID是一個常量,PID的變化會引發這些進程奔潰。換句話說,一旦程序進程建立之後,那麼它的PID namespace的關係就肯定下來了,進程不會變動他們對應的PID namespace。
經過上面簡單的概述,對於Namespace
的操做有如下方式:
clone
系統調用爲新進程分配一個或多個新的Namespace
。setns()
將進程加入到已有的Namespace
中。unshare()
爲已存在的進程建立一個或多個新的Namespace
。接下來詳細的介紹一下各個Namespace
的功能和特性。
Mount Namespace
用來隔離文件系統的掛載點,不一樣Mount Namespace
的進程擁有不一樣的掛載點,同時也擁有了不一樣的文件系統視圖。Mount Namespace
是歷史上第一個支持的Namespace
,它經過CLONE_NEWNS
來標識的。
掛載的過程是經過mount
系統調用完成的,它有兩個參數:一個是已存在的普通文件名,一個是能夠直接訪問的特殊文件,一個是特殊文件的名字。這個特殊文件通常用來關聯一些存儲卷,這個存儲卷能夠包含本身的目錄層級和文件系統結構。mount
所達到的效果是:像訪問一個普通的文件同樣訪問位於其餘設備上文件系統的根目錄,也就是將該設備上目錄的根節點掛到了另一個文件系統的頁節點上,達到給這個文件系統擴充容量的目的。能夠經過/proc
文件系統查看一個進程的掛載信息,具體作法以下:
cat /proc/$pid/mountinfo
其輸出結果以下:其中輸出的格式以下:
進程在建立Mount Namespace
時,會把當前的文件結構複製給新的Namespace
,新的Namespace
中的全部mount
操做僅影響自身的文件系統。但隨着引入掛載傳播的特性,Mount Namespace
變得並非徹底意義上的資源隔離,這種傳播特性使得多Mount Namespace
之間的掛載事件能夠相互影響。掛載傳播定義了掛載對象之間的關係,系統利用這些關係來決定掛載對象中的掛載事件對其餘掛載對象的影響。其中掛載對象之間的關係描述以下:
Namespace
共享到其餘掛載對象。Namespace
的掛載事件是互不影響的(默認選項)。其中給掛載點設置掛載關係的例子以下:
mount --make-shared /mntS # 將掛載點設置爲共享關係屬性 mount --make-private /mntP # 將掛載點設置爲私有關係屬性 mount --make-slave /mntY # 將掛載點設置爲從屬關係屬性 mount --make-unbindable /mntU # 將掛載點設置爲不可綁定屬性
注意在設置私有關係屬性時,在本命名空間下的這個掛載點是Slave,而父命名空間下這個掛載點是Master,掛載傳播的方向只能由Master傳給Slave。
綁定掛載的引入使得mount
的其中一個參數不必定要是一個特殊文件,也能夠是該文件系統上的一個普通文件目錄。Linux中綁定掛載的用法以下:
mount --bind /home/work /home/alpha mount -o bind /home/work /home/alpha
其中/home/work
是磁盤上的存在的一個目錄,而不是一個文件設備(好比磁盤分區)。若是須要將Linux中兩個文件目錄連接起來,能夠經過綁定掛載的方式,掛載後的效果相似於在兩個文件目錄上創建了硬連接。在綁定掛載中同時會涉及到掛載的傳播特性,掛載傳播的特性參考:Linux綁定掛載
UTS Namespace
提供了主機名和域名的隔離,也就是struct utsname
裏的nodename
和domainname
兩個字段。不一樣Namespace
中能夠擁有獨立的主機名和域名。那麼爲何須要對主機名和域名進行隔離呢?由於主機名和域名能夠用來代替IP地址,若是沒有這一層隔離,同一主機上不一樣的容器的網絡訪問就可能出問題。
IPC Namespace
是對進程間通訊的隔離,進程間通訊常見的方法有信號量、消息隊列和共享內存。IPC Namespace
主要針對的是SystemV IPC和Posix消息隊列,這些IPC機制都會用到標識符,好比用標識符來區分不一樣的消息隊列,IPC Namespace
要達到的目標是相同的標識符在不一樣的Namepspace
中表明不一樣的通訊介質(好比信號量、消息隊列和共享內存)。原文