CRI shim:kubelet怎么与容器运行时交互(二)

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: CRI shim:kubelet怎么与容器运行时交互(二)

前言


通过《CRI shim:kubelet怎么与容器运行时交互(一)》这一篇文章,我们知道了:


  • CRI 是服务于 Kubernetes 的,而且它呈现向上汇报的状态。它是帮助 Kubernetes 的,它不帮助OCI的。所以说当你去做这个集成时候,你会发现尤其对于 VM gVisor\KataContainer 来说,它与 CRI 的很多假设或者是 API 的写法上是不对应的。所以你的集成工作会比较费劲,这是一个不 match 的状态。


  • 另一个问题就是我们维护起来非常困难,因为由于有了 CRI 之后,比如 RedHat 拥有自己的 CRI 实现叫 cri-o,他们和 containerd 在本质上没有任何区别,跑到最后都是靠 runC 起容器,为什么还需要cri-o这种东西?我们不知道,如果我想使用Kata container与containerd多运行时的话,我需要给他们两个分别写两部分的一体化把 Kata 集成进去。这就很麻烦,就意味着我有 100 种这样的 CRI ,我就要写 100 个shim去集成,而且他们的功能全部都是重复的。


  • 多容器运行时用于不同目的,比如使用虚拟化容器引擎式运行不可信应用和多租户应用,而使用 Docker 运行系统组件或者无法虚拟化的容器(比如需要 HostNetwork 的容器。


所以这就产生了Containerd ShimV2的这样的shim来解决这个问题。


Containerd ShimV2


2018 年,由 containerd 社区主导的 shimv2 API 的出现,在 CRI 的基础上,为用户集成自己的容器运行时带来了更加成熟和方便的实践方法。


今天给大家 propose 的这个东西叫做 Containerd ShimV2。前面我们说过 CRI,CRI 决定的是 Runtime 和 Kubernetes 之间的关系,那么我们现在能不能再有一层更细致的 API 来决定我的 CRI Shim 跟下面的 Runtime 之间真正的接口是什么样的?


这就是 ShimV2 出现的原因,它是一层 CRI shim 到 Containerd runtime 之间的标准接口,所以前面我直接从 CRI 到 Containerd 到 runC,现在不是。我们是从 CRI 到 Containerd 到 ShimV2,然后 ShimV2 再到 RunC 或者 KataContainer。这么做有什么好处?


640.png


我们来看一下,最大的区别在于:在这种方式下,你可以为每一个 Pod 指定一个 Shim。因为在最开始的时候,Containerd 是直接启动了一个 Containerd Shim 来去做响应,但我们新的 API 是这样写的,是 Containerd Shim start 或者 stop。所以这个 start 和 stop 操作怎么去实现是你要做的事情。


640.png


现在,我作为一位 Kata Containers项目的维护者我就可以这么实现。我在 created Sandbox 的时候 call 这个 start 的时候,我启动一个 Containerd Shim。

但是当我下一步是调用 API 的时候,就是在前面那个 CRI 里面,访问 Container API 时候,我就不用再启动一个连接,我是复用。我重用创建好的这个 Sandbox,这就为你的实现提供了很大的自由度。所以这时候你会发现整个实现的方式变了,这时候 Containerd 用过来之后,它不再去关心每个容器起 Containerd Shim,而是由你自己去实现。我的实现方式是我只在 Sandbox 时候,去创建 containerd-shim-v2,而接下来整个后面的 container 层的操作,会全部走到这个 containerd-shim-v2 里面,去重用这个 Sandbox,所以这个跟前面的时间就出现很大的不同。


image.png


所以你现在去总结一下这个图的话,你发现我们实现方式是变成这个样子:

首先,你还是用原来的 CRI Containerd,只不过现在装的是 runC,你现在再装一个 kata container 放在那机器上面。接下来我们 Kata 那边会给你写一个实现叫 kata-Containerd-Shimv2。


现在,我们只聚焦在怎么去把 Containerd 对接在 kata container 上面,就是所谓的实现 Shimv2 API,这是我们要做的工作。而具体到我们这要做的事情上,其实它就是这样一系列与run一个容器相关的 API。比如说我可以去 create、start,这些操作全部映射在我 Shimv2 上面去实现,而不是说我现在考虑怎么去映射,去实现 CRI,这个自由度由于之前太大,造成了我们现在的一个局面,就有一堆 CRI Shim 可以用。这其实是一个不好的事情。有很多政治原因,有很多非技术原因,这都不是我们作为技术人员应该关心的事情,你现在只需要想我怎么去跟 Shimv2 对接就好了。


给 Kubernetes 提供 kata-runtime


通过直接创建 Container 可以使用 kata-runtime 。但在集群中,我们该如何告诉 Kubernetes 哪些负载需要使用 kata-runtime 呢?根据不同的版本,Kata 提供了不同的方式。1.以 CentOS 操作系统为例,安装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 之后,执行检测命令:


$ 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 的方式

这种方式对相关组件版本有要求:

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 配置文件中,增加如下内容:


[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 关键字。


  • 使用 untrusted_workload_runtime 的方式


对于不符合上述版本要求的环境,可以使用之前的方式。在配置文件中新增如下内容:


[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 方式


  • 创建 RuntimeClass


kind: RuntimeClass
apiVersion: node.k8s.io/v1beta1
metadata:
  name: kata-containers
handler: kata


也可以为 runc 创建 RuntimeClass


$ kubectl get runtimeclass
NAME              CREATED AT
kata-containers   2020-08-30


  • 创建负载 kata-pod.yaml


apiVersion: v1
kind: Pod
metadata:
  name: kata-nginx
spec:
  runtimeClassName: kata-containers
  containers:
  - name: nginx
    image: nginx
    ports:
    - containerPort: 80


执行创建:


$ 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


执行创建:


$ kubectl apply -f kata-pod-untrusted.yaml


查看负载:


$ kata-runtime list


总结


Kubernetes 现在的核心设计思想,就是通过接口化和插件化,将原本复杂的、对主干代码有侵入性的特性,逐一从核心库中剥离和解耦。而在这个过程中,CRI 就是 Kubernetes 项目中最早完成了插件化的一个调用接口。这里主要为你介绍了在CRI基础上的另一种集成容器运行时的思路,即:CRI + containerd shimv2 的方式。


  • 通过这种方式,你就不需要再为自己的容器运行时专门编写一个 CRI 实现(CRI shim),而是可以直接重用 containerd对 CRI 的支持能力,然后通过 containerd shimv2的方式来对接具体的容器运行时(比如 runc)。


  • 这种集成方式已经成为了社区对接下层容器运行时的主流思路,像很多类似于 KataContainers,gVisor,Firecracker 等基于独立内核或者虚拟化的容器项目,也都开始通过 shimv2 ,进而借助 containerd项目无缝接入到 Kubernetes 当中。
相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
16天前
|
监控 Docker 容器
在Docker容器中运行打包好的应用程序
在Docker容器中运行打包好的应用程序
|
4月前
|
存储 消息中间件 容器
当一个 Pod 中包含多个容器时,容器间共享一些重要的资源和环境,这使得它们能够更有效地协同工作和交互。
当一个 Pod 中包含多个容器时,容器间共享一些重要的资源和环境,这使得它们能够更有效地协同工作和交互。
|
16天前
|
存储 Prometheus 监控
Docker容器内进行应用调试与故障排除的方法与技巧,包括使用日志、进入容器检查、利用监控工具及检查配置等,旨在帮助用户有效应对应用部署中的挑战,确保应用稳定运行
本文深入探讨了在Docker容器内进行应用调试与故障排除的方法与技巧,包括使用日志、进入容器检查、利用监控工具及检查配置等,旨在帮助用户有效应对应用部署中的挑战,确保应用稳定运行。
27 5
|
16天前
|
开发框架 安全 开发者
Docker 是一种容器化技术,支持开发者将应用及其依赖打包成容器,在不同平台运行而无需修改。
Docker 是一种容器化技术,支持开发者将应用及其依赖打包成容器,在不同平台运行而无需修改。本文探讨了 Docker 在多平台应用构建与部署中的作用,包括环境一致性、依赖管理、快速构建等优势,以及部署流程和注意事项,展示了 Docker 如何简化开发与部署过程,提高效率和可移植性。
40 4
|
2月前
|
Kubernetes 监控 Cloud Native
|
2月前
|
存储 监控 Shell
docker的底层原理二:容器运行时环境
本文深入探讨了Docker容器运行时环境的关键技术,包括命名空间、控制组、联合文件系统、容器运行时以及分离的进程树,这些技术共同确保了容器的隔离性、资源控制和可移植性。
45 5
|
2月前
|
安全 Docker 容器
Docker中运行容器时Operation not permitted报错问题解决
【10月更文挑战第2天】Docker中运行容器时Operation not permitted报错问题解决
555 3
|
2月前
|
Kubernetes Docker 容器
容器运行时Containerd k8s
容器运行时Containerd k8s
47 3
|
3月前
|
Kubernetes API Docker
跟着iLogtail学习容器运行时与K8s下日志采集方案
iLogtail 作为开源可观测数据采集器,对 Kubernetes 环境下日志采集有着非常好的支持,本文跟随 iLogtail 的脚步,了解容器运行时与 K8s 下日志数据采集原理。
|
3月前
|
存储 Docker 容器
containerd容器运行时快速入门使用指南
关于containerd容器运行时的快速入门使用指南,涵盖了镜像管理、容器管理、NameSpace管理、数据持久化、镜像推送至Harbor仓库以及Docker与Containerd集成等内容。
243 1
containerd容器运行时快速入门使用指南