最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

一文搞懂Docker容器里進(jìn)程的 pid 是如何申請(qǐng)出來的?

2023-02-16 15:45 作者:補(bǔ)給站Linux內(nèi)核  | 我要投稿

如果大家有過在容器中執(zhí)行 ps 命令的經(jīng)驗(yàn),都會(huì)知道在容器中的進(jìn)程的 pid 一般是比較小的。例如下面我的這個(gè)例子。

不知道大家是否和我一樣好奇容器進(jìn)程中的 pid 是如何申請(qǐng)出來的?和宿主機(jī)中申請(qǐng) pid 有什么不同?內(nèi)核又是如何顯示容器中的進(jìn)程號(hào)的?

事實(shí)上進(jìn)程的 pid 命名空間、pid 也都是在這個(gè)過程中申請(qǐng)的。我今天就來帶大家深入理解一下 docker 核心之一 pid 命名空間的工作原理。

一、Linux 的默認(rèn) pid 命名空間

我們提到了進(jìn)程的命名空間成員 nsproxy。

Linux 在啟動(dòng)的時(shí)候會(huì)有一套默認(rèn)的命名空間,定義在 kernel/nsproxy.c 文件下。

其中默認(rèn)的 pid 命名空間是 init_pid_ns,它定義在 kernel/pid.c 下。

在 pid 命名空間里我覺得最需要關(guān)注的是兩個(gè)字段。一個(gè)是 level 表示當(dāng)前 pid 命名空間的層級(jí)。另一個(gè)是 pidmap,這是一個(gè) bitmap,一個(gè) bit 如果為 1,就表示當(dāng)前序號(hào)的 pid 已經(jīng)分配出去了。

另外默認(rèn)命名空間的 level 初始化是 0。這是一個(gè)表示樹的層次結(jié)構(gòu)的節(jié)點(diǎn)。如果有多個(gè)命名空間創(chuàng)建出來,它們之間會(huì)組成一棵樹。level 表示樹在第幾層。根節(jié)點(diǎn)的 level 是 0。

INIT_TASK 0號(hào)進(jìn)程,也叫 idle 進(jìn)程,它固定使用這個(gè)默認(rèn)的 init_nsproxy。

所有進(jìn)程都是一個(gè)派生一個(gè)的方式生成出來的。如果不指定命名空間,所有進(jìn)程使用的都是使用缺省的命名空間。

【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【749907784】整理了一些個(gè)人覺得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦?。。。ê曨l教程、電子書、實(shí)戰(zhàn)項(xiàng)目及代碼)??


二、Linux 新 pid 命名空間創(chuàng)建

在這里,我們假設(shè)我們創(chuàng)建進(jìn)程時(shí)指定了 CLONE_NEWPID 要?jiǎng)?chuàng)建一個(gè)獨(dú)立的 pid 命名空間出來(Docker 容器就是這么干的)。

整個(gè)創(chuàng)建過程的核心是在于 copy_process 函數(shù)。

在這個(gè)函數(shù)中會(huì)申請(qǐng)和拷貝進(jìn)程的地址空間、打開文件列表、文件目錄等關(guān)鍵信息,另外就是pid 命名空間的創(chuàng)建也是在這里完成的?。

2.1 創(chuàng)建進(jìn)程時(shí)構(gòu)造新命名空間

在上面的 copy_process 代碼中我們看到對(duì) copy_namespaces 函數(shù)的調(diào)用。命名空間就是在這個(gè)函數(shù)中操作的。

如果在創(chuàng)建進(jìn)程時(shí)候沒有傳入 CLONE_NEWNS 等幾個(gè) flag,還是會(huì)復(fù)用之前的默認(rèn)命名空間。這幾個(gè) flag 的含義如下。

  • CLONE_NEWPID: 是否創(chuàng)建新的進(jìn)程編號(hào)命名空間,以便與宿主機(jī)的進(jìn)程 PID 進(jìn)行隔離

  • CLONE_NEWNS: 是否創(chuàng)建新的掛載點(diǎn)(文件系統(tǒng))命名空間,以便隔離文件系統(tǒng)和掛載點(diǎn)

  • CLONE_NEWNET: 是否創(chuàng)建新的網(wǎng)絡(luò)命名空間,以便隔離網(wǎng)卡、IP、端口、路由表等網(wǎng)絡(luò)資源

  • CLONE_NEWUTS: 是否創(chuàng)建新的主機(jī)名與域名命名空間,以便在網(wǎng)絡(luò)中獨(dú)立標(biāo)識(shí)自己

  • CLONE_NEWIPC: 是否創(chuàng)建新的 IPC 命名空間,以便隔離信號(hào)量、消息隊(duì)列和共享內(nèi)存

  • CLONE_NEWUSER: 用來隔離用戶和用戶組的。

因?yàn)槲覀儽竟?jié)開頭假設(shè)傳入了 CLONE_NEWPID 標(biāo)記。所以會(huì)進(jìn)入到 create_new_namespaces 中來申請(qǐng)新的命名空間。

create_new_namespaces 中會(huì)調(diào)用 copy_pid_ns 來完成實(shí)際的創(chuàng)建,真正的創(chuàng)建過程是在 create_pid_namespace 中完成的。

在 create_pid_namespace 真正申請(qǐng)了新的 pid 命名空間,為它的 pidmap 申請(qǐng)了內(nèi)存(在 create_pid_cachep 中申請(qǐng)的),也進(jìn)行了初始化。

另外還有一點(diǎn)比較重要的是新命名空間和舊命名空間通過 parent、level 等字段組成了一棵樹。其中 parent 指向了上一級(jí)命名空間,自己的 level 用來表示層次,設(shè)置成了上一級(jí) level + 1。

其最終的效果就是新進(jìn)程擁有了新的 pid namespace,并且這個(gè)新 pid namespace 和父 pidnamespace 串聯(lián)了起來,效果如下圖。

如果 pid 有多層的話,會(huì)組成更直觀的樹形結(jié)構(gòu)。

2.2 申請(qǐng)進(jìn)程id

創(chuàng)建完命名空間后,在 copy_process 中接下來接著就是調(diào)用 alloc_pid 來分配 pid。

注意傳入的參數(shù)是 p->nsproxy->pid_ns。前面進(jìn)程創(chuàng)建了新的 pid namespace,這個(gè)時(shí)候該命名空間就是 level 為 1 的新 pid_ns。我們繼續(xù)來看 alloc_pid 具體 pid 的過程。

在上面的代碼中要注意兩個(gè)細(xì)節(jié)。

  • 我們平時(shí)說的 pid 在內(nèi)核中并不是一個(gè)簡(jiǎn)單的整數(shù)類型,而是一個(gè)小結(jié)構(gòu)體來表示的(struct pid)。

  • 申請(qǐng) pid 并不是申請(qǐng)了一個(gè),而是使用了一個(gè) for 循環(huán)申請(qǐng)多個(gè)出來

之所以要申請(qǐng)多個(gè),是因?yàn)閷?duì)于容器里的進(jìn)程來說,并不是在自己當(dāng)前的命名空間申請(qǐng)就完事了,還要到其父命名空間中也申請(qǐng)一個(gè)。我們把 for 循環(huán)的工作工程用下圖表示一下。

首先到當(dāng)前層次的命名空間申請(qǐng)一個(gè) pid 出來,然后順著命名空間的父節(jié)點(diǎn),每一層也都要申請(qǐng)一個(gè),并都記錄到 pid->numbers 數(shù)組中。

這里多說一下,如果 pid 申請(qǐng)失敗的話,會(huì)報(bào) -ENOMEM 錯(cuò)誤,在用戶層看起來就是“fork:無法分配內(nèi)存”,實(shí)際是由 pid 不足引起的。

2.3 設(shè)置整數(shù)格式 pid

當(dāng)申請(qǐng)并構(gòu)造完 pid 后,將其設(shè)置在 task_struct 上,記錄起來。

其中 pid_nr 是獲取的根 pid 命名空間下的 pid 編號(hào),參見 pid_nr 源碼。

然后再調(diào)用 attach_pid 是把申請(qǐng)到的 pid 結(jié)構(gòu)掛到自己的 pids[PIDTYPE_PID] 鏈表里了。

三、容器進(jìn)程 pid 查看

pid 已經(jīng)申請(qǐng)好了,那在容器中是如何查看當(dāng)前層次的進(jìn)程號(hào)的呢?比如我們?cè)谌萜髦锌吹降?demo-ie 進(jìn)程的 id 就是 1。

內(nèi)核提供了個(gè)函數(shù)用來查看進(jìn)程在當(dāng)前某個(gè)命名空間的命名號(hào)。

其中在容器中查看進(jìn)程 pid 使用的是 pid_vnr,pid_vnr 調(diào)用 pid_nr_ns 來查看進(jìn)程在特定命名空間里的進(jìn)程號(hào)。

函數(shù) pid_nr_ns 接收連個(gè)參數(shù)

  • 第一個(gè)參數(shù)是進(jìn)程里記錄的 pid 對(duì)象(保存有在各個(gè)層次申請(qǐng)到的 pid 號(hào))

  • 第二個(gè)參數(shù)是指定的 pid 命名空間(通過 task_active_pid_ns(current)獲取)。

當(dāng)具備這兩個(gè)參數(shù)后,就可以根據(jù) pid 命名空間里記錄的層次 level 取得容器進(jìn)程的當(dāng)前 pid 了

在 pid_nr_ns 中通過判斷 level 就把容器 pid 整數(shù)值查出來了。

四、總結(jié)

最后,舉個(gè)例子,假如有一個(gè)進(jìn)程在 level 0 級(jí)別的 pid 命名空間里申請(qǐng)到的進(jìn)程號(hào)是 1256,在 level 1 容器 pid 命名空間里申請(qǐng)到的進(jìn)程號(hào)是 5。那么這個(gè)進(jìn)程以及其 pid 在內(nèi)存中的形式是下圖這個(gè)樣子的。

那么容器在查看進(jìn)程的 pid 號(hào)的時(shí)候,傳入容器的 pid 命名空間,就可以將該進(jìn)程在容器中的 pid 號(hào) 5 給打印出來了!!

原文作者:開發(fā)內(nèi)功修煉



一文搞懂Docker容器里進(jìn)程的 pid 是如何申請(qǐng)出來的?的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國家法律
福建省| 怀安县| 筠连县| 京山县| 阿拉善盟| 西华县| 北碚区| 万全县| 鄂州市| 合江县| 海伦市| 兴安县| 桃园市| 社会| 翼城县| 吴堡县| 翁牛特旗| 镇安县| 修文县| 霸州市| 安陆市| 彭水| 台前县| 名山县| 阜新市| 西乌| 新平| 青铜峡市| 阿克陶县| 垣曲县| 元氏县| 开平市| 泉州市| 大新县| 元朗区| 丹凤县| 周至县| 天津市| 商洛市| 嘉定区| 广丰县|