CRI shim:Kubelet 怎么與容器運(yùn)行時(shí)交互之二
前言
通過(guò)《CRI shim:kubelet怎么與容器運(yùn)行時(shí)交互(一)》這一篇文章,我們知道了:
- CRI 是服務(wù)于 Kubernetes 的,而且它呈現(xiàn)向上匯報(bào)的狀態(tài)。它是幫助 Kubernetes 的,它不幫助OCI的。所以說(shuō)當(dāng)你去做這個(gè)集成時(shí)候,你會(huì)發(fā)現(xiàn)尤其對(duì)于 VM gVisor\KataContainer 來(lái)說(shuō),它與 CRI 的很多假設(shè)或者是 API 的寫(xiě)法上是不對(duì)應(yīng)的。所以你的集成工作會(huì)比較費(fèi)勁,這是一個(gè)不 match 的狀態(tài)。
- 另一個(gè)問(wèn)題就是我們維護(hù)起來(lái)非常困難,因?yàn)橛捎谟辛?CRI 之后,比如 RedHat 擁有自己的 CRI 實(shí)現(xiàn)叫 cri-o,他們和 containerd 在本質(zhì)上沒(méi)有任何區(qū)別,跑到最后都是靠 runC 起容器,為什么還需要cri-o這種東西?我們不知道,如果我想使用Kata container與containerd多運(yùn)行時(shí)的話,我需要給他們兩個(gè)分別寫(xiě)兩部分的一體化把 Kata 集成進(jìn)去。這就很麻煩,就意味著我有 100 種這樣的 CRI ,我就要寫(xiě) 100 個(gè)shim去集成,而且他們的功能全部都是重復(fù)的。
- 多容器運(yùn)行時(shí)用于不同目的,比如使用虛擬化容器引擎式運(yùn)行不可信應(yīng)用和多租戶應(yīng)用,而使用 Docker 運(yùn)行系統(tǒng)組件或者無(wú)法虛擬化的容器(比如需要 HostNetwork 的容器。
所以這就產(chǎn)生了Containerd ShimV2的這樣的shim來(lái)解決這個(gè)問(wèn)題。
Containerd ShimV2
2018 年,由 containerd 社區(qū)主導(dǎo)的 shimv2 API 的出現(xiàn),在 CRI 的基礎(chǔ)上,為用戶集成自己的容器運(yùn)行時(shí)帶來(lái)了更加成熟和方便的實(shí)踐方法。
今天給大家 propose 的這個(gè)東西叫做 Containerd ShimV2。前面我們說(shuō)過(guò) CRI,CRI 決定的是 Runtime 和 Kubernetes 之間的關(guān)系,那么我們現(xiàn)在能不能再有一層更細(xì)致的 API 來(lái)決定我的 CRI Shim 跟下面的 Runtime 之間真正的接口是什么樣的?
這就是 ShimV2 出現(xiàn)的原因,它是一層 CRI shim 到 Containerd runtime 之間的標(biāo)準(zhǔn)接口,所以前面我直接從 CRI 到 Containerd 到 runC,現(xiàn)在不是。我們是從 CRI 到 Containerd 到 ShimV2,然后 ShimV2 再到 RunC 或者 KataContainer。這么做有什么好處?
我們來(lái)看一下,最大的區(qū)別在于:在這種方式下,你可以為每一個(gè) Pod 指定一個(gè) Shim。因?yàn)樵谧铋_(kāi)始的時(shí)候,Containerd 是直接啟動(dòng)了一個(gè) Containerd Shim 來(lái)去做響應(yīng),但我們新的 API 是這樣寫(xiě)的,是 Containerd Shim start 或者 stop。所以這個(gè) start 和 stop 操作怎么去實(shí)現(xiàn)是你要做的事情。
現(xiàn)在,我作為一位 Kata Containers項(xiàng)目的維護(hù)者我就可以這么實(shí)現(xiàn)。我在 created Sandbox 的時(shí)候 call 這個(gè) start 的時(shí)候,我啟動(dòng)一個(gè) Containerd Shim。
但是當(dāng)我下一步是調(diào)用 API 的時(shí)候,就是在前面那個(gè) CRI 里面,訪問(wèn) Container API 時(shí)候,我就不用再啟動(dòng)一個(gè)連接,我是復(fù)用。我重用創(chuàng)建好的這個(gè) Sandbox,這就為你的實(shí)現(xiàn)提供了很大的自由度。所以這時(shí)候你會(huì)發(fā)現(xiàn)整個(gè)實(shí)現(xiàn)的方式變了,這時(shí)候 Containerd 用過(guò)來(lái)之后,它不再去關(guān)心每個(gè)容器起 Containerd Shim,而是由你自己去實(shí)現(xiàn)。我的實(shí)現(xiàn)方式是我只在 Sandbox 時(shí)候,去創(chuàng)建 containerd-shim-v2,而接下來(lái)整個(gè)后面的 container 層的操作,會(huì)全部走到這個(gè) containerd-shim-v2 里面,去重用這個(gè) Sandbox,所以這個(gè)跟前面的時(shí)間就出現(xiàn)很大的不同。
所以你現(xiàn)在去總結(jié)一下這個(gè)圖的話,你發(fā)現(xiàn)我們實(shí)現(xiàn)方式是變成這個(gè)樣子:
首先,你還是用原來(lái)的 CRI Containerd,只不過(guò)現(xiàn)在裝的是 runC,你現(xiàn)在再裝一個(gè) kata container 放在那機(jī)器上面。接下來(lái)我們 Kata 那邊會(huì)給你寫(xiě)一個(gè)實(shí)現(xiàn)叫 kata-Containerd-Shimv2。
現(xiàn)在,我們只聚焦在怎么去把 Containerd 對(duì)接在 kata container 上面,就是所謂的實(shí)現(xiàn) Shimv2 API,這是我們要做的工作。而具體到我們這要做的事情上,其實(shí)它就是這樣一系列與run一個(gè)容器相關(guān)的 API。比如說(shuō)我可以去 create、start,這些操作全部映射在我 Shimv2 上面去實(shí)現(xiàn),而不是說(shuō)我現(xiàn)在考慮怎么去映射,去實(shí)現(xiàn) CRI,這個(gè)自由度由于之前太大,造成了我們現(xiàn)在的一個(gè)局面,就有一堆 CRI Shim 可以用。這其實(shí)是一個(gè)不好的事情。有很多政治原因,有很多非技術(shù)原因,這都不是我們作為技術(shù)人員應(yīng)該關(guān)心的事情,你現(xiàn)在只需要想我怎么去跟 Shimv2 對(duì)接就好了。
給 Kubernetes 提供 kata-runtime
通過(guò)直接創(chuàng)建 Container 可以使用 kata-runtime 。但在集群中,我們?cè)撊绾胃嬖V Kubernetes 哪些負(fù)載需要使用 kata-runtime 呢?根據(jù)不同的版本,Kata 提供了不同的方式。1.以 CentOS 操作系統(tǒng)為例,安裝kata及命令工具:
- $ source /etc/os-release
- $ yum -y install yum-utils
- $ ARCH=$(arch)
- $ BRANCH="${BRANCH:-master}"
- $ yum-config-manager --add-repo "http://download.opensuse.org/repositories/home:/katacontainers:/releases:/${ARCH}:/${BRANCH}/CentOS_${VERSION_ID}/home:katacontainers:releases:${ARCH}:${BRANCH}.repo"
- $ yum -y install kata-runtime kata-proxy kata-shim
2.首先檢查Kata 對(duì)硬件的要求是否滿足以下任意條件:
- Intel VT-x technology.
- ARM Hyp mode (virtualization extension).
- IBM Power Systems.
- IBM Z mainframes.
安裝完 kata-runtime 之后,執(zhí)行檢測(cè)命令:
- $ kata-runtime kata-check
- $ System is capable of running Kata Containers
- $ System can currently create Kata Containers
3.安裝 Kubernetes 集群 使用 Kubeadm 安裝集群非常方便,可以參考之前的文檔 使用 Kubeadm 安裝 Kubernetes 集群 。4.生成 containerd 配置文件
- containerd config default > /etc/containerd/config.toml
- RuntimeClass 的方式
這種方式對(duì)相關(guān)組件版本有要求:
- Kata Containers v1.5.0 or above (including 1.5.0-rc)
- Containerd v1.2.0 or above
- Kubernetes v1.12.0 or above
在 config.toml 配置文件中,增加如下內(nèi)容:
- [plugins.cri.containerd]
- no_pivot = false
- [plugins.cri.containerd.runtimes]
- [plugins.cri.containerd.runtimes.runc]
- runtime_type = "io.containerd.runc.v1"
- [plugins.cri.containerd.runtimes.runc.options]
- NoPivotRoot = false
- NoNewKeyring = false
- ShimCgroup = ""
- IoUid = 0
- IoGid = 0
- BinaryName = "runc"
- Root = ""
- CriuPath = ""
- SystemdCgroup = false
- [plugins.cri.containerd.runtimes.kata]
- runtime_type = "io.containerd.kata.v2"
- [plugins.cri.containerd.runtimes.katacli]
- runtime_type = "io.containerd.runc.v1"
- [plugins.cri.containerd.runtimes.katacli.options]
- NoPivotRoot = false
- NoNewKeyring = false
- ShimCgroup = ""
- IoUid = 0
- IoGid = 0
- BinaryName = "/usr/bin/kata-runtime"
- Root = ""
- CriuPath = ""
- SystemdCgroup = false
這里 [plugins.cri.containerd.runtimes.kata] 中的 kata 將被作為 RuntimeClass handler 關(guān)鍵字。
- 使用 untrusted_workload_runtime 的方式
對(duì)于不符合上述版本要求的環(huán)境,可以使用之前的方式。在配置文件中新增如下內(nèi)容:
- [plugins.cri.containerd.untrusted_workload_runtime]
- runtime_type = "io.containerd.runtime.v1.linux"
- runtime_engine = "/usr/bin/kata-runtime"
最后,都需要重啟 containerd。
- $ containerd systemctl daemon-reload
- $ systemctl restart containerd
5.使用 kata-runtime 方式一:RuntimeClass 方式
- 創(chuàng)建 RuntimeClass
- kind: RuntimeClass
- apiVersion: node.k8s.io/v1beta1
- metadata:
- name: kata-containers
- handler: kata
也可以為 runc 創(chuàng)建 RuntimeClass
- $ kubectl get runtimeclass
- NAME CREATED AT
- kata-containers 2020-08-30
創(chuàng)建負(fù)載 kata-pod.yaml
- apiVersion: v1
- kind: Pod
- metadata:
- name: kata-nginx
- spec:
- runtimeClassName: kata-containers
- containers:
- - name: nginx
- image: nginx
- ports:
- - containerPort: 80
執(zhí)行創(chuàng)建:
- $ kubectl apply -f kata-pod.yaml
查看負(fù)載:
- $ kata-runtime list
方式二:untrusted_workload_runtime 的方式 untrusted_workload_runtime 使用 annotations 告訴 Kubernetes 集群哪些負(fù)載需要使用 kata-runtime。
- annotations:
- io.kubernetes.cri.untrusted-workload: "true"
下面是一個(gè)示例 kata-pod-untrusted.yaml
- apiVersion: v1
- kind: Pod
- metadata:
- name: kata-nginx-untrusted
- annotations:
- io.kubernetes.cri.untrusted-workload: "true"
- spec:
- containers:
- - name: nginx
- image: nginx
- ports:
- - containerPort: 80
執(zhí)行創(chuàng)建:
- $ kubectl apply -f kata-pod-untrusted.yaml
查看負(fù)載:
- $ kata-runtime list
總結(jié)
Kubernetes 現(xiàn)在的核心設(shè)計(jì)思想,就是通過(guò)接口化和插件化,將原本復(fù)雜的、對(duì)主干代碼有侵入性的特性,逐一從核心庫(kù)中剝離和解耦。而在這個(gè)過(guò)程中,CRI 就是 Kubernetes 項(xiàng)目中最早完成了插件化的一個(gè)調(diào)用接口。這里主要為你介紹了在CRI基礎(chǔ)上的另一種集成容器運(yùn)行時(shí)的思路,即:CRI + containerd shimv2 的方式。
- 通過(guò)這種方式,你就不需要再為自己的容器運(yùn)行時(shí)專門(mén)編寫(xiě)一個(gè) CRI 實(shí)現(xiàn)(CRI shim),而是可以直接重用 containerd對(duì) CRI 的支持能力,然后通過(guò) containerd shimv2的方式來(lái)對(duì)接具體的容器運(yùn)行時(shí)(比如 runc)。
- 這種集成方式已經(jīng)成為了社區(qū)對(duì)接下層容器運(yùn)行時(shí)的主流思路,像很多類似于 KataContainers,gVisor,F(xiàn)irecracker 等基于獨(dú)立內(nèi)核或者虛擬化的容器項(xiàng)目,也都開(kāi)始通過(guò) shimv2 ,進(jìn)而借助 containerd項(xiàng)目無(wú)縫接入到 Kubernetes 當(dāng)中。
reference
https://blog.csdn.net/yuchunyu97/article/details/109241723https://github.com/kata-containers/documentation/blob/master/install/centos-installation-guide.mdhttps://ustack.io/2019-11-21-container%E7%9B%B8%E5%85%B3%E6%A6%82%E5%BF%B5%E6%A2%B3%E7%90%86.htmlhttps://github.com/kata-containers/documentation/blob/master/how-to/how-to-use-k8s-with-cri-containerd-and-kata.mdhttps://github.com/kubernetes/kubernetes/issues/73189https://blog.zufardhiyaulhaq.com/kubernetes-with-cri-containerd-and-kata-containers/https://www.chenshaowen.com/blog/how-to-integrate-kata-in-kubernetes-cluster.html