容器与 Kubernetes

在早期 Kubernetes 利用 Docker 作为容器运行时实现,直接调用 Docker API 来创建和管理容器。在 Docker 盛行之后,CoreOS 推出了 rkt 运行时实现,Kubernetes 又实现了对 rkt 的支持,随着容器技术的蓬勃发展,越来越多运行时实现出现,Kubernetes 要重新考虑对所有容器运行时的兼容适配问题了。

7.7.1 CRI in Kubernetes

Kubernetes 从 1.5 版本开始,在遵循 OCI 基础上,将容器操作抽象为一个接口,该接口作为 Kubelet 与运行时实现对接的桥梁,Kubelet 通过发送接口请求对容器进行启动和管理,各个容器运行时只要实现这个接口就可以接入 Kubernetes。

这个接口就是 Kubernetes 容器运行时接口: CRI(Container Runtime Interface)。

1. 容器运行时交互接口 CRI

CRI(Container Runtime Interface,容器运行时接口)是 Kubernetes 定义的一组与容器运行时进行交互的接口,用于将 Kubernetes 平台与特定容器实现解耦,建立业界容器编排对接的标准规范。

CRI 是一套通过 Protocol Buffer 定义的 API,如下图:

从上图可以看出:CRI 主要有 gRPC client、gRPC Server 和具体容器运行时实现三个组件。其中 Kubelet 作为 gRPC Client 调用 CRI 接口,CRI shim 作为 gRPC Server 来响应 CRI 请求,并负责将 CRI 请求内容转换为具体的运行时管理操作。

因此,任何容器运行时实现想要接入 Kubernetes,都需要实现一个基于 CRI 接口规范的 CRI shim(gRPC Server)。由于容器运行时与镜像的生命周期是彼此隔离的,因此 CRI 主要定义了两类接口:

  • RuntimeService 定义跟容器相关的操作,如创建、启动、删除容器等。
  • ImageService 定义容器镜像相关的操作,如拉取镜像、删除镜像等。

至此之后,Kubernetes 创建容器流程为: Kubernetes 通过调度制定一个具体的节点运行 Pod,该节点的 Kubelet 在接收到 pod 创建请求后, 调用 GenericRuntime 的通用组件发起创建 Pod 的 CRI 请求给 CRI shim, CRI shim 在收到 CRI 请求后,将其转换为具体的容器运行时指令,并调用相应的容器运行时来创建 Pod,最后将处理结果返回给 Kubelet。

7.7.2 Docker 与 Kubernetes

Kubernetes 提出 CRI 操作规范时,Docker 刚拆出 containerd,并不支持 CRI 标准。但由于 Docker 是当时容器技术主流存在,Kuberentes 虽然提出了 CRI 接口规范,仍然需要去适配 CRI 与 Docker 的对接,因此它需要一个中间层或 shim(垫片) 来对接 Kubelet 和 Docker 运行时实现。

于是 kubelet 中加入了 Dockershim,当 Docker 作为容器运行时,Kubernetes 内启动一个容器流程如下图所示:

在这个阶段 Kubelet 的代码和 dockershim 都是放在一个 Repo

这也就意味着 Dockershim 是由 Kubernetes 进行组织开发和维护!由于 Docker 的版本发布 Kubernetes 无法控制和管理,所以每次 Docker 发布新的 Release,Kubernetes 都要集中精力去快速地更新维护 Dockershim。同时如果 Docker 仅作为 runtime 实现也过于庞大,Kubernetes 弃用 Dockershim 有了足够的理由和动力。

Kubernetes 弃用 Dockershim

Kubernetes1.24 版本正式删除和弃用 dockershim。

这件事情的本质是废弃了内置的 dockershim 功能,直接对接 containerd(后续已经支持 CRI)。从 containerd 1.0 开始,为了能够减少一层调用的开销,containerd 开发了一个新的 daemon,叫做 CRI-Containerd,直接与 containerd 通信,从而取代了 dockershim。

从 Kubernetes 角度看,选择 containerd 作为运行时的组件,它调用链更短,组件更少,更稳定,占用节点资源更少。

7.7.3 使用多运行时 RuntimeClass

RuntimeClass 是 v1.12 引入的新 API 对象,用来支持多容器运行时,比如

  • Kata Containers/gVisor + runc
  • Windows Process isolation + Hyper-V isolation containers

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


 

小结

梳理完 CRI 的发展关系后,总结 kubelet 调用 各容器运行时 关系如下图所示:


  • 无标签
写评论...