Docker內(nèi)核技術(shù)原理之Namespace
Docker的空間隔離使用的是namespace(空間),它是內(nèi)核提供的一種空間隔離,在一個(gè)空間下,每個(gè)進(jìn)程看到的視圖是一致的,相應(yīng)的如果不在一個(gè)空間下看到資源視圖是不一致的,舉個(gè)例子,如果兩個(gè)進(jìn)程在同一個(gè)網(wǎng)絡(luò)命令空間下,那么他們看到的網(wǎng)絡(luò)信息(網(wǎng)卡、IP、路由等)是一樣的,可以通過(guò)localhost的方式互相訪問(wèn)。常用的有6種namespace,在Linux 內(nèi)核4.6之后又添加了Cgroup這namespace,5.6 之后又添加了時(shí)鐘namespace。
Namespace |
系統(tǒng)調(diào)用參數(shù) |
隔離內(nèi)容 |
UTS |
CLONE_NEWUTS |
主機(jī)名與域名 |
IPC |
CLONE_NEWIPC |
信號(hào)量、消息隊(duì)列和共享內(nèi)存 |
PID |
CLONE_NEWPID |
進(jìn)程編號(hào) |
Network |
CLONE_NEWNET |
網(wǎng)絡(luò)設(shè)備、網(wǎng)絡(luò)棧、端口等等 |
Mount |
CLONE_NEWNS |
掛載點(diǎn)(文件系統(tǒng)) |
User |
CLONE_NEWUSER |
用戶和用戶組 |
Cgroup |
CLONE_NEWCGROUP |
Cgroup的根目錄 |
Time |
CLONE_NEWTIME |
時(shí)鐘 |
這里有個(gè)小細(xì)節(jié),上面表格創(chuàng)建Mount Namespace的系統(tǒng)調(diào)用參數(shù)是CLONE_NEWNS,而不是CLONE_NEWMOUNT。從字面理解是創(chuàng)建一個(gè)命名空間的意思,這是由于歷史原因?qū)е碌模驗(yàn)镸ount Namespace是第一個(gè)namespace,內(nèi)核的開(kāi)發(fā)者可能也沒(méi)有預(yù)料到后續(xù)還有其它的namespace的加入,所以就先把CLONE_NEWNS給占用了。
可見(jiàn),namespace的隔離其實(shí)并不充分,除了上面的隔離能力,其他的都一樣。譬如,時(shí)鐘在內(nèi)核5.6版本之前,所有容器和操作系統(tǒng)都共享同一個(gè)時(shí)鐘,如果修改了操作系統(tǒng)的時(shí)間,所有容器都時(shí)間都會(huì)變化。
namespace實(shí)現(xiàn)原理也非常簡(jiǎn)單,每個(gè)進(jìn)程(task_struct)都有一個(gè)關(guān)于namespace的屬性nsproxy,表示自己所屬的namespace。
struct task_struct { ...
/* namespaces */
struct nsproxy *nsproxy;
...
}
其中的nsproxy就是指向各種namespace的一個(gè)代理。如下所示:
當(dāng)新進(jìn)程被創(chuàng)建后會(huì)繼承其父進(jìn)程的namespace,這就是為啥一個(gè)容器里面的所有進(jìn)程都共享namespace。在Linux集群上面,通過(guò)讀取“/proc/進(jìn)程ID/ns/”下的文件可以獲取到每個(gè)進(jìn)程對(duì)應(yīng)的namespace。