CRI shim:Kubelet 怎么與容器運行時交互之二
前言
通過《CRI shim:kubelet怎么與容器運行時交互(一)》這一篇文章,我們知道了:
- CRI 是服務(wù)于 Kubernetes 的,而且它呈現(xiàn)向上匯報的狀態(tài)。它是幫助 Kubernetes 的,它不幫助OCI的。所以說當(dāng)你去做這個集成時候,你會發(fā)現(xiàn)尤其對于 VM gVisor\KataContainer 來說,它與 CRI 的很多假設(shè)或者是 API 的寫法上是不對應(yīng)的。所以你的集成工作會比較費勁,這是一個不 match 的狀態(tài)。
- 另一個問題就是我們維護起來非常困難,因為由于有了 CRI 之后,比如 RedHat 擁有自己的 CRI 實現(xiàn)叫 cri-o,他們和 containerd 在本質(zhì)上沒有任何區(qū)別,跑到最后都是靠 runC 起容器,為什么還需要cri-o這種東西?我們不知道,如果我想使用Kata container與containerd多運行時的話,我需要給他們兩個分別寫兩部分的一體化把 Kata 集成進去。這就很麻煩,就意味著我有 100 種這樣的 CRI ,我就要寫 100 個shim去集成,而且他們的功能全部都是重復(fù)的。
- 多容器運行時用于不同目的,比如使用虛擬化容器引擎式運行不可信應(yīng)用和多租戶應(yīng)用,而使用 Docker 運行系統(tǒng)組件或者無法虛擬化的容器(比如需要 HostNetwork 的容器。
所以這就產(chǎn)生了Containerd ShimV2的這樣的shim來解決這個問題。
Containerd ShimV2
2018 年,由 containerd 社區(qū)主導(dǎo)的 shimv2 API 的出現(xiàn),在 CRI 的基礎(chǔ)上,為用戶集成自己的容器運行時帶來了更加成熟和方便的實踐方法。
今天給大家 propose 的這個東西叫做 Containerd ShimV2。前面我們說過 CRI,CRI 決定的是 Runtime 和 Kubernetes 之間的關(guān)系,那么我們現(xiàn)在能不能再有一層更細致的 API 來決定我的 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。這么做有什么好處?
我們來看一下,最大的區(qū)別在于:在這種方式下,你可以為每一個 Pod 指定一個 Shim。因為在最開始的時候,Containerd 是直接啟動了一個 Containerd Shim 來去做響應(yīng),但我們新的 API 是這樣寫的,是 Containerd Shim start 或者 stop。所以這個 start 和 stop 操作怎么去實現(xiàn)是你要做的事情。
現(xiàn)在,我作為一位 Kata Containers項目的維護者我就可以這么實現(xiàn)。我在 created Sandbox 的時候 call 這個 start 的時候,我啟動一個 Containerd Shim。
但是當(dāng)我下一步是調(diào)用 API 的時候,就是在前面那個 CRI 里面,訪問 Container API 時候,我就不用再啟動一個連接,我是復(fù)用。我重用創(chuàng)建好的這個 Sandbox,這就為你的實現(xiàn)提供了很大的自由度。所以這時候你會發(fā)現(xiàn)整個實現(xiàn)的方式變了,這時候 Containerd 用過來之后,它不再去關(guān)心每個容器起 Containerd Shim,而是由你自己去實現(xiàn)。我的實現(xiàn)方式是我只在 Sandbox 時候,去創(chuàng)建 containerd-shim-v2,而接下來整個后面的 container 層的操作,會全部走到這個 containerd-shim-v2 里面,去重用這個 Sandbox,所以這個跟前面的時間就出現(xiàn)很大的不同。
所以你現(xiàn)在去總結(jié)一下這個圖的話,你發(fā)現(xiàn)我們實現(xiàn)方式是變成這個樣子:
首先,你還是用原來的 CRI Containerd,只不過現(xiàn)在裝的是 runC,你現(xiàn)在再裝一個 kata container 放在那機器上面。接下來我們 Kata 那邊會給你寫一個實現(xiàn)叫 kata-Containerd-Shimv2。
現(xiàn)在,我們只聚焦在怎么去把 Containerd 對接在 kata container 上面,就是所謂的實現(xiàn) Shimv2 API,這是我們要做的工作。而具體到我們這要做的事情上,其實它就是這樣一系列與run一個容器相關(guān)的 API。比如說我可以去 create、start,這些操作全部映射在我 Shimv2 上面去實現(xiàn),而不是說我現(xiàn)在考慮怎么去映射,去實現(xiàn) CRI,這個自由度由于之前太大,造成了我們現(xiàn)在的一個局面,就有一堆 CRI Shim 可以用。這其實是一個不好的事情。有很多政治原因,有很多非技術(shù)原因,這都不是我們作為技術(shù)人員應(yīng)該關(guān)心的事情,你現(xiàn)在只需要想我怎么去跟 Shimv2 對接就好了。
給 Kubernetes 提供 kata-runtime
通過直接創(chuàng)建 Container 可以使用 kata-runtime 。但在集群中,我們該如何告訴 Kubernetes 哪些負載需要使用 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 對硬件的要求是否滿足以下任意條件:
- Intel VT-x technology.
- ARM Hyp mode (virtualization extension).
- IBM Power Systems.
- IBM Z mainframes.
安裝完 kata-runtime 之后,執(zhí)行檢測命令:
- $ 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 的方式
這種方式對相關(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 的方式
對于不符合上述版本要求的環(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)建負載 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
查看負載:
- $ kata-runtime list
方式二:untrusted_workload_runtime 的方式 untrusted_workload_runtime 使用 annotations 告訴 Kubernetes 集群哪些負載需要使用 kata-runtime。
- annotations:
- io.kubernetes.cri.untrusted-workload: "true"
下面是一個示例 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
查看負載:
- $ kata-runtime list
總結(jié)
Kubernetes 現(xiàn)在的核心設(shè)計思想,就是通過接口化和插件化,將原本復(fù)雜的、對主干代碼有侵入性的特性,逐一從核心庫中剝離和解耦。而在這個過程中,CRI 就是 Kubernetes 項目中最早完成了插件化的一個調(diào)用接口。這里主要為你介紹了在CRI基礎(chǔ)上的另一種集成容器運行時的思路,即:CRI + containerd shimv2 的方式。
- 通過這種方式,你就不需要再為自己的容器運行時專門編寫一個 CRI 實現(xiàn)(CRI shim),而是可以直接重用 containerd對 CRI 的支持能力,然后通過 containerd shimv2的方式來對接具體的容器運行時(比如 runc)。
- 這種集成方式已經(jīng)成為了社區(qū)對接下層容器運行時的主流思路,像很多類似于 KataContainers,gVisor,F(xiàn)irecracker 等基于獨立內(nèi)核或者虛擬化的容器項目,也都開始通過 shimv2 ,進而借助 containerd項目無縫接入到 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