自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

真正運行容器的工具:深入了解 Runc 和 OCI 規(guī)范

開發(fā) 開發(fā)工具
runc 是一個命令行客戶端,用于運行根據(jù) Open Container Initiative (OCI) 格式打包的應(yīng)用程序,并且是 Open Container Initiative 規(guī)范的兼容實現(xiàn)。

[[430749]]

我們談?wù)勎挥?Docker、Podman、CRI-O 和 Containerd 核心的工具:runc。

原始容器運行時

如果試圖將鏈從最終用戶繪制到實際的容器進程,它可能如下所示:

runc 是一個命令行客戶端,用于運行根據(jù) Open Container Initiative (OCI) 格式打包的應(yīng)用程序,并且是 Open Container Initiative 規(guī)范的兼容實現(xiàn)。

有一個關(guān)于如何運行容器和管理容器映像的開放容器計劃(OCI) 和規(guī)范。runc 符合此規(guī)范,但還有其他符合 OCI 的運行時。甚至可以運行符合 OCI 標(biāo)準(zhǔn)的虛擬機,Kata Containers 與gVisor就是符合符合 OCI 標(biāo)準(zhǔn)的虛擬機。gVisor 為代表的用戶態(tài) Kernel 方案是安全容器的未來,只是現(xiàn)在還不夠完善。

runc 希望提供一個“ OCI 包”,它只是一個根文件系統(tǒng)和一個config.json 文件。而不是Podman 或 Docker 那樣有“鏡像”概念,所以不能只執(zhí)行runc run nginx:latest這樣來啟動一個容器。

Runc 符合 OCI 規(guī)范(具體來說,是runtime-spec),這意味著它可以使用 OCI 包并從中運行一個容器。值得重申的是,這些bundle并不是“容器鏡像”,它們要簡單得多。層、標(biāo)簽、容器注冊表和存儲庫等功能 - 所有這些都不是 OCI 包甚至運行時規(guī)范的一部分。有一個單獨的 OCI-spec (image-spec )定義鏡像。

文件系統(tǒng)包是你下載容器鏡像并解壓后得到的。所以它是這樣的:

  1. OCI Image -> OCI Runtime Bundle -> OCI Runtime 

在我們的例子中,這意味著:

  1. Container image -> Root filesystem and config.json -> runc 

讓我們構(gòu)建一個應(yīng)用程序包。我們可以從 config.json 文件開始,因為這部分非常簡單:

  1. mkdir my-bundle 
  2. cd my-bundle 
  3. runc spec 

runc spec生成一個虛擬的 config.json。它已經(jīng)有一個“進程”部分,用于指定在容器內(nèi)運行哪個進程 - 即使有幾個環(huán)境變量。

  1.         "ociVersion""1.0.1-dev"
  2.         "process": { 
  3.              "terminal"true
  4.                 "user": { 
  5.                         "uid": 0, 
  6.                         "gid": 0 
  7.                 }, 
  8.                 "args": [ 
  9.                         "sh" 
  10.                 ], 
  11.                 "env": [ 
  12.                         "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
  13.                         "TERM=xterm" 
  14.                 ], 
  15.  
  16. ... 

它還定義了在哪里查找根文件系統(tǒng)...

  1. ... 
  2.  
  3.         "root": { 
  4.                 "path""rootfs"
  5.                 "readonly"true 
  6.  
  7.         }, 
  8. ... 

...以及其他許多內(nèi)容,包括容器內(nèi)的默認(rèn)掛載、功能、主機名等。如果檢查此文件,會注意到,許多部分與平臺無關(guān),并且特定于具體操作系統(tǒng)的部分嵌套在適當(dāng)?shù)膬?nèi)部部分。例如,會注意到有一個帶有 Linux 特定選項的“linux”部分。

如果我們嘗試運行這個包,我們會得到一個錯誤:

  1. # runc run test 
  2. rootfs (/root/my-bundle/rootfs) does not exist 

如果我們簡單地創(chuàng)建文件夾,我們會得到另一個錯誤:

  1. # mkdir rootfs 
  2. # runc run test 
  3. container_linux.go:345: starting container process caused "exec: \"sh\": executable file not found in $PATH" 

這完全有道理 - 空文件夾并不是真正有用的根文件系統(tǒng),我們的容器沒有機會做任何有用的事情。我們需要創(chuàng)建一個真正的 Linux 根文件系統(tǒng)。這里可以使用如下命令解壓rootfs:

  1. $ docker export $(docker create busybox) | tar -C /mycontainer/rootfs -xvf - 

這里我們使用skopeo 和 umoci 獲取 OCI 應(yīng)用程序包。

如何使用 skopeo 和 umoci 獲取 OCI 應(yīng)用程序包

從頭開始創(chuàng)建 rootfilesystem 是一種相當(dāng)麻煩的事情,因此讓我們使用現(xiàn)有的最小映像之一 busybox。

要拉取鏡像,我們首先需要安裝skopeo。我們也可以使用 Buildah,但它的功能太多,無法滿足我們的需求。Buildah 專注于構(gòu)建鏡像,甚至具有運行容器的基本功能。由于我們今天盡可能地低級別,我們將使用 skopeo:

  • skopeo 是一個命令行程序,可對容器鏡像和鏡像存儲庫執(zhí)行各種操作。
  • skopeo 可以在不同來源和目的地之間復(fù)制鏡像、檢查鏡像甚至刪除它們。
  • skopeo 無法構(gòu)建映像,它不知道如何處理 Containerfile。它非常適合自動化容器鏡像升級的 CI/CD 管道。
  1. yum install skopeo -y 

然后復(fù)制busybox鏡像:

  1. skopeo copy docker://busybox:latest oci:busybox:latest 

沒有“拉取”——我們需要告訴 skopeo 鏡像的來源和目的地。skopeo 支持幾乎十幾種不同類型的來源和目的地。請注意,此命令將創(chuàng)建一個新busybox文件夾,將在其中找到所有 OCI 鏡像文件,具有不同的鏡像層、清單等。

不要混淆 Image manifest 和 Application runtime bundle manifest,它們是不一樣的。

我們復(fù)制的是一個 OCI Image,但是我們已經(jīng)知道,runc 需要 OCI Runtime Bundle。我們需要一個將鏡像轉(zhuǎn)換為解壓包的工具。這個工具將是umoci - 一個 openSUSE 實用程序,其唯一目的是操作 OCI 鏡像。要安裝它,請從 Github Releases獲取最新版本的PATH。在撰寫本文時,最新版本是0.4.5. umoci unpack獲取 OCI 鏡像并從中制作一個包:

  1. umoci unpack --image busybox:latest bundle 

讓我們看看bundle文件夾里面有什么:

  1. # ls bundle 
  2. config.json 
  3. rootfs 
  4. sha256_73c6c5e21d7d3467437633012becf19e632b2589234d7c6d0560083e1c70cd23.mtree 
  5. umoci.json 

讓我們將rootfs目錄復(fù)制到之前創(chuàng)建的my-bundle目錄。如果你好奇,這是rootfs的內(nèi)容,如下:

  1. bin dev etc home root tmp usr var 

如果它看起來像一個基本的 Linux 根文件系統(tǒng),那么就是對的。

根據(jù) OCI Runtime 規(guī)范,Linux ABI 下的應(yīng)用程序會期望 Linux 環(huán)境提供以下特殊的文件系統(tǒng):

  • /proc 文件夾,掛載 proc 文件系統(tǒng)。
  • /sys 文件夾,掛載 sysfs 文件系統(tǒng)。
  • /dev/pts 文件夾,掛載 devpts 文件系統(tǒng)。
  • /dev/shm 文件夾,掛載 tmpfs 文件系統(tǒng)。

這幾個文件夾的作用這里略去,有興趣的讀者可以自行查閱 man7.org。runc 文檔中還額外要求提供:

  • /dev 文件夾,掛載 tmpfs 文件系統(tǒng)。
  • /dev/mqueue 文件夾,掛載 mqueue 文件系統(tǒng)。

runc 是 OCI Runtime 規(guī)范的參考實現(xiàn),規(guī)范為容器的創(chuàng)建提供了整潔的接口,只需要為 runc 提供一份 config.json [1]。

使用 runc 運行 OCI 應(yīng)用程序包

我們準(zhǔn)備好將我們的應(yīng)用程序包作為名為 的容器運行test:

  1. runc run test 

接下來發(fā)生的事情是我們最終進入了一個新創(chuàng)建的容器內(nèi)的 shell!

  1. # runc run test 
  2. / # ls 
  3. bin   dev   etc   home  proc  root  sys   tmp   usr   var 

我們以默認(rèn)foreground模式運行前一個容器。在這種模式下,每個容器進程都成為一個長時間運行的runc進程的子進程:

  1. 6801   997  \_ sshd: root [priv] 
  2. 6805  6801      \_ sshd: root@pts/1 
  3. 6806  6805          \_ -bash 
  4. 6825  6806              \_ zsh 
  5. 7342  6825                  \_ runc run test 
  6. 7360  7342                  |   \_ runc run test 

如果我終止與該服務(wù)器的 ssh 會話,runc 進程也會終止,最終殺死容器進程。讓我們通過sleep infinite在 config.json 中替換 command并將終端選項設(shè)置為“false”來更仔細(xì)地檢查這個容器。

runc不提供大量的命令行參數(shù)。它有類似start,stop和 run的命令來做容器的生命周期管理,但是容器的配置總是來自文件,而不是來自命令行:

  1.         "ociVersion""1.0.1-dev"
  2.         "process": { 
  3.                 "terminal"false
  4.                 "user": { 
  5.                         "uid": 0, 
  6.                         "gid": 0 
  7.                 }, 
  8.                 "args": [ 
  9.                         "sleep"
  10.                         "infinite" 
  11.                 ] 
  12. ... 

這次讓我們以分離模式運行容器:

  1. runc run test --detach 

我們可以看到正在運行的容器runc list:

  1. ID          PID         STATUS      BUNDLE            CREATED                          OWNER 
  2. test        4258        running     /root/my-bundle   2020-04-23T20:29:39.371137097Z   root 

在 Docker 的情況下,有一個Docker Daemon守護進程知道關(guān)于容器的一切。runc 如何找到我們的容器?事實證明,它只是在文件系統(tǒng)上保持狀態(tài),默認(rèn)情況下在里面/run/runc/CONTAINER_NAME/state.json:

  1. # cat /run/runc/test/state.json 
  2. {"id":"test","init_process_pid":4258,"init_process_start":9561183,"created":"2020-04-23T20:29:39.371137097Z","config":{"no_pivot_root":false,"parent_death_signal":0,"rootfs":"/root/my-bundle/rootfs","readonlyfs":true,"rootPropagation":0,"mounts".... 

當(dāng)我們在分離模式下運行時,原始runc run命令(不再有這樣的進程)和這個容器進程之間沒有關(guān)系。如果我們查看進程表,我們會看到容器的父進程是PID 1:

  1. # ps axfo pid,ppid,command 
  2. 4258     1 sleep infinite 

Docker、containerd、CRI-O 等使用分離模式。它的目的是簡化 runc 和全功能容器管理工具之間的集成。值得一提的是 runc 本身并不是某種類型的庫——它是一個 CLI。當(dāng)其他工具使用 runc 時,它們會調(diào)用我們剛剛在操作中看到的相同 runc 命令。

在runc 文檔中閱讀有關(guān)前臺模式和分離模式之間差異的更多信息。雖然容器進程的PID是4258,但在容器內(nèi)部PID顯示為1:

  1. # runc exec test ps                      
  2. PID   USER     TIME  COMMAND 
  3.     1 root      0:00 sleep infinite 
  4.    13 root      0:00 ps 

這要歸功于Linux 命名空間,它是真正的容器背后的基本技術(shù)之一。我們可以通過lsns在主機系統(tǒng)上執(zhí)行來列出所有當(dāng)前的命名空間 :

  1. # lsns 
  2. NS TYPE   NPROCS   PID USER COMMAND 
  3. 4026532219 mnt         1  4258 root sleep infinite 
  4. 4026532220 uts         1  4258 root sleep infinite 
  5. 4026532221 ipc         1  4258 root sleep infinite 
  6. 4026532222 pid         1  4258 root sleep infinite 
  7. 4026532224 net         1  4258 root sleep infinite 

runc 負(fù)責(zé)我們?nèi)萜鬟M程的進程、網(wǎng)絡(luò)、掛載和其他命名空間。

容器世界的影子統(tǒng)治者

Podman、Docker 和所有其他工具,包括在那里運行的大多數(shù) Kubernetes 集群,都?xì)w結(jié)為runc啟動容器進程的二進制文件。

在實際工作中,幾乎永遠(yuǎn)不會做我剛剛給你展示的事情 - 除非正在開發(fā)或者調(diào)試自己的或現(xiàn)有的容器工具。不能從容器映像中組裝應(yīng)用程序包,并且使用 Podman 而不是直接使用 runc 會更好。

runc就是Low-Level實現(xiàn)的實現(xiàn),我們了解幕后發(fā)生的事情以及運行容器真正涉及的內(nèi)容是非常有幫助的。最終用戶和最終容器過程之間仍然有很多層,但是如果了解最后一層,那么容器將不再是神奇的東西,有時也很奇怪。最后你會發(fā)現(xiàn)容器它只是 runc 在命名空間中生成一個進程。當(dāng)然最后一層是Linux內(nèi)核,相比宇宙中有無數(shù)層。

runc 最重要的部分是它跟蹤 OCI運行時規(guī)范。盡管幾乎每一個容器,這些天與runc催生,它不具有與runc催生??梢詫⑵渑c遵循運行時規(guī)范的任何其他容器運行時交換,并且容器引擎(如 CRI-O)應(yīng)該以相同的方式工作。

High-Level容器運行時可以不依賴于 runc 本身。它們依賴于一些遵循 OCI 規(guī)范的容器運行時。這是當(dāng)今容器世界真正美麗的部分。

reference

[1]https://github.com/opencontainers/runtime-spec/blob/master/config.md

https://mkdev.me/en/posts/the-tool-that-really-runs-your-containers-deep-dive-into-runc-and-oci-specifications

https://github.com/opencontainers/runc/blob/master/docs/terminals.md

https://katacontainers.io/

https://polyverse.com/blog/skopeo-the-best-container-tool-you-need-to-know-about/ 

https://umo.ci/quick-start/workflow/

 

責(zé)任編輯:武曉燕 來源: 運維開發(fā)故事
相關(guān)推薦

2010-11-08 13:54:49

Sqlserver運行

2017-05-23 16:11:40

紅帽PaaSOpenShift

2010-10-26 11:28:33

ORACLE運行方式

2012-05-14 17:22:38

ibmdw

2023-09-26 00:40:35

Docker容器操作命令

2010-11-19 16:22:14

Oracle事務(wù)

2010-07-13 09:36:25

2010-06-23 20:31:54

2009-08-25 16:27:10

Mscomm控件

2022-08-26 13:48:40

EPUBLinux

2020-09-21 09:53:04

FlexCSS開發(fā)

2020-07-20 06:35:55

BashLinux

2023-10-06 00:04:02

2019-08-02 08:59:21

Token認(rèn)證服務(wù)器

2019-11-29 16:21:22

Spring框架集成

2017-01-20 08:30:19

JavaScriptfor循環(huán)

2013-04-10 11:16:19

iPad的MouseE

2018-02-24 13:21:02

2018-09-04 16:20:46

MySQ索引數(shù)據(jù)結(jié)構(gòu)

2016-10-20 08:46:17

點贊
收藏

51CTO技術(shù)棧公眾號