当前位置:首页 > 经验 >

pod调度原理(pod调度使用法则)

来源:原点资讯(www.yd166.com)时间:2022-11-04 17:53:18作者:YD166手机阅读>>

1.用户删除相关 PVC。

2.External Provisioner 组件观察到 PVC 删除事件,根据 PVC 的回收策略(Reclaim)执行不同操作:

  • Delete:调用外部 CSI 插件DeleteVolume 函数以删除卷;一旦卷成功删除,Provisioner会删除集群中对应 PV 对象。
  • Retain:Provisioner不执行卷删除操作。
CSI Sidecar 组件介绍

为使 K8s 适配 CSI 标准,社区将与 K8s 相关的存储流程逻辑放在了 CSI Sidecar 组件中。

1. Node Driver Registrar

1)功能

Node-Driver-Registrar 组件会将外部 CSI 插件注册到Kubelet,从而使Kubelet通过特定的 Unix Domain Socket 来调用外部 CSI 插件函数(Kubelet 会调用外部 CSI 插件的 NodeGetInfo、NodeStageVolume、NodePublishVolume、NodeGetVolumeStats 等函数)。

2)原理

Node-Driver-Registrar 组件通过Kubelet 外部插件注册机制实现注册,注册成功后:

  • Kubelet为本节点 Node 资源打 annotation:Kubelet调用外部 CSI 插件NodeGetInfo 函数,其返回值 [nodeID]、[driverName] 将作为值用于 "csi.volume.kubernetes.io/nodeid" 键。
  • Kubelet更新 Node Label:将NodeGetInfo 函数返回的 [AccessibleTopology] 值用于节点的 Label。
  • Kubelet更新 Node Status:将NodeGetInfo 函数返回的 maxAttachLimit(节点最大可挂载卷数量)更新到 Node 资源的 Status.Allocatable:attachable-volumes-csi-[driverName]=[maxAttachLimit]。

pod调度原理,pod调度使用法则(13)

  • Kubelet更新 CSINode 资源(没有则创建):将 [driverName]、[nodeID]、[maxAttachLimit]、[AccessibleTopology] 更新到 Spec 中(拓扑仅保留 Key 值)。

2. External Provisioner

1)功能

创建/删除实际的存储卷,以及代表存储卷的 PV 资源。

2)原理

External-Provisioner在启动时需指定参数 -- provisioner,该参数指定 Provisioner 名称,与 StorageClass 中的 provisioner 字段对应。

External-Provisioner启动后会 watch 集群中的 PVC 和 PV 资源。

对于集群中的 PVC 资源:

  • 判断 PVC 是否需要动态创建存储卷,标准如下:PVC 的 annotation 中是否包含 "volume.beta.kubernetes.io/storage-provisioner" 键(由卷控制器创建),并且其值是否与 Provisioner 名称相等。PVC 对应 StorageClass 的 VolumeBindingMode 字段若为 WaitForFirstConsumer,则 PVC 的 annotation 中必须包含 "volume.kubernetes.io/selected-node" 键(详见调度器如何处理 WaitForFirstConsumer),且其值不为空;若为 Immediate 则表示需要 Provisioner 立即提供动态存储卷。
  • 通过特定的 Unix Domain Socket 调用外部 CSI 插件CreateVolume 函数
  • 创建 PV 资源,PV 名称为 [Provisioner 指定的 PV 前缀] - [PVC uuid]。

对于集群中的 PV 资源:

  • 判断 PV 是否需要删除,标准如下:判断其 .Status.Phase 是否为 Release。判断其 .Spec.PersistentVolumeReclaimPolicy 是否为 Delete。判断其是否包含 annotation(pv.kubernetes.io/provisioned-by),且其值是否为自己。
  • 通过特定的 Unix Domain Socket 调用外部 CSI 插件DeleteVolume 接口
  • 删除集群中的 PV 资源。

3. External Attacher

1)功能

挂接/摘除存储卷。

2)原理

External-Attacher 内部会时刻 watch 集群中的 VolumeAttachment 资源和 PersistentVolume 资源。

对于 VolumeAttachment 资源:

  • 从 VolumeAttachment 资源中获得 PV 的所有信息,如 volume ID、node ID、挂载 Secret 等。
  • 判断 VolumeAttachment 的 DeletionTimestamp 字段是否为空来判断其为卷挂接或卷摘除:若为卷挂接则通过特定的 Unix Domain Socket 调用外部 CSI 插件ControllerPublishVolume 接口;若为卷摘除则通过特定的 Unix Domain Socket 调用外部 CSI 插件ControllerUnpublishVolume 接口

对于 PersistentVolume 资源:

  • 在挂接时为相关 PV 打上 Finalizer:external-attacher/[driver 名称]。
  • 当 PV 处于删除状态时(DeletionTimestamp 非空),删除 Finalizer:external-attacher/[driver 名称]。

4. External Resizer

1)功能

扩容存储卷。

2)原理

External-Resizer内部会 watch 集群中的 PersistentVolumeClaim 资源。

对于 PersistentVolumeClaim 资源:

  • 判断 PersistentVolumeClaim 资源是否需要扩容:PVC 状态需要是 Bound 且 .Status.Capacity 与 .Spec.Resources.Requests 不等。
  • 更新 PVC 的 .Status.Conditions,表明此时处于 Resizing 状态。
  • 通过特定的 Unix Domain Socket 调用外部 CSI 插件ControllerExpandVolume 接口
  • 更新 PV 的 .Spec.Capacity。
  • 若 CSI 支持文件系统在线扩容,ControllerExpandVolume 接口返回值中 NodeExpansionRequired 字段为 true,External-Resizer更新 PVC 的 .Status.Conditions 为 FileSystemResizePending 状态;若不支持则扩容成功,External-Resizer更新 PVC 的 .Status.Conditions 为空,且更新 PVC 的 .Status.Capacity。

Volume Manager(Kubelet 组件)观察到存储卷需在线扩容,于是通过特定的 Unix Domain Socket 调用外部 CSI 插件NodeExpandVolume 接口实现文件系统扩容。

5. livenessprobe

1)功能

检查 CSI 插件是否正常。

2)原理

通过对外暴露一个 / healthz HTTP 端口以服务 kubelet 的探针探测器,内部是通过特定的 Unix Domain Socket 调用外部 CSI 插件Probe 接口

CSI 接口介绍

三方存储厂商需实现 CSI 插件的三大接口:IdentityServer、ControllerServer、NodeServer

1. IdentityServer

IdentityServer 主要用于认证 CSI 插件的身份信息。

// IdentityServer is the server API for Identity service. type IdentityServer interface { // 获取CSI插件的信息,比如名称、版本号 GetPluginInfo(context.Context, *GetPluginInfoRequest) (*GetPluginInfoResponse, error) // 获取CSI插件提供的能力,比如是否提供ControllerService能力 GetPluginCapabilities(context.Context, *GetPluginCapabilitiesRequest) (*GetPluginCapabilitiesResponse, error) // 获取CSI插件健康状况 Probe(context.Context, *ProbeRequest) (*ProbeResponse, error) }

2. ControllerServer

ControllerServer 主要负责存储卷及快照的创建/删除以及挂接/摘除操作。

// ControllerServer is the server API for Controller service. type ControllerServer interface { // 创建存储卷 CreateVolume(context.Context, *CreateVolumeRequest) (*CreateVolumeResponse, error) // 删除存储卷 DeleteVolume(context.Context, *DeleteVolumeRequest) (*DeleteVolumeResponse, error) // 挂接存储卷到特定节点 ControllerPublishVolume(context.Context, *ControllerPublishVolumeRequest) (*ControllerPublishVolumeResponse, error) // 从特定节点摘除存储卷 ControllerUnpublishVolume(context.Context, *ControllerUnpublishVolumeRequest) (*ControllerUnpublishVolumeResponse, error) // 验证存储卷能力是否满足要求,比如是否支持跨节点多读多写 ValidateVolumeCapabilities(context.Context, *ValidateVolumeCapabilitiesRequest) (*ValidateVolumeCapabilitiesResponse, error) // 列举全部存储卷信息 ListVolumes(context.Context, *ListVolumesRequest) (*ListVolumesResponse, error) // 获取存储资源池可用空间大小 GetCapacity(context.Context, *GetCapacityRequest) (*GetCapacityResponse, error) // 获取ControllerServer支持功能点,比如是否支持快照能力 ControllerGetCapabilities(context.Context, *ControllerGetCapabilitiesRequest) (*ControllerGetCapabilitiesResponse, error) // 创建快照 CreateSnapshot(context.Context, *CreateSnapshotRequest) (*CreateSnapshotResponse, error) // 删除快照 DeleteSnapshot(context.Context, *DeleteSnapshotRequest) (*DeleteSnapshotResponse, error) // 获取所有快照信息 ListSnapshots(context.Context, *ListSnapshotsRequest) (*ListSnapshotsResponse, error) // 扩容存储卷 ControllerExpandVolume(context.Context, *ControllerExpandVolumeRequest) (*ControllerExpandVolumeResponse, error) }

3. NodeServer

NodeServer 主要负责存储卷挂载/卸载操作。

// NodeServer is the server API for Node service. type NodeServer interface { // 将存储卷格式化并挂载至临时全局目录 NodeStageVolume(context.Context, *NodeStageVolumeRequest) (*NodeStageVolumeResponse, error) // 将存储卷从临时全局目录卸载 NodeUnstageVolume(context.Context, *NodeUnstageVolumeRequest) (*NodeUnstageVolumeResponse, error) // 将存储卷从临时目录bind-mount到目标目录 NodePublishVolume(context.Context, *NodePublishVolumeRequest) (*NodePublishVolumeResponse, error) // 将存储卷从目标目录卸载 NodeUnpublishVolume(context.Context, *NodeUnpublishVolumeRequest) (*NodeUnpublishVolumeResponse, error) // 获取存储卷的容量信息 NodeGetVolumeStats(context.Context, *NodeGetVolumeStatsRequest) (*NodeGetVolumeStatsResponse, error) // 存储卷扩容 NodeExpandVolume(context.Context, *NodeExpandVolumeRequest) (*NodeExpandVolumeResponse, error) // 获取NodeServer支持功能点,比如是否支持获取存储卷容量信息 NodeGetCapabilities(context.Context, *NodeGetCapabilitiesRequest) (*NodeGetCapabilitiesResponse, error) // 获取CSI节点信息,比如最大支持卷个数 NodeGetInfo(context.Context, *NodeGetInfoRequest) (*NodeGetInfoResponse, error) }K8s CSI API 对象

K8s 为支持 CSI 标准,包含如下 API 对象:

  • CSINode
  • CSIDriver
  • VolumeAttachment

1. CSINode

apiVersion: storage.k8s.io/v1beta1 kind: CSINode metadata: name: node-10.212.101.210 spec: drivers: - name: yodaplugin.csi.alibabacloud.com nodeID: node-10.212.101.210 topologyKeys: - kubernetes.io/hostname - name: pangu.csi.alibabacloud.com nodeID: a5441fd9013042ee8104a674e4a9666a topologyKeys: - topology.pangu.csi.alibabacloud.com/zone

作用:

  1. 判断外部 CSI 插件是否注册成功。在 Node Driver Registrar 组件向 Kubelet 注册完毕后,Kubelet 会创建该资源,故不需要显式创建 CSINode 资源。
  2. 将 Kubernetes 中 Node 资源名称与三方存储系统中节点名称(nodeID)一一对应。此处Kubelet会调用外部 CSI 插件NodeServer 的 GetNodeInfo 函数获取 nodeID。
  3. 显示卷拓扑信息。CSINode 中 topologyKeys 用来表示存储节点的拓扑信息,卷拓扑信息会使得Scheduler在 Pod 调度时选择合适的存储节点。

2. CSIDriver

apiVersion: storage.k8s.io/v1beta1 kind: CSIDriver metadata: name: pangu.csi.alibabacloud.com spec: # 插件是否支持卷挂接(VolumeAttach) attachRequired: true # Mount阶段是否CSI插件需要Pod信息 podInfoOnMount: true # 指定CSI支持的卷模式 volumeLifecycleModes: - Persistent

作用:

  1. 简化外部 CSI 插件的发现。由集群管理员创建,通过 kubectl get csidriver 即可得知环境上有哪些 CSI 插件。
  2. 自定 义Kubernetes 行为,如一些外部 CSI 插件不需要执行卷挂接(VolumeAttach)操作,则可以设置 .spec.attachRequired 为 false。

3. VolumeAttachment

apiVersion: storage.k8s.io/v1 kind: VolumeAttachment metadata: annotations: csi.alpha.kubernetes.io/node-id: 21481ae252a2457f9abcb86a3d02ba05 finalizers: - external-attacher/pangu-csi-alibabacloud-com name: csi-0996e5e9459e1ccc1b3a7aba07df4ef7301c8e283d99eabc1b69626b119ce750 spec: attacher: pangu.csi.alibabacloud.com nodeName: node-10.212.101.241 source: persistentVolumeName: pangu-39aa24e7-8877-11eb-b02f-021234350de1 status: attached: true

作用:VolumeAttachment 记录了存储卷的挂接/摘除信息以及节点信息。

支持特性

1. 拓扑支持

在 StorageClass 中有 AllowedTopologies 字段:

apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: csi-pangu provisioner: pangu.csi.alibabacloud.com parameters: type: cloud_ssd volumeBindingMode: Immediate allowedTopologies: - matchLabelExpressions: - key: topology.pangu.csi.alibabacloud.com/zone values: - zone-1 - zone-2

外部 CSI 插件部署后会为每个节点打标,打标内容NodeGetInfo 函数返回的 [AccessibleTopology] 值(详见 Node Driver Registrar 部分)。

External Provisioner在调用 CSI 插件的 CreateVolume 接口之前,会在请求参数设置 AccessibilityRequirements:

  • 对于 WaitForFirstConsumer当 PVC 的 anno 中包含 "volume.kubernetes.io/selected-node" 且不为空,则先获取对应节点 CSINode 的 TopologyKeys,然后根据该 TopologyKeys 键从 Node 资源的 Label 获取 Values 值,最后拿该 Values 值与 StorageClass 的 AllowedTopologies 比对,判断其是否包含于其中;若不包含则报错。
  • 对于 Immediately将 StorageClass 的 AllowedTopologies 的值填进来,若 StorageClass 没有设置 AllowedTopologies 则将所有包含 TopologyKeys 键的节点 Value 添进来。

Scheduler 如何处理使用存储卷调度

基于社区 1.18 版本调度器

调度器的调度过程主要有如下三步:

  • 预选(Filter):筛选满足 Pod 调度要求的节点列表。
  • 优选(Score):通过内部的优选算法为节点打分,获得最高分数的节点即为选中的节点。
  • 绑定(Bind):调度器将调度结果通知给 kube-apiserver,更新 Pod 的 .spec.nodeName 字段。

调度器预选阶段:处理 Pod 的 PVC/PV 绑定关系以及动态供应 PV(Dynamic Provisioning),同时使调度器调度时考虑 Pod 所使用 PV 的节点亲和性。详细调度过程如下:

  1. Pod 不包含 PVC 直接跳过。
  2. FindPodVolumes获取 Pod 的 boundClaims、claimsToBind 以及 unboundClaimsImmediate。boundClaims:已 Bound 的 PVCclaimsToBind:PVC 对应 StorageClass 的 VolumeBindingMode 为 VolumeBindingWaitForFirstConsumerunboundClaimsImmediate:PVC 对应 StorageClass 的 VolumeBindingMode 为 VolumeBindingImmediate若 len(unboundClaimsImmediate) 不为空,表示这种 PVC 需要立即绑定 PV(即存 PVC 创建后,立刻动态创建 PV 并将其绑定到 PVC,该过程不走调度),若 PVC 处于 unbound 阶段则报错。若 len(boundClaims) 不为空,则检查 PVC 对应 PV 的节点亲和性与当前节点的 Label 是否冲突,若冲突则报错(可检查 Immediate 类型的 PV 拓扑)。若 len(claimsToBind) 不为空先检查环境中已有的 PV 能否与该 PVC 匹配(findMatchingVolumes),将能够匹配 PVC 的 PV 记录在调度器的 cache 中。未匹配到 PV 的 PVC 走动态调度流程,动态调度主要通过 StorageClass 的 AllowedTopologies 字段判断当前调度节点是否满足拓扑要求(针对 WaitForFirstConsumer 类型的 PVC)。

调度器优选阶段不讨论。

调度器 Assume 阶段

调度器会先 Assume PV/PVC,再 Assume Pod。

  1. 将当前待调度的 Pod 进行深拷贝。
  2. AssumePodVolumes(针对 WaitForFirstConsumer 类型的 PVC)更改调度器 cache 中已经 Match 的 PV 信息:设置 annotation:pv.kubernetes.io/bound-by-controller="yes"。更改调度器 cache 中未匹配到 PV 的 PVC,设置 annotation:volume.kubernetes.io/selected-node=【所选节点】。
  3. Assume Pod 完毕更改调度器 cache 中 Pod 的 .Spec.NodeName 为【所选节点】。

调度器 Bind 阶段

BindPodVolumes:

  • 调用 Kubernetes 的 API 更新集群中 PV/PVC 资源,使其与调度器 Cache 中的 PV/PVC 一致。
  • 检查 PV/PVC 状态:检查所有 PVC 是否已处于 Bound 状态。检查所有 PV 的 NodeAffinity 是否与节点 Label 冲突。
  • 调度器执行 Bind 操作:调用 Kubernetes 的 API 更新 Pod 的 .Spec.NodeName 字段。

2. 存储卷扩容

存储卷扩容部分在 External Resizer 部分已提到,故不再赘述。用户只需要编辑 PVC 的 .Spec.Resources.Requests.Storage 字段即可,注意只可扩容不可缩容。

若 PV 扩容失败,此时 PVC 无法重新编辑 spec 字段的 storage 为原来的值(只可扩容不可缩容)。

3. 单节点卷数量限制

卷数量限制在 Node Driver Registrar 部分已提到,故不再赘述。

4. 存储卷监控

存储商需实现 CSI 插件的 NodeGetVolumeStats 接口,Kubelet 会调用该函数,并反映在其 metrics上:

  • kubelet_volume_stats_capacity_bytes:存储卷容量
  • kubelet_volume_stats_used_bytes:存储卷已使用容量
  • kubelet_volume_stats_available_bytes:存储卷可使用容量
  • kubelet_volume_stats_inodes:存储卷 inode 总量
  • kubelet_volume_stats_inodes_used:存储卷 inode 使用量
  • kubelet_volume_stats_inodes_free:存储卷 inode 剩余量

5. Secret

CSI 存储卷支持传入 Secret 来处理不同流程中所需要的私密数据,目前 StorageClass 支持如下 Parameter:

  • csi.storage.k8s.io/provisioner-secret-name
  • csi.storage.k8s.io/provisioner-secret-namespace
  • csi.storage.k8s.io/controller-publish-secret-name
  • csi.storage.k8s.io/controller-publish-secret-namespace
  • csi.storage.k8s.io/node-stage-secret-name
  • csi.storage.k8s.io/node-stage-secret-namespace
  • csi.storage.k8s.io/node-publish-secret-name
  • csi.storage.k8s.io/node-publish-secret-namespace
  • csi.storage.k8s.io/controller-expand-secret-name
  • csi.storage.k8s.io/controller-expand-secret-namespace

Secret 会包含在对应 CSI 接口的参数中,如对于 CreateVolume 接口而言则包含在 CreateVolumeRequest.Secrets 中。

6. 块设备

apiVersion: apps/v1 kind: StatefulSet metadata: name: nginx-example spec: selector: matchLabels: app: nginx serviceName: "nginx" volumeClaimTemplates: - metadata: name: html spec: accessModes: - ReadWriteOnce volumeMode: Block storageClassName: csi-pangu resources: requests: storage: 40Gi template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx volumeDevices: - devicePath: "/dev/vdb" name: html

三方存储厂商需实现 NodePublishVolume 接口。Kubernetes 提供了针对块设备的工具包("k8s.io/kubernetes/pkg/util/mount"),在 NodePublishVolume 阶段可调用该工具的 EnsureBlock 和 MountBlock 函数。

7. 卷快照/卷克隆能力

鉴于本文篇幅,此处不做过多原理性介绍。读者感兴趣见官方介绍:卷快照、卷克隆。

总结

本文首先对 CSI 核心流程进行了大体介绍,并结合 CSI Sidecar 组件、CSI 接口、API 对象对 CSI 标准进行了深度解析。在 K8s 上,使用任何一种 CSI 存储卷都离不开上面的流程,环境上的容器存储问题也一定是其中某个环节出现了问题。本文对其流程进行梳理,以便于广大程序猿(媛)排查环境问题。

作者 | 惠志

本文为阿里云原创内容,未经允许不得转载。

栏目热文

什么是pod网络(pod的网络模式)

什么是pod网络(pod的网络模式)

作者 | Aholiab责编 | Carol出品 | CSDN(ID:CSDNnews)封图|CSDN下载自视觉中国云原...

2022-11-04 18:22:53查看全文 >>

pod启动过程(pod调度失败怎么解决)

pod启动过程(pod调度失败怎么解决)

在上一章节,有一个问题一直没有解决[qq@k8snode1 ~]$ kubectl get pod -n dev NAM...

2022-11-04 18:06:18查看全文 >>

什么叫pod结构(pod的组成部分)

什么叫pod结构(pod的组成部分)

IT ___ InformationTechnology 信息技术POP ___ Procedure-Oriented ...

2022-11-04 18:20:20查看全文 >>

常见的pod控制器有哪些(pol控制器的作用)

常见的pod控制器有哪些(pol控制器的作用)

我们已经可以实现通过手工执行kubectl scale命令实现Pod扩容或缩容,但是这显然不符合Kubernetes的定...

2022-11-04 17:56:56查看全文 >>

pod测试原理(pod的原理)

pod测试原理(pod的原理)

本章节主要学习Flannel网络是如何通信,从而深刻理解从内部到外部,从外部到内部的资源访问。一、container-c...

2022-11-04 18:18:43查看全文 >>

pod命令怎么生成的(pod之间怎样通信的)

pod命令怎么生成的(pod之间怎样通信的)

pod生命周期我们一般将pod对象从创建致终的这段时间范围称为pod的生命周期,它主要包含下面的过程:pod创建过程运行...

2022-11-04 18:01:10查看全文 >>

pod电路分析(poe供电电路原理图)

pod电路分析(poe供电电路原理图)

由IEEE制定的新型单对以太网(SPE)或10BASE-T1L物理层标准,为传输设备运行状况信息实施状态监测(CbM)应...

2022-11-04 18:02:23查看全文 >>

pod和sod的区别(pod的作用)

pod和sod的区别(pod的作用)

近年来国家对农药的管控力度越来越强,无论在政策导引、还是食品安全上,绿色健康的农药成分以及使用方式越来越受推崇,这给生物...

2022-11-04 18:12:39查看全文 >>

pod网络是什么(什么是pod数据中心)

pod网络是什么(什么是pod数据中心)

前言Pods是可以在Kubernetes中创建和管理的最小的可部署计算单元。Pod 是一组(一个或多个)容器(例如 Do...

2022-11-04 18:30:05查看全文 >>

pod工作原理(pod的组成部分)

pod工作原理(pod的组成部分)

1. 核心组件原理 —— pod 核心原理1.1 pod 是什么pod 也可以理解是一个容器,装的是 docker 创建...

2022-11-04 18:19:49查看全文 >>

文档排行