为Kubernetes选择合适的容器运行时

【前言】作为后台支撑,Kubernetes优势明显,具有自动化部署、服务伸缩、故障自我修复、负载均衡等特性。我们目前的系统的后台支撑大量使用了Kubernetes,不同的系统对于数据的安全性及运行效率也各不一样,因此如何选择合适容器运行时成为了一个重点考虑的问题。

CRI与OCI

CRI的由来

请添加图片描述

CRI(Container Runtime Interface)是Kubernetes提出的容器运行时接口规范。

在Kubernetes体系中,是由Kubelet组件负责与容器运行时交互的。Kubelet调用容器运行时的流程如上图所示。CRI shim是实现CRI接口的gRPC server服务,负责连接Kubelet和Container runtime,Container runtime是容器运行时工具,它为用户进程隔离出一个独立的运行环境;具体的流程是Kubelet调用CRI shim接口,CRI shim响应请求,然后调用底层的Container runtime工具运行容器。Kubelet、CRI shim和Container runtime都部署在一个Kubernetes worker节点上,前两者是以独立的守护进程的方式启动的,而Container runtime不是守护进程,它通常是一个命令行工具。

Kubernetes在v1.5版本之前是没有CRI接口的,那时Kubelet源码内部只集成了两个容器运行时(Docker和rkt)的相关代码。这两种容器运行时并不能满足所有用户的使用需求,在某些业务场景,用户对容器的安全隔离性有着更高的需求,用户希望Kubernetes能支持更多种类的容器运行时。因此,Kubernetes在1.5版本推出了CRI接口,各个容器运行时只要实现了CRI接口规范,就可以接入到Kubernetes平台为用户提供容器服务。

CRI接口带来的好处,首先它很好的将Kubernetes和容器运行时解耦,容器运行时的每次更新迭代,都不必对Kubelet工程源码进行编译发布;其次解放了容器运行时更新迭代的步伐,也能保证Kubernetes的代码质量和平台的稳定。

CRI接口定义

CRI接口分为两部分,一个是容器运行时服务RuntimeService,负责管理pod和容器的生命周期;一个是镜像服务ImageService,负责管理镜像的生命周期。
请添加图片描述

OCI是什么

OCI规范(Open Container Initiative 开放容器标准),该规范包含两部分内容:容器运行时标准(runtime spec)、容器镜像标准(image spec)。其具体内容的定义如下图:
请添加图片描述

Kubelet CRI架构

Kubernetes在引入CRI之后,Kubelet的架构如下图所示:
请添加图片描述

每一个容器引擎只需要自己实现一个CRI shim,对CRI请求进行处理,就可以接入Kubelet当中去。

我们所说的容器运行时,准确来说包含两部分,一部分是上层容器运行时CRI shim(即容器运行时管理程序,如Containerd、CRI-O),另一部分是下层容器运行时Container runtime(即容器运行时命令工具,如runc、runv,kata)。

当前CRI格局

目前实现了CRI的主流项目有:docker、containerd、CRI-O、Frakti、pouch,它们衔接Kubelet与运行时方式对比如下:

请添加图片描述

PS:由于rkt容器引擎目前未能完全兼容OCI规范,所以图中未将其包含进来。

当前OCI格局

下表是兼容OCI规范的容器运行时项目:
请添加图片描述

Kubernetes多运行时

为什么要支持多运行时呢?举个例子,有一个开放的云平台向外部用户提供容器服务,平台上运行有两种容器,一种是云平台管理用的容器(可信的),一种是用户部署的业务容器(不可信)。在这种场景下,我们希望使用runc运行可信容器(弱隔离但性能好),用runv运行不可信容器(强隔离安全性好)。面对这种需求,Kubernetes也给出了解决方案。

以前,多容器运行时通常以注解(Annotation)的形式支持,比如 cri-o、frakti 等都是这么支持了多容器运行时。但这一点也不优雅,并且也无法实现基于容器运行时来调度容器。因而,Kubernetes 在 v1.12 中开始增加 RuntimeClass 这个新的 API 对象,用来支持多容器运行时。

RuntimeClass 表示一个运行时,在使用前需要开启特性开关 RuntimeClass,并创建 RuntimeClass CRD:

kubectl apply -f https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/runtimeclass/runtimeclass_crd.yaml

然后就可以定义 RuntimeClass 对象

apiVersion: node.k8s.io/v1alpha1  # RuntimeClass is defined in the node.k8s.io API group
kind: RuntimeClass
metadata:
  name: myclass  # The name the RuntimeClass will be referenced by
  # RuntimeClass is a non-namespaced resource
spec:
  runtimeHandler: myconfiguration  # The name of the corresponding CRI configuration

接着,就可以在 Pod 中定义使用哪个 RuntimeClass:

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  runtimeClassName: myclass
  # ...

选择合适的容器运行时

在生产环境中,我们并不需要docker的镜像打包、容器网络、文件挂载、swarm等这些能力,只需要部署Containerd + runc就可以在node节点上运行pod。因此在生产环境中我们可以不安装docker,而是安装CRI shim组件和运行时工具来运行pod。在多个CRI shim和OCI工具之间,我们该如何选择呢?

首先对比Containerd和CRI-O调用runc的方式,runc代码内置在Containerd内部,通过函数调用;CRI-O是通过linux命令方式调用runc二进制文件,显然前者属于进程内的函数调用,在性能上Containerd更具优势。其次对比runc和runv,这是两种完全不同的容器技术,runc创建的容器进程直接运行在宿主机内核上,而runv是运行在由Hypervisor虚拟出来的虚拟机上,后者占用的资源更多、启动速度慢,而且runv容器在调用底层硬件时(如CPU),中间多了一层虚拟硬件层,计算效率上不如runc容器。最后对比runv和kata,两者都在专用内核中运行,提供网络、I/O 和内存的隔离,Kata Container 是两个现有的开源项目合并:Intel Clear Containers和Hyper runV。Kata Containers是轻量级虚拟机的容器,旨在将虚拟机(VM)的安全优势与容器的速度和可管理性统一起来,即安全,性能也高

*因此建议结合自身业务特点、以及使用场景选择合适的容器运行时。在对用户的隔离没有很高诉求的情况下,可以优先考虑使用性能更好更轻量的Containerd + runc;在隔离性要求较高的业务场景下,推荐使用Containerd+Kata。*

Kata存在的问题

Kata 不支持 host 网络。而 Kubernetes 中,etcd、nodelocaldns、kube-apiserver、kube-scheduler、metrics-server、node-exporter、kube-proxy、calico、kube-controller-manager 等,也就是 Static Pod 和 Daemonset 都会使用 host 网络。所以在安装部署时,依然使用 runc 作为默认的运行时,而将 kata-runtime 作为可选的运行时给特定的负载使用。

参考:https://cloud.tencent.com/developer/article/1730700

答:k8s官方给出了host网络使用的条件,大多数情况下我们用不到host网络,在k8s初始化时将runc作为默认容器运行时命令工具,在启动不受信任的应用容器时,手动指定kata runtime作为容器运行时命令工具:

  • 除非绝对必要,否则不要为 Pod 指定hostPort。 将 Pod 绑定到hostPort时,它会限制 Pod 可以调度的位置数,因为每个<hostIP, hostPort, protocol>组合必须是唯一的。 如果您没有明确指定hostIPprotocol,Kubernetes 将使用0.0.0.0作为默认hostIPTCP作为默认protocol

如果您只需要访问端口以进行调试,则可以使用 apiserver proxykubectl port-forward

如果您明确需要在节点上公开 Pod 的端口,请在使用 hostPort 之前考虑使用 NodePort 服务。

  • 避免使用hostNetwork,原因与hostPort相同。

参考:https://kubernetes.io/zh/docs/concepts/configuration/overview/

总结

在生产环境中,可以使用container+runc/kata双容器运行时命令工具的配置,具体为runc为默认工具供系统应用使用,kata为手动配置工具供不受信任的第三方应用使用。

下一篇介绍,如何在 Kubernetes 集群中集成 Kata

猜你喜欢

转载自blog.csdn.net/qq_26356861/article/details/125764564