K8S 的架构

像大多数的分布式系统,K8S 集群至少需要一个主节点 Master 和多个计算节点 Node

k8s架构图

Master(控制节点)

由三个紧密协作的独立组件组合而成

  • 负责 API 服务的 kube-apiserver
  • 负责调度的 kube-scheduler
  • 负责容器编排的 kube-controller-manager
    整个集群的持久化数据,则由 kube-apiserver 处理后保存在 Etcd
Node(计算节点)

最核心的是 kubelet 的组件,具备以下功能

  • 负责同容器运行时(比如 Docker 项目)打交道。而这个交互所依赖的,是一个称作 CRI(Container Runtime Interface)的远程调用接口,这个接口定义了容器运行时的各项核心操作
  • 通过 gRPC 协议同一个叫作 Device Plugin 的插件进行交互。这个插件,是 K8S 项目用来管理 GPU 等宿主机物理设备的主要组件
  • 调用网络插件和存储插件为容器配置网络和持久化存储。这两个插件与 kubelet 进行交互的接口,分别是 CNI(Container Networking Interface)CSI(Container Storage Interface)

补充:K8S 项目并不关心你部署的是什么容器运行时、使用的什么技术实现,只要你的这个容器运行时能够运行标准的容器镜像,它就可以通过实现 CRI 接入到 K8S 项目当中;而具体的容器运行时,比如 Docker 项目,则一般通过 OCI 这个容器运行时规范同底层的 Linux 操作系统进行交互,即:把 CRI 请求翻译成对 Linux 操作系统的调用(操作 Linux Namespace 和 Cgroups 等)

Prometheus、Metrics Server 与 K8S 监控体系

Prometheus 项目工作的核心,是使用 Pull (抓取)的方式去搜集被监控对象的 Metrics 数据(监控指标数据),然后,再把这些数据保存在一个 TSDB (时间序列数据库,比如 OpenTSDB、InfluxDB 等)当中,以便后续可以按照时间进行检索;其主要的特点如下:

  • 多维度的数据模型:由指标名称和键 / 值对标签标识的时间序列数据来组成多维的数据模型。
  • 灵活的查询语言:在 Prometheus 中使用强大的查询语言 PromSQL 来进行查询。
  • 不依赖分布式存储,Prometheus 单个节点也可以直接工作,支持本地存储(TSDB)和远程存储的模式。
  • 服务端采集数据:Prometheus 基于 HTTP pull 方式去对不同的端采集时间序列数据。
  • 客户端主动推送:支持通过 PushGateway 组件主动推送时间序列数据。

Prometheus 作用和工作方式,如下图
Prometheus 作用和工作方式

Prometheus 剩下的组件就是用来配合这套机制的运行

  • Prometheus Server:Prometheus 服务端,用于收集指标和存储时间序列数据,并提供一系列的查询和设置接口。

  • Client Libraries客户端库,用于帮助需要监控采集的服务暴露 metrics handler 给 Prometheus server,直接调用 promhttp 暴露了一个 metrics 接口。

  • Push Gateway:推送网关,Prometheus 服务端仅支持 HTTP pull 的采集方式,而有一些指存在的时间短,Prometheus 来 pull 前就结束了。又或是该类指标,就是要客户端自行上报的,这时候就可以采用 Push Gateway 的方式,客户端将指标 push 到 Push Gateway,再由 Prometheus Server 从 Pushgateway 上 pull

  • Exporters:用于暴露已有的第三方服务的 metrics 给 Prometheus Server

  • Alertmanager:可以根据 Metrics 信息灵活地设置报警,从 Prometheus server 端接收到 alerts 后,会进行去重,分组,然后路由到对应的 Receiver,发出报警

  • Grafana:对外暴露出的、可以灵活配置的监控数据可视化界面

按照 Metrics 数据的来源,来对 K8S 的监控体系做一个汇总:

  • 第一种 Metrics,是宿主机的监控数据。这部分数据的提供,需要借助一个由 Prometheus 维护的Node Exporter 工具
  • 第二种 Metrics,是来自于 Kubernetes 的 API Server、kubelet 等组件的 /metrics API。除了常规的 CPU、内存的信息外,这部分信息还主要包括了各个组件的核心监控指标。比如,对于 API Server 来说,它就会在 /metrics API 里,暴露出各个 Controller 的工作队列
  • 第三种 Metrics,是 Kubernetes 相关的监控数据。这部分数据,一般叫作 Kubernetes 核心监控数据(core metrics)。这其中包括了 Pod、Node、容器、Service 等主要 Kubernetes 核心概念的 Metrics。

其中,容器相关的 Metrics 主要来自于 kubelet 内置的 cAdvisor 服务。在 kubelet 启动后,cAdvisor 服务也随之启动,而它能够提供的信息,可以细化到每一个容器的 CPU 、文件系统、内存、网络等资源的使用情况。

需要注意的是,这里提到的 Kubernetes 核心监控数据,其实使用的是 Kubernetes 的一个非常重要的扩展能力,叫作 Metrics Server

声明式 API 和 K8S 控制器

声明式 API

是 Kubernetes 项目编排能力“赖以生存”的核心所在

  • 首先,所谓“声明式”,指的就是我只需要提交一个定义好的 API 对象来“声明”,我所期望的状态是什么样子
  • 其次,“声明式 API”允许有多个 API 写端,以 PATCH 的方式对 API 对象进行修改,而无需关心本地原始 YAML 文件的内容
  • 最后,也是最重要的,有了上述两个能力,Kubernetes 项目才可以基于对 API 对象的增、删、改、查,在完全无需外界干预的情况下,完成对“实际状态”和“期望状态”的调谐(Reconcile)过程

实际运用项目:

Istio 项目使用的,是 K8S 中的一个非常重要的功能,叫作 Dynamic Admission Control(动态入场控制),也叫作:Initializer(初始化器)。提供了一种“热插拔”式的 Admission 机制

Kubernetes 控制器

GPU 在容器云中的方案及使用

GPU 在容器云中的方案及使用
核心功能模块:

  • GPU Share Scheduler Extender: 利用 Kubernetes 的调度器扩展机制,负责在全局调度器 Filter 和 Bind 的时候判断节点上单个 GPU 卡是否能够提供足够的 GPU Mem,并且在 Bind 的时刻将 GPU 的分配结果通过 annotation 记录到 Pod Spec 以供后续 Filter 检查分配结果。
  • GPU Share Device Plugin: 利用 Device Plugin 机制,在节点上被 Kubelet 调用负责 GPU 卡的分配,依赖 scheduler Extender 分配结果执行。

具体流程:

  1. 资源上报
    GPU Share Device Plugin利用nvml库查询到GPU卡的数量和每张GPU卡的显存, 通过 ListAndWatch() 将节点的GPU总显存(数量 显存)作为另外 Extended Resource 汇报给 Kubelet; Kubelet 进一步汇报给 Kubernetes API Server

  2. 扩展调度
    GPU Share Scheduler Extender 可以在分配 gpu-mem 给 Pod 的同时将分配信息以 annotation 的形式保留在 Pod spec 中,并且在过滤时刻根据此信息判断每张卡是否包含足够可用的 gpu-mem 分配。

  3. 节点上运行
    当Pod和节点绑定的事件被Kubelet接收到后,Kubelet就会在节点上创建真正的Pod实体,在这个过程中, Kubelet会调用GPU Share Device Plugin的 Allocate 方法, Allocate 方法的参数是Pod申请的gpu-mem。而在 Allocate 方法中,会根据GPU Share Scheduler Extender的调度决策运行对应的Pod