Kubernetes 容器运行时(CRI)

kubernetes各个组件

Master

Master 是整个集群的大脑,所有的编排、调度、API 访问等都由 Master 来负责

  • etcd 保存了整个集群的状态
  • kube-apiserver 提供了资源操作的唯一入口,并提供认证、授权、访问控制、API
  • 注册和发现等机制。并且无论是集群内部还是外部的组件,都必须通过API Server来访问数据
  • kube-controller-manager 负责维护集群的状态,包括很多资源的控制器,是保证 Kubernetes 声明式 API工作的大脑,比如故障检测、自动扩展、滚动更新等
  • kube-scheduler 负责资源的调度,按照预定的调度策略将 Pod 调度到相应的 Node 上

Node

负责运行具体的容器,并为容器提供存储、网络等必要的功能

  • kubelet 负责维持容器的生命周期,同时也负责 Volume(CSI)和网络(CNI)的管理
  • Container runtime 负责镜像管理以及 Pod 和容器的真正运行。Kubelet 默认的容器运行时为 Docker
  • kube-proxy 负责为 Service 提供 cluster 内部的服务发现和负载均衡
  • Network plugin 也就基于 CNI(Container Network Internface)负责为容器配置网络

扩展

  • 扩展(Addon),比如 dashboard、EFK、Prometheus、各种 Operator 等,这些扩展不需要 Kubernetes 提供标准的接口,但是都为 Kubernetes 增加了新的功能特性
  • 插件(Plugin),比如 CNI、CRI、CSI、Device Plugin 等,这些都是 Kubernetes 各个核心组件提供了标准的内置接口,而外部插件则是实现这些接口,从而将 Kubernetes 扩展到更多的用例场景中

Kubelet中的CRI

img

  • Kubelet Server 对外提供 API,供 kube-apiserver、metrics-server 等服务调用。比如 kubectl exec 需要通过 Kubelet API /exec/{token} 与容器进行交互。
  • Container Manager 管理容器的各种资源,比如 cgroups、QoS、cpuset、device 等。
    Volume Manager 管理容器的存储卷,比如格式化磁盘、挂载到 Node 本地、最后再将挂载路径传给容器。
  • Eviction 负责容器的驱逐,比如在资源不足时驱逐优先级低的容器,保证高优先级容器的运行。
  • cAdvisor 负责为容器提供 metrics 数据源。
  • Metrics 和 stats 提供容器和节点的度量数据,比如 metrics-server 通过 /stats/summary 提取的度量数据是 HPA 自动扩展的依据。
  • 再向下就是 Generic Runtime Manager,这是容器运行时的管理者,负责跟 CRI 交互,完成容器和镜像的管理。
  • 在 CRI 之下,包括两种容器运行时的实现
    一个是内置的 dockershim,实现了 docker 容器引擎的支持以及 CNI 网络插件(包括 kubenet)的支持
    另一个就是外部的容器运行时,用来支持 runc、containerd、gvisor 等外部容器运行时。

Kubernetes 中的容器运行时按照不同的功能就可以分为三个部分:

  1. Kubelet 中容器运行时的管理模块 Generic Runtime Manager,它通过 CRI 来管理容器和镜像。
  2. 容器运行时接口,是 Kubelet 与外部容器运行时的通信接口。
  3. 容器运行时实现,包括 Kubelet 内置的 dockershim 以及外部的容器运行时(如 cri-o、cri-containerd 等)

容器运行时接口(CRI)

容器运行时接口(CRI),顾名思义,用来在 Kubernetes 扩展容器运行时,从而用户可以选择自己喜欢的容器引擎。

CRI 接口

CRI 是基于 gPRC 的,用户不需要关心内部通信逻辑,而只需要实现定义的接口就可以,包括 RuntimeService 和 ImageService: RuntimeService负责管理Pod和容器的生命周期,而ImageService负责镜像的生命周期管理
img

  • 管理镜像的 ImageService 提供了 5 个接口,分别是查询镜像列表、拉取镜像到本地、查询镜像状态、删除本地镜像以及查询镜像占用空间等。这些都很容易映射到 docker API 或者 CLI 上面。

  • 而 RuntimeService 则提供了更多的接口,按照功能可以划分为四组:

  1. PodSandbox 的管理接口:PodSandbox 是对 Kubernete Pod 的抽象,用来给容器提供一个隔离的环境(比如挂载到相同的 cgroup 下面),并提供网络等共享的命名空间。PodSandbox 通常对应到一个 Pause 容器或者一台虚拟机。
  2. Container 的管理接口:在指定的 PodSandbox 中创建、启动、停止和删除容器。
  3. Streaming API 接口:包括 Exec、Attach 和 PortForward 等三个和容器进行数据交互的接口,这三个接口返回的是运行时 Streaming Server 的 URL,而不是直接跟容器交互。
  4. 状态接口,包括查询 API 版本和查询运行时状态。

Streaming API

Streaming API 用于客户端与容器需要交互的场景,所以采用的是流式接口,包括 Exec、PortForward 和 Attach 等。Kubelet 内置的 docker 通过 nsenter、socat 等方法来支持这些特性,但它们不一定适用于其他的运行时。因而,CRI 也显式定义了这些 API,并且要求容器运行时返回一个 streaming server 的 URL 以便 Kubelet 重定向 API Server 发送过来的流式请求。
img

这样一个完整的 Exec 流程就是

  • 客户端 kubectl exec -i -t …
  1. kube-apiserver 向 Kubelet 发送流式请求 /exec/
  2. Kubelet 通过 CRI 接口向 CRI Shim 请求 Exec 的 URL
  3. CRI Shim 向 Kubelet 返回 Exec URL
  4. Kubelet 向 kube-apiserver 返回重定向的响应
  5. kube-apiserver 重定向流式请求到 Exec URL,接着就是 CRI Shim 内部的 Streaming Server 跟 kube-apiserver 进行数据交互,完成 Exec 的请求和响应

参考

参考链接1