天天看點

Linux的命名空間詳解--Linux程序的管理與排程(二) 命名空間概念 Linux核心命名空間描述 命名空間的建立

傳統上,在linux以及其他衍生的unix變體中,許多資源是全局管理的。

例如,系統中的所有程序按照慣例是通過pid辨別的,這意味着核心必須管理一個全局的pid清單。而且,所有調用者通過uname系統調用傳回的系統相關資訊(包括系統名稱和有關核心的一些資訊)都是相同的。使用者id的管理方式類似,即各個使用者是通過一個全局唯一的uid号辨別。

全局id使得核心可以有選擇地允許或拒絕某些特權。雖然uid為0的root使用者基本上允許做任何事,但其他使用者id則會受到限制。例如uid為n 的使用者,不允許殺死屬于使用者m的程序(m≠ n)。但這不能防止使用者看到彼此,即使用者n可以看到另一個使用者m也在計算機上活動。隻要使用者隻能操縱他們自己的程序,這就沒什麼問題,因為沒有理由不允許使用者看到其他使用者的程序。

但有些情況下,這種效果可能是不想要的。如果提供web主機的供應商打算向使用者提供linux計算機的全部通路權限,包括root權限在内。傳統上,這需要為每個使用者準備一台計算機,代價太高。使用kvm或vmware提供的虛拟化環境是一種解決問題的方法,但資源配置設定做得不是非常好。計算機的各個使用者都需要一個獨立的核心,以及一份完全安裝好的配套的使用者層應用。

命名空間提供了一種不同的解決方案,所需資源較少。在虛拟化的系統中,一台實體計算機可以運作多個核心,可能是并行的多個不同的作業系統。而命名空間則隻使用一個核心在一台實體計算機上運作,前述的所有全局資源都通過命名空間抽象起來。這使得可以将一組程序放置到容器中,各個容器彼此隔離。隔離可以使容器的成員與其他容器毫無關系。但也可以通過允許容器進行一定的共享,來降低容器之間的分隔。例如,容器可以設定為使用自身的pid集合,但仍然與其他容器共享部分檔案系統。

本質上,命名空間建立了系統的不同視圖。此前的每一項全局資源都必須包裝到容器資料結構中,隻有資源和包含資源的命名空間構成的二進制組仍然是全局唯一的。雖然在給定容器内部資源是自足的,但無法提供在容器外部具有唯一性的id。

考慮系統上有3個不同命名空間的情況。命名空間可以組織為層次,我會在這裡讨論這種情況。一個命名空間是父命名空間,衍生了兩個子命名空間。假定容器用于虛拟主機配置中,其中的每個容器必須看起來像是單獨的一台linux計算機。是以其中每一個都有自身的init程序,pid為0,其他程序的pid 以遞增次序配置設定。兩個子命名空間都有pid為0的init程序,以及pid分别為2和3的兩個程序。由于相同的pid在系統中出現多次,pid号不是全局唯一的。

雖然子容器不了解系統中的其他容器,但父容器知道子命名空間的存在,也可以看到其中執行的所有程序。圖中子容器的程序映射到父容器中,pid為4到 9。盡管系統上有9個程序,但卻需要15個pid來表示,因為一個程序可以關聯到多個pid。至于哪個pid是”正确”的,則依賴于具體的上下文。

如果命名空間包含的是比較簡單的量,也可以是非層次的,例如下文讨論的uts命名空間。在這種情況下,父子命名空間之間沒有聯系。

請注意,linux系統對簡單形式的命名空間的支援已經有很長一段時間了,主要是chroot系統調用。該方法可以将程序限制到檔案系統的某一部分,因而是一種簡單的命名空間機制。但真正的命名空間能夠控制的功能遠遠超過檔案系統視圖。

在linux核心中提供了多個namespace,其中包括fs (mount), uts, network, sysvipc, 等。一個程序可以屬于多個namesapce,既然namespace和程序相關,那麼在task_struct結構體中就會包含和namespace相關聯的變量。在task_struct 結構中有一個指向namespace結構體的指針nsproxy。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

uts命名空間包含了運作核心的名稱、版本、底層體系結構類型等資訊。uts是unix timesharing system的簡稱。

儲存在struct ipc_namespace中的所有與程序間通信(ipc)有關的資訊。

已經裝載的檔案系統的視圖,在struct mnt_namespace中給出。

有關程序id的資訊,由struct pid_namespace提供。

struct net_ns包含所有網絡相關的命名空間參數。

對于.mnt_ns沒有進行初始化,其餘的namespace都進行了系統預設初始

新的命名空間可以用下面兩種方法建立。

在用fork或clone系統調用建立新程序時,有特定的選項可以控制是與父程序共享命名空間,還是建立新的命名空間。

unshare系統調用将程序的某些部分從父程序分離,其中也包括命名空間。更多資訊請參見手冊頁unshare(2)。

在程序已經使用上述的兩種機制之一從父程序命名空間分離後,從該程序的角度來看,改變全局屬性不會傳播到父程序命名空間,而父程序的修改也不會傳播到子進 程,至少對于簡單的量是這樣。而對于檔案系統來說,情況就比較複雜,其中的共享機制非常強大,帶來了大量的可能性。

命名空間的實作需要兩個部分:每個子系統的命名空間結構,将此前所有的全局元件包裝到命名空間中;将給定程序關聯到所屬各個命名空間的機制。

在用fork或clone系統調用建立新程序時,有特定的選項可以控制是與父程序共享命名空間,還是建立新的命名空間。這些選項如下

clone_newpid 程序命名空間。空間内的pid 是獨立配置設定的,意思就是命名空間内的虛拟 pid 可能會與命名空間外的 pid 相沖突,于是命名空間内的 pid 映射到命名空間外時會使用另外一個 pid。比如說,命名空間内第一個 pid 為1,而在命名空間外就是該 pid 已被 init 程序所使用。

clone_newipc 程序間通信(ipc)的命名空間,可以将 systemv 的 ipc 和 posix 的消息隊列獨立出來。

clone_newnet 網絡命名空間,用于隔離網絡資源(/proc/net、ip 位址、網卡、路由等)。背景程序可以運作在不同命名空間内的相同端口上,使用者還可以虛拟出一塊網卡。

clone_newns 挂載命名空間,程序運作時可以将挂載點與系統分離,使用這個功能時,我們可以達到 chroot 的功能,而在安全性方面比 chroot 更高。

clone_newuts uts 命名空間,主要目的是獨立出主機名和網絡資訊服務(nis)。

clone_newuser 使用者命名空間,同程序 id 一樣,使用者 id 群組 id 在命名空間内外是不一樣的,并且在不同命名空間内可以存在相同的 id。

當調用clone時,設定了clone_newpid,就會建立一個新的pid namespace,clone出來的新程序将成為namespace裡的第一個程序。一個pid namespace為程序提供了一個獨立的pid環境,pid namespace内的pid将從1開始,在namespace内調用fork,vfork或clone都将産生一個在該namespace内獨立的pid。新建立的namespace裡的第一個程序在該namespace内的pid将為1,就像一個獨立的系統裡的init程序一樣。該namespace内的孤兒程序都将以該程序為父程序,當該程序被結束時,該namespace内所有的程序都會被結束。pid namespace是層次性,新建立的namespace将會是建立該namespace的程序屬于的namespace的子namespace。子namespace中的程序對于父namespace是可見的,一個程序将擁有不止一個pid,而是在所在的namespace以及所有直系祖先namespace中都将有一個pid。系統啟動時,核心将建立一個預設的pid namespace,該namespace是所有以後建立的namespace的祖先,是以系統所有的程序在該namespace都是可見的。

當調用clone時,設定了clone_newipc,就會建立一個新的ipc namespace,clone出來的程序将成為namespace裡的第一個程序。一個ipc namespace有一組system v ipc objects 辨別符構成,這辨別符有ipc相關的系統調用建立。在一個ipc namespace裡面建立的ipc object對該namespace内的所有程序可見,但是對其他namespace不可見,這樣就使得不同namespace之間的程序不能直接通信,就像是在不同的系統裡一樣。當一個ipc namespace被銷毀,該namespace内的所有ipc object會被核心自動銷毀。

pid namespace和ipc namespace可以組合起來一起使用,隻需在調用clone時,同時指定clone_newpid和clone_newipc,這樣新建立的namespace既是一個獨立的pid空間又是一個獨立的ipc空間。不同namespace的程序彼此不可見,也不能互相通信,這樣就實作了程序間的隔離。

當調用clone時,設定了clone_newns,就會建立一個新的mount namespace。每個程序都存在于一個mount namespace裡面,mount namespace為程序提供了一個檔案層次視圖。如果不設定這個flag,子程序和父程序将共享一個mount namespace,其後子程序調用mount或umount将會影響到所有該namespace内的程序。如果子程序在一個獨立的mount namespace裡面,就可以調用mount或umount建立一份新的檔案層次視圖。該flag配合pivot_root系統調用,可以為程序建立一個獨立的目錄空間。

當調用clone時,設定了clone_newnet,就會建立一個新的network namespace。一個network namespace為程序提供了一個完全獨立的網絡協定棧的視圖。包括網絡裝置接口,ipv4和ipv6協定棧,ip路由表,防火牆規則,sockets等等。一個network namespace提供了一份獨立的網絡環境,就跟一個獨立的系統一樣。一個實體裝置隻能存在于一個network namespace中,可以從一個namespace移動另一個namespace中。虛拟網絡裝置(virtual network device)提供了一種類似管道的抽象,可以在不同的namespace之間建立隧道。利用虛拟化網絡裝置,可以建立到其他namespace中的實體裝置的橋接。當一個network namespace被銷毀時,實體裝置會被自動移回init network namespace,即系統最開始的namespace。

當調用clone時,設定了clone_newuts,就會建立一個新的uts namespace。一個uts namespace就是一組被uname傳回的辨別符。新的uts namespace中的辨別符通過複制調用程序所屬的namespace的辨別符來初始化。clone出來的程序可以通過相關系統調用改變這些辨別符,比如調用sethostname來改變該namespace的hostname。這一改變對該namespace内的所有程序可見。clone_newuts和clone_newnet一起使用,可以虛拟出一個有獨立主機名和網絡空間的環境,就跟網絡上一台獨立的主機一樣。

以上所有clone flag都可以一起使用,為程序提供了一個獨立的運作環境。lxc正是通過clone時設定這些flag,為程序建立一個有獨立pid,ipc,fs,network,uts空間的container。一個container就是一個虛拟的運作環境,對container裡的程序是透明的,它會以為自己是直接在一個系統上運作的。一個container就像傳統虛拟化技術裡面的一台安裝了os的虛拟機,但是開銷更小,部署更為便捷。

linux namespaces機制本身就是為了實作 container based virtualizaiton開發的。它提供了一套輕量級、高效率的系統資源隔離方案,遠比傳統的虛拟化技術開銷小,不過它也不是完美的,它為核心的開發帶來了更多的複雜性,它在隔離性和容錯性上跟傳統的虛拟化技術比也還有差距。

clone_newuser指定子程序擁有新的使用者空間

轉載:http://blog.csdn.net/gatieme/article/details/51383322

繼續閱讀