久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Docker背后的內(nèi)核知識(shí):命名空間資源隔離

 gljin_cn 2015-03-17

Docker這么火,,喜歡技術(shù)的朋友可能也會(huì)想,如果要自己實(shí)現(xiàn)一個(gè)資源隔離的容器,,應(yīng)該從哪些方面下手呢,?也許你第一反應(yīng)可能就是chroot命令,這條命令給用戶最直觀的感覺(jué)就是使用后根目錄/的掛載點(diǎn)切換了,,即文件系統(tǒng)被隔離了,。然后,,為了在分布式的環(huán)境下進(jìn)行通信和定位,容器必然需要一個(gè)獨(dú)立的IP,、端口,、路由等等,自然就想到了網(wǎng)絡(luò)的隔離,。同時(shí),,你的容器還需要一個(gè)獨(dú)立的主機(jī)名以便在網(wǎng)絡(luò)中標(biāo)識(shí)自己。想到網(wǎng)絡(luò),,順其自然就想到通信,,也就想到了進(jìn)程間通信的隔離??赡苣阋蚕氲搅藱?quán)限的問(wèn)題,,對(duì)用戶和用戶組的隔離就實(shí)現(xiàn)了用戶權(quán)限的隔離。最后,,運(yùn)行在容器中的應(yīng)用需要有自己的PID,自然也需要與宿主機(jī)中的PID進(jìn)行隔離。

由此,,我們基本上完成了一個(gè)容器所需要做的六項(xiàng)隔離,,Linux內(nèi)核中就提供了這六種命名空間(namespace)隔離的系統(tǒng)調(diào)用,如下表所示,。

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

用戶和用戶組

表 namespace六項(xiàng)隔離

實(shí)際上,,Linux內(nèi)核實(shí)現(xiàn)namespace的主要目的就是為了實(shí)現(xiàn)輕量級(jí)虛擬化(容器)服務(wù)。在同一個(gè)namespace下的進(jìn)程可以感知彼此的變化,,而對(duì)外界的進(jìn)程一無(wú)所知,。這樣就可以讓容器中的進(jìn)程產(chǎn)生錯(cuò)覺(jué),仿佛自己置身于一個(gè)獨(dú)立的系統(tǒng)環(huán)境中,,以此達(dá)到獨(dú)立和隔離的目的,。

需要說(shuō)明的是,本文所討論的namespace實(shí)現(xiàn)針對(duì)的均是Linux內(nèi)核3.8及其以后的版本,。接下來(lái),,我們將首先介紹使用namespace的API,然后針對(duì)這六種namespace進(jìn)行逐一講解,,并通過(guò)程序讓你親身感受一下這些隔離效果{![參考自http:///Articles/531114/]},。

1. 調(diào)用namespace的API

namespace的API包括clone()、setns()以及unshare(),,還有/proc下的部分文件,。為了確定隔離的到底是哪種namespace,,在使用這些API時(shí),通常需要指定以下六個(gè)常數(shù)的一個(gè)或多個(gè),,通過(guò)|(位或)操作來(lái)實(shí)現(xiàn),。你可能已經(jīng)在上面的表格中注意到,這六個(gè)參數(shù)分別是CLONE_NEWIPC,、CLONE_NEWNS,、CLONE_NEWNET、CLONE_NEWPID,、CLONE_NEWUSER和CLONE_NEWUTS,。

(1)通過(guò)clone()創(chuàng)建新進(jìn)程的同時(shí)創(chuàng)建namespace

使用clone()來(lái)創(chuàng)建一個(gè)獨(dú)立namespace的進(jìn)程是最常見(jiàn)做法,它的調(diào)用方式如下,。

  1. int clone(int (*child_func)(void *), void *child_stack, int flags, void *arg);

clone()實(shí)際上是傳統(tǒng)UNIX系統(tǒng)調(diào)用fork()的一種更通用的實(shí)現(xiàn)方式,,它可以通過(guò)flags來(lái)控制使用多少功能。一共有二十多種CLONE_*的flag(標(biāo)志位)參數(shù)用來(lái)控制clone進(jìn)程的方方面面(如是否與父進(jìn)程共享虛擬內(nèi)存等等),,下面外面逐一講解clone函數(shù)傳入的參數(shù),。

  • 參數(shù)child_func傳入子進(jìn)程運(yùn)行的程序主函數(shù)。
  • 參數(shù)child_stack傳入子進(jìn)程使用的??臻g
  • 參數(shù)flags表示使用哪些CLONE_*標(biāo)志位
  • 參數(shù)args則可用于傳入用戶參數(shù)

在后續(xù)的內(nèi)容中將會(huì)有使用clone()的實(shí)際程序可供大家參考,。

(2)查看/proc/[pid]/ns文件

從3.8版本的內(nèi)核開(kāi)始,用戶就可以在/proc/[pid]/ns文件下看到指向不同namespace號(hào)的文件,,效果如下所示,,形如[4026531839]者即為namespace號(hào)。

  1. $ ls -l /proc/$$/ns <<-- $$ 表示應(yīng)用的PID
  2. total 0
  3. lrwxrwxrwx. 1 mtk mtk 0 Jan 8 04:12 ipc -> ipc:[4026531839]
  4. lrwxrwxrwx. 1 mtk mtk 0 Jan 8 04:12 mnt -> mnt:[4026531840]
  5. lrwxrwxrwx. 1 mtk mtk 0 Jan 8 04:12 net -> net:[4026531956]
  6. lrwxrwxrwx. 1 mtk mtk 0 Jan 8 04:12 pid -> pid:[4026531836]
  7. lrwxrwxrwx. 1 mtk mtk 0 Jan 8 04:12 user->user:[4026531837]
  8. lrwxrwxrwx. 1 mtk mtk 0 Jan 8 04:12 uts -> uts:[4026531838]

如果兩個(gè)進(jìn)程指向的namespace編號(hào)相同,,就說(shuō)明他們?cè)谕粋€(gè)namespace下,,否則則在不同namespace里面。/proc/[pid]/ns的另外一個(gè)作用是,,一旦文件被打開(kāi),,只要打開(kāi)的文件描述符(fd)存在,那么就算PID所屬的所有進(jìn)程都已經(jīng)結(jié)束,,創(chuàng)建的namespace就會(huì)一直存在,。那如何打開(kāi)文件描述符呢?把/proc/[pid]/ns目錄掛載起來(lái)就可以達(dá)到這個(gè)效果,,命令如下,。

  1. # touch ~/uts
  2. # mount --bind /proc/27514/ns/uts ~/uts

如果你看到的內(nèi)容與本文所描述的不符,那么說(shuō)明你使用的內(nèi)核在3.8版本以前,。該目錄下存在的只有ipc,、net和uts,并且以硬鏈接存在,。

(3)通過(guò)setns()加入一個(gè)已經(jīng)存在的namespace

上文剛提到,,在進(jìn)程都結(jié)束的情況下,,也可以通過(guò)掛載的形式把namespace保留下來(lái),保留namespace的目的自然是為以后有進(jìn)程加入做準(zhǔn)備,。通過(guò)setns()系統(tǒng)調(diào)用,,你的進(jìn)程從原先的namespace加入我們準(zhǔn)備好的新namespace,使用方法如下,。

  1. int setns(int fd, int nstype);
  • 參數(shù)fd表示我們要加入的namespace的文件描述符,。上文已經(jīng)提到,它是一個(gè)指向/proc/[pid]/ns目錄的文件描述符,,可以通過(guò)直接打開(kāi)該目錄下的鏈接或者打開(kāi)一個(gè)掛載了該目錄下鏈接的文件得到,。
  • 參數(shù)nstype讓調(diào)用者可以去檢查fd指向的namespace類型是否符合我們實(shí)際的要求。如果填0表示不檢查,。

為了把我們創(chuàng)建的namespace利用起來(lái),,我們需要引入execve()系列函數(shù),這個(gè)函數(shù)可以執(zhí)行用戶命令,,最常用的就是調(diào)用/bin/bash并接受參數(shù),,運(yùn)行起一個(gè)shell,用法如下,。

  1. fd = open(argv[1], O_RDONLY); /* 獲取namespace文件描述符 */
  2. setns(fd, 0); /* 加入新的namespace */
  3. execvp(argv[2], &argv[2]); /* 執(zhí)行程序 */

假設(shè)編譯后的程序名稱為setns,。

  1. # ./setns ~/uts /bin/bash # ~/uts 是綁定的/proc/27514/ns/uts

至此,你就可以在新的命名空間中執(zhí)行shell命令了,,在下文中會(huì)多次使用這種方式來(lái)演示隔離的效果。

(4)通過(guò)unshare()在原先進(jìn)程上進(jìn)行namespace隔離

最后要提的系統(tǒng)調(diào)用是unshare(),,它跟clone()很像,,不同的是,unshare()運(yùn)行在原先的進(jìn)程上,,不需要啟動(dòng)一個(gè)新進(jìn)程,,使用方法如下。

  1. int unshare(int flags);

調(diào)用unshare()的主要作用就是不啟動(dòng)一個(gè)新進(jìn)程就可以起到隔離的效果,,相當(dāng)于跳出原先的namespace進(jìn)行操作,。這樣,你就可以在原進(jìn)程進(jìn)行一些需要隔離的操作,。Linux中自帶的unshare命令,,就是通過(guò)unshare()系統(tǒng)調(diào)用實(shí)現(xiàn)的,有興趣的讀者可以在網(wǎng)上搜索一下這個(gè)命令的作用,。

(5)延伸閱讀:fork()系統(tǒng)調(diào)用

系統(tǒng)調(diào)用函數(shù)fork()并不屬于namespace的API,,所以這部分內(nèi)容屬于延伸閱讀,如果讀者已經(jīng)對(duì)fork()有足夠的了解,,那大可跳過(guò),。

當(dāng)程序調(diào)用fork()函數(shù)時(shí),,系統(tǒng)會(huì)創(chuàng)建新的進(jìn)程,為其分配資源,,例如存儲(chǔ)數(shù)據(jù)和代碼的空間,。然后把原來(lái)的進(jìn)程的所有值都復(fù)制到新的進(jìn)程中,只有少量數(shù)值與原來(lái)的進(jìn)程值不同,,相當(dāng)于克隆了一個(gè)自己,。那么程序的后續(xù)代碼邏輯要如何區(qū)分自己是新進(jìn)程還是父進(jìn)程呢?

fork()的神奇之處在于它僅僅被調(diào)用一次,,卻能夠返回兩次(父進(jìn)程與子進(jìn)程各返回一次),,通過(guò)返回值的不同就可以進(jìn)行區(qū)分父進(jìn)程與子進(jìn)程。它可能有三種不同的返回值:

  • 在父進(jìn)程中,,fork返回新創(chuàng)建子進(jìn)程的進(jìn)程ID
  • 在子進(jìn)程中,,fork返回0
  • 如果出現(xiàn)錯(cuò)誤,fork返回一個(gè)負(fù)值

下面給出一段實(shí)例代碼,,命名為fork_example.c,。

  1. #include <unistd.h>
  2. #include <stdio.h>
  3. int main (){
  4. pid_t fpid; //fpid表示fork函數(shù)返回的值
  5. int count=0;
  6. fpid=fork();
  7. if (fpid < 0)printf("error in fork!");
  8. else if (fpid == 0) {
  9. printf("I am child. Process id is %d/n",getpid());
  10. }
  11. else {
  12. printf("i am parent. Process id is %d/n",getpid());
  13. }
  14. return 0;
  15. }

編譯并執(zhí)行,結(jié)果如下,。

  1. root@local:~# gcc -Wall fork_example.c && ./a.out
  2. I am parent. Process id is 28365
  3. I am child. Process id is 28366

使用fork()后,,父進(jìn)程有義務(wù)監(jiān)控子進(jìn)程的運(yùn)行狀態(tài),并在子進(jìn)程退出后自己才能正常退出,,否則子進(jìn)程就會(huì)成為“孤兒”進(jìn)程,。

下面我們將分別對(duì)六種namespace進(jìn)行詳細(xì)解析。

 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多