久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

docker源碼分析Libcontainer

154次閱讀
沒有評論

共計 7544 個字符,預(yù)計需要花費 19 分鐘才能閱讀完成。

這篇文章主要講解了“docker 源碼分析 Libcontainer”,文中的講解內(nèi)容簡單清晰,易于學習與理解,下面請大家跟著丸趣 TV 小編的思路慢慢深入,一起來研究和學習“docker 源碼分析 Libcontainer”吧!

1. Libcontainer 簡介 1.1 linux container 相關(guān)技術(shù)

要了解 Libcontainer 首先要了解 linux container 所用到的一些基本技術(shù)。linux container 是一種內(nèi)核虛擬化技術(shù),可以提供輕量級的虛擬化,以便隔離進程和資源。而這正是 docker 容器技術(shù)和核心,docker 正是 linux container 的一種實現(xiàn)。linux container 所用到的基本技術(shù)包括 namespace、cgroup、chroot、veth、union FS、iptables 和 netfilter、TC、quota、setrlimit, 下面對這些基本技術(shù)做一個簡要的概括:

1. Namespace:用來做資源隔離以實現(xiàn)輕量級虛擬化,包括六種 namespace,UTS namespace 提供了主機名和域名之間的隔離;IPC namespace 提供了進程間通信的隔離;Network namespace 提供了網(wǎng)絡(luò)的隔離包括網(wǎng)絡(luò)設(shè)備、網(wǎng)絡(luò)棧、端口等;Mount namespace 提供了文件系統(tǒng)的隔離;User namespace 提供了用戶權(quán)限間的隔離。

2. Cgroups:實現(xiàn)資源限制,可以限制、記錄任務(wù)組所使用的物理資源。還可用于優(yōu)先級分配,通過分配的 CPU 時間片數(shù)量及磁盤 IO 寬帶大小控制任務(wù)運行的優(yōu)先級。用于資源統(tǒng)計,統(tǒng)計系統(tǒng)的資源使用量,如 CPU 使用時長、內(nèi)存用量等。用于任務(wù)控制,可以對任務(wù)執(zhí)行掛起、控制等操作。

3. Chroot:更改 root 目錄,用于在 container 里查看到的文件系統(tǒng)。他有三大優(yōu)點:增加系統(tǒng)的安全性,限制了用戶的權(quán)利;建立一個與原系統(tǒng)隔離的系統(tǒng)目錄,這一點對容器極為重要;切換系統(tǒng)的根目錄位置。

4. Veth:把一個從網(wǎng)絡(luò)用戶空間(network namespace)發(fā)出的數(shù)據(jù)包轉(zhuǎn)發(fā)到另一個用戶空間。即實現(xiàn)容器和宿主機之間的通信。

5. Union FS:疊加的文件系統(tǒng),其中包括 aufs 一種支持聯(lián)合掛載的文件系統(tǒng)。

6. Iptables,netfilter:主要用來做 ip 數(shù)據(jù)包的過濾。

7. TC:主要用來做流量隔離,帶寬的限制。

8. Quota:用來做磁盤讀寫大小的限制,用來限制用戶可用空間的大小。

9. Setrlimit:可以限制 container 中打開的進程數(shù),限制打開的文件個數(shù)等。

1.2 Libcontainer 簡介

  基于上文對 linux container 相關(guān)技術(shù),docker 基本是實現(xiàn)了前五個的技術(shù),用 libcontainer 做了一層封裝。也就是說 docker 通過 libcontainer 封裝了 linux container 的部分技術(shù),這樣使得 Docker 具有持續(xù)部署與測試、跨云平臺支持、環(huán)境標準化和版本控制、高資源利用率與隔離、容器跨平臺性與鏡像、易于理解且易用以及具有應(yīng)用鏡像倉庫等優(yōu)點。Libcontainer 本質(zhì)上是 Docker 中用于容器管理的包,基于 Go 語言實現(xiàn),通過管理 namespace、Cgroups、capabilities 以及文件系統(tǒng)等來進行容器控制。Libcontainer 可用于創(chuàng)建容器并對容器進行生命周期管理。提到 Libcontainer 就要提到 execdriver,execdriver 封裝了對 namespace、cgroups 等對 OS 資源進行操作的所有方法,而 Libcontainer 是 execdriver 的默認實現(xiàn)。execdriver 通過得到的 command 信息加載生成容器配置 container,然后調(diào)用 libcontainer 加載容器配置 container,創(chuàng)建真正的 docker 容器,完成容器的創(chuàng)建并對容器的生命周期進行管理。

2. execdriver 工作流程

  Execdriver 的工作流程如圖 2.1 所示:

圖 2.1 execdriver 的工作流程

2.1 配置信息簡介

Execdriver 首先得到 Docker daemon 提交的 command 信息,提交過來的 command 信息包含 namespace、cgroup 等配置容器所需的重要信息。相對應(yīng)的 command 結(jié)構(gòu)體源碼如圖 2.2,其中包含了生成容器所需的基本配置,有 namespace 相關(guān)比如 UTS 可提主機名和域名之間的隔離;IPC 提供了進程間通信的隔離;Network 提供了網(wǎng)絡(luò)的隔離包括網(wǎng)絡(luò)設(shè)備、網(wǎng)絡(luò)棧、端口等;Mount 提供了文件系統(tǒng)的隔離。Resource 包含了 cgroup 相關(guān)的信息,ProcessConfig 表示容器中運行的進程的信息。

對圖 2.2 中的部分參數(shù)做簡要解釋,其中:ContainerPid 表示容器中進程的 pid;ID 是容器 ID,代表容器的唯一標識,非常重要;Mount 是 namespace 的一種用于文件系統(tǒng)的隔離;Network 也是 namespace 的一種用于進行網(wǎng)絡(luò)的隔離;ProcessConfig 描述了容器中運行的進程的信息;Resource 提供了 cgroup 相關(guān)的信息,后面會對 Resource 結(jié)構(gòu)體展開做詳細的分析;Rootfs 是容器的根目錄系統(tǒng);WorkingDir 顧名思義是容器的工作路徑;TmpDir 是用來存儲 docker 臨時文件的目錄;

圖 2.2 command 結(jié)構(gòu)體

Cgroups 用于實現(xiàn)資源限制,可以限制、記錄任務(wù)組所使用的物理資源。cgroups 相關(guān)信息包含在 resource 里,resource 包含了對 driver 配置的所有資源的信息,resource 結(jié)構(gòu)體相關(guān)定義如圖 2.3,其中:memory 表示所使用的存儲容量,還定義了 CPU 用量等 cgroup 所需的信息。

圖 2.3 resource 結(jié)構(gòu)體

  ProcessConfig 中包含了表示容器中運行的進程的信息,ProcessConfig 結(jié)構(gòu)體相關(guān)定義源碼如圖 2.4,

圖 2.4ProcessConfig 結(jié)構(gòu)體

2.2 主要流程分析

  圖 2.1 中所示的工作流程相對應(yīng)的源碼在 deamon/execdriver/native/driver.go 的 run 函數(shù)中,run 函數(shù)部分截圖如圖 2.5 所示,其中 container, err := d.createContainer(c, hooks) 語句的作用是調(diào)用 createContainer 函數(shù)創(chuàng)建容器配置。函數(shù)傳入的參數(shù) c 表示 execdriver.Command,即上文提到的 command 結(jié)構(gòu)體,也就是說 createContainer 函數(shù)根據(jù) command 參數(shù)創(chuàng)建相關(guān)的容器配置。

圖 2.5 Run 函數(shù)部分函數(shù)體

  上文說到 createContainer 函數(shù)根據(jù) command 參數(shù)創(chuàng)建相關(guān)的容器配置,下面我們看一下 createContainer 函數(shù)的內(nèi)部結(jié)構(gòu),如圖 2.6 為 createContainer 函數(shù)的部分結(jié)構(gòu)。其中 container = execdriver.InitContainer(c) 可以看到調(diào)用 InitContainer 函數(shù)通過傳入的 execdriver.Command 參數(shù)生成容器配置 container。其中一系列的 createXXX() 方法根據(jù) InitContainer 函數(shù)得到的 container 填充模板,配置 IPC、Pid、network 等所需字段。其中 createIpc() 表示配置 Ipc 提供提供了進程間通信的隔離;createPid() 表示配置 Pid;createUTS() 表示配置 UTS 提供主機名和域名之間的隔離;createNetwork() 配置 Network 提供了網(wǎng)絡(luò)的隔離包括網(wǎng)絡(luò)設(shè)備、網(wǎng)絡(luò)棧、端口等。

圖 2.6 createContainer 函數(shù)的部分函數(shù)體

  由 createContainer 函數(shù)的源碼的內(nèi)部結(jié)構(gòu)可以看到在 createContainer 函數(shù)中首先調(diào)用 InitContainer 函數(shù)生成了一個叫做 container 的變量,InitContainer 函數(shù)通過傳入的 execdriver.Command 參數(shù)生成容器配置 container,如圖 2.7 是 execdriver.InitContainer 函數(shù)的內(nèi)部結(jié)構(gòu)。在 InitContainer 函數(shù)中根據(jù) command 配置 container 的 hostname 主機名、cgroup、devices、rootfs 等信息,最后返回一個容器配置 container,這時候的返回的 container 其實是一個 Config 對象,表示容器配置。后面再由 createContainer 函數(shù)中的 createXXX() 方法根據(jù) InitContainer 函數(shù)返回的 container 容器配置,配置相應(yīng) IPC、Pid、network 等所需字段。

圖 2.7 InitContainer 函數(shù)的部分函數(shù)體

  至此我們已經(jīng)分析完了 deamon/execdriver/native/driver.go 的 run 函數(shù)中 container, err := d.createContainer(c, hooks) 語句,簡單的說該語句的結(jié)果就是生成了一份 container 容器配置。接下來在 run 函數(shù)中 execdriver 調(diào)用 libcontainer 加載已經(jīng)生成好的容器配置 container,創(chuàng)建真正的 Docker 容器。

3. Libcontainer 實現(xiàn)原理

  在 deamon/execdriver/native/driver.go 的 run 函數(shù)中,成功生成 container 容器配置以后,工作就交由 libcontainer。libcontainer 的主要工作為:

1. 創(chuàng)建 libcontainer 構(gòu)建容器所需要使用的進程對象,即 Process。對應(yīng)源碼如圖 3.1 所示。Process 指定了容器內(nèi)進程對象的配置和 IO,其中有指定若干參數(shù),并對參數(shù)賦值。Args 表示將要運行的一系列指令;Env 指定該進程對象的環(huán)境變量;Cwd 將進程的工作目錄改至容器的 rootfs 中;User 將為容器中的正在運行的進程設(shè)置 UID 和 GID。

docker 源碼分析 Libcontainer

圖 3.1 構(gòu)建 Process

2. 接下來在 run 函數(shù)中 err := setupPipes(container, c.ProcessConfig, p, pipes); 語句調(diào)用 setupPipes 函數(shù)設(shè)置容器的輸出管道。而 setupPipes 函數(shù)即為設(shè)置容器輸出管道函數(shù),其函數(shù)體定義在 deamon/execdriver/native/driver.go 的 setupPipes 函數(shù)中。setupPipes 函數(shù)主要通過 execdriver.Pipes 配置容器的輸出管道,其主要作用是將容器的輸出成標準輸入、標準輸出和標準錯誤。

3. 使用 Factory 工廠類,用容器 ID 和容器配置 container 創(chuàng)建邏輯容器 Container,在 run 函數(shù)中對應(yīng)的源碼為:d.factory.Create(c.ID, container),其中 c 為 execdriver.Command,c.ID 為容器 ID,container 即為之前多次提到的容器配置。在生成邏輯容器的過程中,容器配置 container 的各項會填充到邏輯容器 Container 對像的配置項 config 里。

4. 接下來用啟動容器,啟動容器對應(yīng)的語句為 cont.Start(p),其中 cont 為 d.factory.Create(c.ID, container) 函數(shù)生成的 Container 邏輯容器,而參數(shù) p 為之前生成的容器所需要使用的進程對象 Process。

5. 下面的代碼 p.Wait() 即為 process.Wait(),表示等待之前 Process 的所有工作都完成,直到物理容器創(chuàng)建成功。Processd 的 Wait 函數(shù)所對應(yīng)的源碼為圖 3.2 所示。

docker 源碼分析 Libcontainer

圖 3.2 Process 的 Wait() 函數(shù)

6. 最后的 cont.Destroy() 表示 Container.Destory(),即在需要的情況下可以銷毀容器。

通過上述對 libcontainer 主要工作分析,我們發(fā)現(xiàn) libcontainer 的重點正是 Process、Container、Factory 這 3 個邏輯實體的實現(xiàn)。其中 Factory 用于創(chuàng)建一個邏輯上的容器對象;Container 是包含容器配置信息的邏輯容器;Process 用于物理容器中進程的配置和 IO 管理。下面我們 libcontainer 中這三個邏輯實體進行詳細的解析。

3.1 Factory 創(chuàng)建邏輯容器

  Factory 的作用是用給定的容器 ID 創(chuàng)建一個新的容器,并在該容器中啟動初始進程。并且接受的容器 ID 為只包含字母、數(shù)字、下劃線組成的字符創(chuàng),且長度必須在 1 到 1024 之間。容器 ID 不能與已經(jīng)存在的容器的 ID 重合,使用同一路徑(和文件系統(tǒng))的 Factory 創(chuàng)建的容器必須有不同的標識。最后用一個正在運行的進程返回一個新的容器。

  在這個過程中可能出現(xiàn)的錯誤有:IdInUse 表示容器 ID 已經(jīng)被其他容器占用;InvalidIdFormat 表示容器 ID 的格式不正確;ConfigInvalid 表示配置信息無用;Systemerror 表示系統(tǒng)錯誤。一但發(fā)生錯誤,那么任何已經(jīng)創(chuàng)建的容器部分都會被清除,保證了容器創(chuàng)建的原子性,要不全部創(chuàng)建成功,否則全部不創(chuàng)建。

  Factory 對象中包含三個函數(shù),他們分別為:

  1. Create() 函數(shù):其傳入?yún)?shù)為一個容器 ID 和一份 Config 類型的配置參數(shù),并且接受的容器 ID 為只包含字母、數(shù)字、下劃線組成的字符創(chuàng),且長度必須在 1 到 1024 之間。容器 ID 不能與已經(jīng)存在的容器的 ID 重合,使用同一路徑(和文件系統(tǒng))的 Factory 創(chuàng)建的容器必須有不同的標識。根據(jù)傳入的這兩個參數(shù)創(chuàng)建并返回一個 Container 類,其中包括容器 ID、容器工作目錄、容器配置、初始化指令和參數(shù)、以及 Cgroup 管理器等信息。在這個函數(shù)中 Container 創(chuàng)建完畢。其中可能出現(xiàn)路徑不存在、容器已經(jīng)停止、系統(tǒng)故障等錯誤。

  2. Load() 函數(shù):傳入?yún)?shù)為一個已經(jīng)被成功 Create 過的容器的容器 ID,返回該容器的信息。如果容器已經(jīng) Create 過說明存在 id 目錄,則會從 id 目錄下直接讀取 state.json 來載入容器信息。其中可能出現(xiàn)的錯誤有管道連接錯誤和系統(tǒng)故障。

  3. StartInitialization() 函數(shù):是容器初始化函數(shù),是 Libcontainer 在容器重新執(zhí)行期間會調(diào)用的內(nèi)部 API。

  4. Type() 函數(shù):返回容器管理的類型,比如 lxc 或 libcontainer 等。

  至此,F(xiàn)actory 對象完成了容器的創(chuàng)建和初始化。接下來就了解一下包含包含容器配置信息的邏輯容器 Container。

3.2 邏輯容器 Container

  Container 對象相當于是邏輯容器主要包含了容器配置、控制、狀態(tài)顯示等功能。其中 ID 表示容器的 ID。Status 表示容器內(nèi)進程的狀態(tài),容器的狀態(tài)包括:Running 表示容器存在并且正在運行;Pausing 表示容器存在并且進程正在被停止;Paused 表示容器存在但是所有的進程都被停止了;Checkpointed 表示容器存在并且容器狀態(tài)都已保存至磁盤;Destoryed 表示容器不存在。

  Container 對象中具有一系列容器相關(guān)的函數(shù)操作,其中包括:

  ID():返回容器的 ID,代表容器的唯一標識

  Status():返回容器內(nèi)進程的狀態(tài),可能為運行狀態(tài)也可能是停止狀態(tài)。可能拋出的錯誤為 ContainerDestroyed 表示容器不存在已經(jīng)被銷毀;Systemerror 表示系統(tǒng)錯誤。

  State():返回容器的狀態(tài)信息,包括容器 ID、配置信息、初始進程 ID、進程啟動時間、cgroup 文件路徑、namespace 路徑等。可能出現(xiàn)的錯誤為 Systemerror 即系統(tǒng)錯誤。

  Config():返回容器的配置信息

  Processes():返回容器的 PID,這個 PID 即為用來調(diào)用進程的 namespace。有些 PID 可能不在與容器中的進程相關(guān),除非容器的狀態(tài)是 PAUSED,這樣才能保證每一個 PID 都是有效的。

  Stats():返回容器統(tǒng)計信息,包括 cgroup 中的統(tǒng)計以及網(wǎng)卡設(shè)備的統(tǒng)計信息。

  Set():設(shè)置容器的資源配置,例如 cgroup 各個子系統(tǒng)的文件路徑等。

  Start():在容器內(nèi)啟動一個進程,如果進程啟動失敗就返回一個錯誤。可以根據(jù)以往的 Process 結(jié)構(gòu)追蹤進程的生命周期。其中主要工作有兩個:創(chuàng)建 ParentProcess 實例,執(zhí)行 ParentProcess.start() 來啟動物理容器。ParentProcess 是一個接口其具體實現(xiàn)為 initProcess 對象,initProcess 用于創(chuàng)建容器所需的 ParentProcess,為創(chuàng)建物理容器做準備。用邏輯容器 Container 執(zhí)行 initProcess.start(),真正的物理容器即 Docker 容器就生成了。

  Destory():在結(jié)束所有的正在運行的進程以后銷毀容器。

3.3  Process 對象

  Process 分為兩類,一類是 Process 另外一類是 ParentProcess。Process 用于容器內(nèi)進程的配置和 IO 的管理,其參數(shù)包括:Args 表示將要運行的一系列指令;Env 指定該進程對象的環(huán)境變量;Cwd 將進程的工作目錄改至容器的 rootfs 中;User 將為容器中的正在運行的進程設(shè)置 UID 和 GID;Stdin io.Reader 表示標準輸入;Stdout io.Writer 表示標準輸出;Stderr io.Writer 表示標準錯誤;consolePath 表示到容器的控制臺的路徑;Capabilities 表示容器中進程運行所需的權(quán)限;ops 表示 ParentProcess 對象。ParentProcess 負責處理容器啟動工作,包含一系列的函數(shù)動作:

  pid():返回一個正在運行的進程的 pid,可以通過管道從已啟動的容器進程中獲得。

  start():開始容器中的執(zhí)行進程。

  terminate():發(fā)送 SIGKILL 信號結(jié)束進程。

  StartTime():獲取進程啟動時間。

  signal():發(fā)送信號給進程。

  wait():等待程序執(zhí)行結(jié)束,返回結(jié)束的程序狀態(tài)。

感謝各位的閱讀,以上就是“docker 源碼分析 Libcontainer”的內(nèi)容了,經(jīng)過本文的學習后,相信大家對 docker 源碼分析 Libcontainer 這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是丸趣 TV,丸趣 TV 小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!

正文完
 
丸趣
版權(quán)聲明:本站原創(chuàng)文章,由 丸趣 2023-08-16發(fā)表,共計7544字。
轉(zhuǎn)載說明:除特殊說明外本站除技術(shù)相關(guān)以外文章皆由網(wǎng)絡(luò)搜集發(fā)布,轉(zhuǎn)載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 玛沁县| 康平县| 武宁县| 临朐县| 泊头市| 绩溪县| 淅川县| 彭州市| 霍山县| 瑞安市| 兴海县| 三江| 海丰县| 靖西县| 海盐县| 高青县| 桃园县| 会理县| 德化县| 大新县| 凤山县| 桃园市| 两当县| 尤溪县| 方城县| 青岛市| 宜黄县| 巫溪县| 谷城县| 河源市| 延寿县| 南陵县| 舟山市| 鹰潭市| 阿瓦提县| 静海县| 兴仁县| 阳西县| 疏勒县| 连平县| 安新县|