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

容器中的 Shim 到底是個(gè)什么鬼?

云計(jì)算 云原生
Kubernetes 1.20 版開(kāi)始廢除了對(duì) dockershim 的支持,改用 Containerd[1] 作為默認(rèn)的容器運(yùn)行時(shí)。本文將介紹 Containerd 中的 "shim" 接口。

本文轉(zhuǎn)載自微信公眾號(hào)「云原生實(shí)驗(yàn)室」,作者Brian Goff。轉(zhuǎn)載本文請(qǐng)聯(lián)系云原生實(shí)驗(yàn)室公眾號(hào)。

Kubernetes 1.20 版開(kāi)始廢除了對(duì) dockershim 的支持,改用 Containerd[1] 作為默認(rèn)的容器運(yùn)行時(shí)。本文將介紹 Containerd 中的 "shim" 接口。

每一個(gè) Containerd 或 Docker 容器都有一個(gè)相應(yīng)的 "shim" 守護(hù)進(jìn)程,這個(gè)守護(hù)進(jìn)程會(huì)提供一個(gè) API,Containerd 使用該 API 來(lái)管理容器基本的生命周期(啟動(dòng)/停止),在容器中執(zhí)行新的進(jìn)程、調(diào)整 TTY 的大小以及與特定平臺(tái)相關(guān)的其他操作。shim 還有一個(gè)作用是向 Containerd 報(bào)告容器的退出狀態(tài),在容器退出狀態(tài)被 Containerd 收集之前,shim 會(huì)一直存在。這一點(diǎn)和僵尸進(jìn)程很像,僵尸進(jìn)程在被父進(jìn)程回收之前會(huì)一直存在,只不過(guò)僵尸進(jìn)程不會(huì)占用資源,而 shim 會(huì)占用資源。

shim 將 Containerd 進(jìn)程從容器的生命周期中分離出來(lái),具體的做法是 runc 在創(chuàng)建和運(yùn)行容器之后退出,并將 shim 作為容器的父進(jìn)程,即使 Containerd 進(jìn)程掛掉或者重啟,也不會(huì)對(duì)容器造成任何影響。這樣做的好處很明顯,你可以高枕無(wú)憂地升級(jí)或者重啟 Containerd,不會(huì)對(duì)運(yùn)行中的容器產(chǎn)生任何影響。Docker 的 --live-restore[2] 特征也實(shí)現(xiàn)了類(lèi)似的功能。

Containerd 支持哪些 shim?

Containerd 目前官方支持的 shim 清單:

io.containerd.runtime.v1.linux

io.containerd.runtime.v1.linux 是最原始的 shim API 和實(shí)現(xiàn)的 v1 版本,在 Containerd 1.0 之前被設(shè)計(jì)出來(lái)。該 shim 使用 runc 來(lái)執(zhí)行容器,并且只支持 cgroup v1。目前 v1 版 shim API 已被廢棄,并將于 Containerd 2.0 被刪除。

io.containerd.runc.v1

io.containerd.runc.v1 與 io.containerd.runtime.v1.linux 的實(shí)現(xiàn)類(lèi)似,唯一的區(qū)別是它使用了 v2 版本 shim API。該 shim 仍然只支持 cgroup v1。

io.containerd.runc.v2

該 shim 與 v1 采用了完全不同的實(shí)現(xiàn),并且使用了 v2 版本 shim API,同時(shí)支持 cgroup v1 和 v2。該 shim 進(jìn)程以運(yùn)行多個(gè)容器,用于 Kubernetes 的 CRI 實(shí)現(xiàn),可以在一個(gè) Pod 中運(yùn)行多個(gè)容器。

io.containerd.runhcs.v1

這是 Windows 平臺(tái)的 shim,使用 Window 的HCSv2 API 來(lái)管理容器。

當(dāng)然,除了官方正式支持的 shim 之外,任何人都可以編寫(xiě)自己的 shim,并讓 Containerd 調(diào)用該 shim。Containerd 在調(diào)用時(shí)會(huì)將 shim 的名稱(chēng)解析為二進(jìn)制文件,并在 $PATH 中查找這個(gè)二進(jìn)制文件。例如 io.containerd.runc.v2 會(huì)被解析成二進(jìn)制文件 containerd-shim-runc-v2,io.containerd.runhcs.v1 會(huì)被解析成二進(jìn)制文件 containerd-shim-runhcs-v1.exe??蛻?hù)端在創(chuàng)建容器時(shí)可以指定使用哪個(gè) shim,如果不指定就使用默認(rèn)的 shim。

下面是一個(gè)示例,用來(lái)指定將要使用的 shim:

package main

import (
"context"

"github.com/containerd/containerd"
"github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/oci"
v1opts "github.com/containerd/containerd/pkg/runtimeoptions/v1"
)

func main() {
ctx := namespaces.WithNamespace(context.TODO(), "default")

// Create containerd client
client, err := containerd.New("/run/containerd/containerd.sock")
if err != nil {
panic(err)
}

// Get the image ref to create the container for
img, err := client.GetImage(ctx, "docker.io/library/busybox:latest")
if err != nil {
panic(err)
}

// set options we will pass to the shim (not really setting anything here, but we could)
var opts v1opts.Options

// Create a container object in containerd
cntr, err := client.NewContainer(ctx, "myContainer",
// All the basic things needed to create the container
containerd.WithSnapshotter("overlayfs"),
containerd.WithNewSnapshot("myContainer-snapshot", img),
containerd.WithImage(img),
containerd.WithNewSpec(oci.WithImageConfig(img)),

// Set the option for the shim we want
containerd.WithRuntime("io.containerd.runc.v1", &opts),
)
if err != nil {
panic(err)
}

// cleanup
cntr.Delete(ctx)
}

??注意:WithRuntime 將 interface{} 作為第二個(gè)參數(shù),可以傳遞任何類(lèi)型給 shim。只要確保你的 shim 能夠識(shí)別這個(gè)類(lèi)型的數(shù)據(jù),并在 typeurl 包中注冊(cè)這個(gè)類(lèi)型,以便它能被正確編碼。

每個(gè) shim 都有自己支持的一組配置選項(xiàng),可以單獨(dú)針對(duì)每個(gè)容器進(jìn)行配置。例如 io.containerd.runc.v2 可以將容器的 stdout/stderr 轉(zhuǎn)發(fā)到一個(gè)單獨(dú)的進(jìn)程,為 shim 的運(yùn)行設(shè)置自定義的 cgroup 等等。你可以創(chuàng)建自定義的 shim,在容器運(yùn)行時(shí)添加自定義的選項(xiàng)??偟膩?lái)說(shuō),shim 的 API 包含了 RPC 和一些二進(jìn)制調(diào)用用于創(chuàng)建/刪除 shim,以及到 Containerd 進(jìn)程的反向通道。

如果你想實(shí)現(xiàn)自己的 shim,下面是相關(guān)參考資料:

  • (v2) shim RPC API 的詳細(xì)定義[3]
  • 實(shí)現(xiàn) shim 二進(jìn)制和RPC API的輔助工具[4]
  • shim 的使用方式[5]

你只需要實(shí)現(xiàn)一個(gè)接口,shim.Run 會(huì)處理剩下的事情。shim 需要重點(diǎn)關(guān)注的是內(nèi)存使用,因?yàn)槊總€(gè)容器都有一個(gè) shim 進(jìn)程,隨著容器數(shù)量的增加,shim 的內(nèi)存使用會(huì)急劇上升。shim 的 API 是在 protobuf 中定義的,看起來(lái)有點(diǎn)像 gRPC 的 API,但實(shí)際上 shim 使用的是一個(gè)叫做 ttrpc[6] 的自定義協(xié)議,與 gRPC 并不兼容。ttrpc 是一個(gè)原 RPC 協(xié)議,專(zhuān)為降低內(nèi)存使用而設(shè)計(jì)。

創(chuàng)建容器的 RPC 調(diào)用流程

Containerd 中有一個(gè) container 對(duì)象,當(dāng)你創(chuàng)建一個(gè) container 對(duì)象,只是創(chuàng)建了一些與容器相關(guān)的數(shù)據(jù),并將這些數(shù)據(jù)存儲(chǔ)到本地?cái)?shù)據(jù)庫(kù)中,并不會(huì)在系統(tǒng)中啟動(dòng)任何容器。container 對(duì)象創(chuàng)建成功后,客戶(hù)端會(huì)從 container 對(duì)象中創(chuàng)建一個(gè) task,接下來(lái)是調(diào)用 shim API。

以下是 RPC 調(diào)用的總體流程:

  • 客戶(hù)端調(diào)用 container.NewTask(…),containerd 根據(jù)指定或默認(rèn)的運(yùn)行時(shí)名稱(chēng)解析 shim 二進(jìn)制文件,例如:io.containerd.runc.v2 -> containerd-shim-runc-v2。
  • containerd 通過(guò) start 命令啟動(dòng) shim 二進(jìn)制文件,并加上一些額外的參數(shù),用于定義命名空間、OCI bundle 路徑、調(diào)試模式、返回給 containerd 的 unix socket 路徑等。在這一步調(diào)用中,當(dāng)前工作目錄設(shè)置為 shim 的工作路徑。
  • 此時(shí),新創(chuàng)建的 shim 進(jìn)程會(huì)向 stdout 寫(xiě)一個(gè)連接字符串,以允許 containerd 連接到 shim ,進(jìn)行 API 調(diào)用。一旦連接字符串初始化完成,shim 開(kāi)始監(jiān)聽(tīng)之后,start 命令就會(huì)返回。
  • containerd 使用 shim start 命令返回的連接字符串,打開(kāi)一個(gè)與 shim API 的連接。
  • containerd 使用 OCI bundle 路徑和其他選項(xiàng),調(diào)用 Create shim RPC。這一步會(huì)創(chuàng)建所有必要的 沙箱,并返回沙箱進(jìn)程的 pid。以 runc 為例,我們使用 runc create --pid-file= 命令創(chuàng)建容器,runc 會(huì)分叉出一個(gè)新進(jìn)程(runc init)用來(lái)設(shè)置沙箱,然后等待調(diào)用 runc start,所有這些都準(zhǔn)備好后,runc create 命令就會(huì)返回結(jié)果。在 runc create 返回結(jié)果之前,runc 會(huì)將 runc-init 進(jìn)程的 pid 寫(xiě)入定義的 pid 文件中,客戶(hù)端可以使用這個(gè) pid 來(lái)做一些操作,比如在沙箱中設(shè)置網(wǎng)絡(luò)(網(wǎng)絡(luò)命名空間可以在 /proc//ns/net 中設(shè)置)。
  • create 調(diào)用還會(huì)提供一個(gè)掛載列表以構(gòu)建 rootfs,還包含 checkpoint 信息。
  • 下一步客戶(hù)端調(diào)用 task.Wait,觸發(fā) containerd 調(diào)用 shim Wait API。這是一個(gè)持久化的請(qǐng)求,只有在容器退出后才會(huì)返回。到這一步仍然不會(huì)啟動(dòng)容器。
  • 客戶(hù)端繼續(xù)調(diào)用 task.Start,觸發(fā) containerd 調(diào)用 Start shim RPC。這一步才會(huì)真正啟動(dòng)容器,并返回容器進(jìn)程的 pid。
  • 這一步,客戶(hù)端就可以針對(duì) task 進(jìn)行一些額外的調(diào)用請(qǐng)求。例如,如果 task 包含 TTY,會(huì)請(qǐng)求task.ResizePTY,或者請(qǐng)求 task.Kill 來(lái)發(fā)送一個(gè)信號(hào)等等。
  • task.Exec 比較特殊,它會(huì)調(diào)用 shim Exec RPC,但并沒(méi)有在容器中執(zhí)行某個(gè)進(jìn)程,只是在 shim 中注冊(cè)了 exec,后面會(huì)使用 exec ID 來(lái)調(diào)用 shim Start RPC。
  • 在容器或 exec 進(jìn)程退出后,containerd 將會(huì)調(diào)用 shim Delete RPC,清理 exec 進(jìn)程或容器的所有資源。例如,對(duì)于runc shim, 這一步會(huì)調(diào)用 runc delete。
  • containerd 調(diào)用 Shutdown RPC,此時(shí) shim 將會(huì)退出。

shim 的另一個(gè)重要部分是將容器的生命周期事件返回給 containerd ,包括:TaskCreateTaskStart TaskDelete TaskExit,TaskOOM, TaskExecAdded, TaskExecStarted,TaskPaused, TaskResumed,TaskCheckpointed??蓞⒖?task 的詳細(xì)定義[7]。

總結(jié)

Containerd 通過(guò) shim 為底層的容器運(yùn)行時(shí)提供了可插拔能力。雖然這不是使用 Containerd 管理容器的唯一手段,但目前內(nèi)置的 TaskService 使用了該方式,Kubernetes 通過(guò)調(diào)用 CRI 來(lái)創(chuàng)建 Pod 也是使用的 shim。由此可見(jiàn) shim 這種方式很受歡迎,它不但增強(qiáng)了 Containerd 的擴(kuò)展能力,以支持更多平臺(tái)和基于虛擬機(jī)的運(yùn)行時(shí)(firecracker[8],kata[9]),而且允許嘗試其他 shim 實(shí)現(xiàn)(systemd[10])。

引用鏈接

[1]Containerd: https://containerd.io/

[2]--live-restore: https://docs.docker.com/config/containers/live-restore/

[3](v2) shim RPC API 的詳細(xì)定義: https://github.com/containerd/containerd/blob/v1.5.8/runtime/v2/task/shim.proto

[4]實(shí)現(xiàn) shim 二進(jìn)制和RPC API的輔助工具: https://github.com/containerd/containerd/blob/89370122089d9cba9875f468db525f03eaf61e96/runtime/v2/shim/shim.go#L181-L194

[5]shim 的使用方式: https://github.com/containerd/containerd/blob/v1.5.8/cmd/containerd-shim-runc-v2/main.go

[6]ttrpc: https://github.com/containerd/ttrpc

[7]task 的詳細(xì)定義: https://github.com/containerd/containerd/blob/v1.5.6/api/events/task.proto

[8]firecracker: https://github.com/firecracker-microvm/firecracker-containerd/tree/main/runtime

[9]kata: https://github.com/kata-containers/kata-containers/tree/2.3.0/src/runtime

[10]systemd: https://github.com/cpuguy83/containerd-shim-systemd-v1

責(zé)任編輯:武曉燕 來(lái)源: 云原生實(shí)驗(yàn)室
相關(guān)推薦

2020-10-25 20:05:29

Pythonyield開(kāi)發(fā)

2021-03-06 09:18:51

JS閉包函數(shù)

2020-09-27 06:53:57

MavenCDNwrapper

2019-10-30 10:13:15

區(qū)塊鏈技術(shù)支付寶

2024-09-11 13:58:18

2022-02-22 13:20:57

RSA算法加密

2023-09-21 07:24:52

2012-02-13 15:50:59

2021-01-29 12:24:22

電腦電子計(jì)算機(jī)

2022-04-10 19:26:07

TypeScript類(lèi)型語(yǔ)法

2022-01-10 11:16:40

漏洞 Log4j2Jndi

2021-03-22 07:45:05

Sentinel微服務(wù)開(kāi)源的項(xiàng)目

2021-02-18 07:43:25

TCP協(xié)議網(wǎng)絡(luò)

2018-09-06 11:20:24

CDNDDoS網(wǎng)站

2024-08-26 14:23:56

2024-07-12 15:08:23

Python@wraps函數(shù)

2016-10-21 09:58:19

WindowsKMSOEM系統(tǒng)

2015-05-21 15:45:13

2024-07-03 12:04:42

C++this?

2010-06-29 13:39:26

Eclipse什么玩意兒
點(diǎn)贊
收藏

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