一文读懂容器存储接口 CSI

简介: 在《一文读懂 K8s 持久化存储流程》一文我们重点介绍了 K8s 内部的存储流程,以及 PV、PVC、StorageClass、Kubelet 等之间的调用关系。接下来本文将将重点放在 CSI(Container Storage Interface)容器存储接口上,探究什么是 CSI 及其内部工作原理。

头图.png

作者 | 惠志
来源 | 阿里巴巴云原生公众号

导读:在《一文读懂 K8s 持久化存储流程》一文我们重点介绍了 K8s 内部的存储流程,以及 PV、PVC、StorageClass、Kubelet 等之间的调用关系。接下来本文将将重点放在 CSI(Container Storage Interface)容器存储接口上,探究什么是 CSI 及其内部工作原理。

背景

K8s 原生支持一些存储类型的 PV,如 iSCSI、NFS、CephFS 等等(详见链接),这些 in-tree 类型的存储代码放在 Kubernetes 代码仓库中。这里带来的问题是 K8s 代码与三方存储厂商的代码强耦合

  • 更改 in-tree 类型的存储代码,用户必须更新 K8s 组件,成本较高
  • in-tree 存储代码中的 bug 会引发 K8s 组件不稳定
  • K8s 社区需要负责维护及测试 in-tree 类型的存储功能
  • in-tree 存储插件享有与 K8s 核心组件同等的特权,存在安全隐患
  • 三方存储开发者必须遵循 K8s 社区的规则开发 in-tree 类型存储代码

CSI 容器存储接口标准的出现解决了上述问题,将三方存储代码与 K8s 代码解耦,使得三方存储厂商研发人员只需实现 CSI 接口(无需关注容器平台是 K8s 还是 Swarm 等)。

CSI 核心流程介绍

在详细介绍 CSI 组件及其接口之前,我们先对 K8s 中 CSI 存储流程进行一个介绍。《一文读懂 K8s 持久化存储流程》一文介绍了 K8s 中的 Pod 在挂载存储卷时需经历三个的阶段:Provision/Delete(创盘/删盘)、Attach/Detach(挂接/摘除)和 Mount/Unmount(挂载/卸载),下面以图文的方式讲解 K8s 在这三个阶段使用 CSI 的流程。

1. Provisioning Volumes

1.jpg

1.集群管理员创建 StorageClass 资源,该 StorageClass 中包含 CSI 插件名称(provisioner:pangu.csi.alibabacloud.com)以及存储类必须的参数(parameters: type=cloud_ssd)。sc.yaml 文件如下:

2.png

2.用户创建 PersistentVolumeClaim 资源,PVC 指定存储大小及 StorageClass(如上)。pvc.yaml 文件如下:

3.png

3.卷控制器(PersistentVolumeController)观察到集群中新创建的 PVC 没有与之匹配的 PV,且其使用的存储类型为 out-of-tree,于是为 PVC 打 annotation:volume.beta.kubernetes.io/storage-provisioner=[out-of-tree CSI 插件名称](本例中即为 provisioner:pangu.csi.alibabacloud.com)。

4.External Provisioner 组件观察到 PVC 的 annotation 中包含 "volume.beta.kubernetes.io/storage-provisioner" 且其 value 是自己,于是开始创盘流程。

  • 获取相关 StorageClass 资源并从中获取参数(本例中 parameters 为  type=cloud_ssd),用于后面 CSI 函数调用。
  • 通过 unix domain socket 调用外部 CSI 插件CreateVolume 函数

5.外部 CSI 插件返回成功后表示盘创建完成,此时External Provisioner 组件会在集群创建一个 PersistentVolume 资源。

6.卷控制器会将 PV 与 PVC 进行绑定。

4.png

2. Attaching Volumes

5.jpg

1.AD 控制器(AttachDetachController)观察到使用 CSI 类型 PV 的 Pod 被调度到某一节点,此时AD 控制器会调用内部 in-tree CSI 插件(csiAttacher)的 Attach 函数。

2.内部 in-tree CSI 插件(csiAttacher)会创建一个 VolumeAttachment 对象到集群中。

3.External Attacher 观察到该 VolumeAttachment 对象,并调用外部 CSI插件ControllerPublish 函数以将卷挂接到对应节点上。外部 CSI 插件挂载成功后,External Attacher会更新相关 VolumeAttachment 对象的 .Status.Attached 为 true。

6.png

4.AD 控制器内部 in-tree CSI 插件(csiAttacher)观察到 VolumeAttachment 对象的 .Status.Attached 设置为 true,于是更新AD 控制器内部状态(ActualStateOfWorld),该状态会显示在 Node 资源的 .Status.VolumesAttached 上。

7.png

3. Mounting Volumes

8.jpg

1.Volume Manager(Kubelet 组件)观察到有新的使用 CSI 类型 PV 的 Pod 调度到本节点上,于是调用内部 in-tree CSI 插件(csiAttacher)的 WaitForAttach 函数。

2.内部 in-tree CSI 插件(csiAttacher)等待集群中 VolumeAttachment 对象状态 .Status.Attached 变为 true。

3.in-tree CSI 插件(csiAttacher)调用 MountDevice 函数,该函数内部通过 unix domain socket 调用外部 CSI 插件NodeStageVolume 函数;之后插件(csiAttacher)调用内部 in-tree CSI 插件(csiMountMgr)的 SetUp 函数,该函数内部会通过 unix domain socket 调用外部 CSI 插件NodePublishVolume 函数

4. Unmounting Volumes

9.jpg

1.用户删除相关 Pod。

2.Volume Manager(Kubelet 组件)观察到包含 CSI 存储卷的 Pod 被删除,于是调用内部 in-tree CSI 插件(csiMountMgr)的 TearDown 函数,该函数内部会通过 unix domain socket 调用外部 CSI 插件的 NodeUnpublishVolume 函数

3.Volume Manager(Kubelet 组件)调用内部 in-tree CSI 插件(csiAttacher)的 UnmountDevice 函数,该函数内部会通过 unix domain socket 调用外部 CSI 插件的 NodeUnpublishVolume 函数

5. Detaching Volumes

10.jpg

1.AD 控制器观察到包含 CSI 存储卷的 Pod 被删除,此时该控制器会调用内部 in-tree CSI 插件(csiAttacher)的 Detach 函数。

2.csiAttacher会删除集群中相关 VolumeAttachment 对象(但由于存在 finalizer,va 对象不会立即删除)。

3.External Attacher观察到集群中 VolumeAttachment 对象的 DeletionTimestamp 非空,于是调用外部 CSI 插件ControllerUnpublish 函数以将卷从对应节点上摘除。外部 CSI 插件摘除成功后,External Attacher会移除相关 VolumeAttachment 对象的 finalizer 字段,此时 VolumeAttachment 对象被彻底删除。

4.AD 控制器内部 in-tree CSI 插件(csiAttacher)观察到 VolumeAttachment 对象已删除,于是更新AD 控制器中的内部状态;同时AD 控制器更新 Node 资源,此时 Node 资源的 .Status.VolumesAttached 上已没有相关挂接信息。

6. Deleting Volumes

11.jpg

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]。

12.png

  • 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.comnodeID: node-10.212.101.210topologyKeys:- kubernetes.io/hostname- name: pangu.csi.alibabacloud.comnodeID: a5441fd9013042ee8104a674e4a9666atopologyKeys:- 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: 21481ae252a2457f9abcb86a3d02ba05finalizers:- external-attacher/pangu-csi-alibabacloud-comname: csi-0996e5e9459e1ccc1b3a7aba07df4ef7301c8e283d99eabc1b69626b119ce750
spec:attacher: pangu.csi.alibabacloud.comnodeName: node-10.212.101.241source: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/zonevalues:- 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 的 PVC
      • claimsToBind:PVC 对应 StorageClass 的 VolumeBindingMode 为 VolumeBindingWaitForFirstConsumer
      • unboundClaimsImmediate: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 为原来的值(只可扩容不可缩容)。参考 K8s 官网提供的 PVC 还原方法:
https://kubernetes.io/docs/concepts/storage/persistent-volumes/#recovering-from-failure-when-expanding-volumes

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: nginxserviceName: "nginx"volumeClaimTemplates:- metadata:name: htmlspec:accessModes:- ReadWriteOncevolumeMode: BlockstorageClassName: csi-panguresources:requests:storage: 40Gitemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginxvolumeDevices:- 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 存储卷都离不开上面的流程,环境上的容器存储问题也一定是其中某个环节出现了问题。本文对其流程进行梳理,以便于广大程序猿(媛)排查环境问题。

原文链接

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/513834.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot Admin2.0 集成 Java 诊断神器 Arthas 实践

简介: 项目最初使用 Arthas 主要有两个目的: 1. 通过 arthas 解决实现测试环境、性能测试环境以及生产环境性能问题分析工具的问题。 2. 通过使用 jad、mc、redefine 功能组合实现生产环境部分节点代码热更新的能力。 作者 | sparrow 来源 | 阿里巴巴云原…

python在办公上的应用_python自动化办公:玩转word之样式秘笈

上节对python如何定制word的页眉页脚做了详细介绍,当然,要作出一篇精彩的word文档,样式公布可没,本章继续介绍python如何玩转word的样式。 使用样式python如何玩转word的样式 此页面使用前一页中开发的概念而不作介绍。如果术语不…

Gartner发布2021年隐私技术成熟度曲线,数字伦理登上顶点

编辑 | 宋慧 供稿 | Gartner 随着人们日益意识到其个人信息的价值并对透明度的缺乏和持续的滥用感到失望,数字伦理登上了Gartner 2021年隐私技术成熟度曲线的顶点。 Gartner将数字伦理定义为人、企业机构和物之间开展电子交互所遵循的价值和伦理道德原则体系。随着…

微服务+异步工作流+ Serverless,Netflix 决定弃用稳定运行 7 年的旧平台

简介: 2021 年,Netflix 会将大部分的工作负载从 Reloaded 转移到 Cosmos 平台。Cosmos 是一个计算平台,它将微服务的最佳特性与异步工作流以及 Serverless 结合在一起。 作者 | Frank San Miguel 策划 | 田晓旭 2021 年,Netflix …

实时 OLAP, 从 0 到 1

简介: BTC.com 团队在实时 OLAP 方面的技术演进过程及生产优化实践。 作者|高正炎 本文主要介绍 BTC.com 团队在实时 OLAP 方面的技术演进过程及生产优化实践,内容如下: 业务背景机遇挑战架构演进架构优化未来展望一、业务背景 …

Gartner发布2021年数字商务技术成熟度曲线,重点关注四项技术

应用领导人应密切关注可视化配置、数字钱包、客户身份和访问管理以及虚拟客户助理这四项将在未来两年对数字商务产生重大影响的技术。 编辑 | 宋慧 供稿 | Gartner 根据Gartner 2021年数字商务技术成熟度曲线(Hype Cycle for Digital Commerce)&#x…

鸿蒙手机系统还没有开发,华为鸿蒙手机太难了!引发开发者大吐槽:为何没有自己独特风格?-互联网/电商-文章-小虾米...

【华为鸿蒙手机太难了!引发开发者大吐槽:为何没有自己独特风格?】互联网/电商-文章-小虾米2020-12-27 11:32:02 小虾米帐号:军事科技(tabc) 关注我 举报 来源:qq新闻 浏览量(129)【12月28日讯】导语&#xff0c…

Fluid给数据弹性一双隐形的翅膀 (1) -- 自定义弹性伸缩

简介: 弹性伸缩作为Kubernetes的核心能力之一,但它一直是围绕这无状态的应用负载展开。而Fluid提供了分布式缓存的弹性伸缩能力,可以灵活扩充和收缩数据缓存。 它基于Runtime提供了缓存空间、现有缓存比例等性能指标, 结合自身对于Runtime资源…

利用 Python 实现多任务进程

来源:杰哥的IT之旅作者:阿拉斯加一、进程介绍 进程:正在执行的程序,由程序、数据和进程控制块组成,是正在执行的程序,程序的一次执行过程,是资源调度的基本单位。程序:没有执行的代码…

小白也能懂的 Nacos 服务模型介绍

简介: 理解了 Nacos 的服务模型,也有利于我们了解 Nacos 背后的工作原理,从而确保我们正确地使用 Nacos。 作者:岛风 前言 按照目前市场上的主流使用场景,Nacos 被分成了两块功能:服务注册发现&#xff0…

那些与 IE 相伴的日子

来源:零一作者:前端印象大家好,IE 大家都不陌生,毕竟出现在大家的视野中已经很久很久,久到有20多年,当然也因前端技术的快速更新,给需要兼容IE浏览器的前端程序员带来了不少的困扰。慢慢地&…

html代码style图片width,HTML Style columnWidth用法及代码示例

DOM中的columnWidth属性用于指定列的宽度。用法:返回columnWidth属性:object.style.columnWidth设置columnWidth属性:object.style.columnWidth "auto | length | initial | inherit"属性值:auto:缺省值。列宽将由浏览器确定lengt…

KubeVela 1.0 :开启可编程式应用平台的未来

简介: 如果你对云原生领域不太关注,可能对 KubeVela 还没有做过太深入的了解。别着急,本文就借着 v1.0 发布之际,为你详细的梳理一次 KubeVela 项目的发展脉络,解读它的核心思想和愿景,领悟这个正冉冉升起的…

android-x86 镜像iso下载_2019年微软MSDN原版镜像系统下载地址 Win10/7原版系统iso镜像文件...

如今,不少用户开始讨厌以GHOST形式来安装操作系统,虽然步骤十分简单,但是从网上下载的GHOST系统,已经形成了一个黑色产业链,为了盈利,捆绑了软件全家桶、恶意强制主页,甚至捆绑木马,…

大流量场景下如何云淡风轻地进行线上发布?

简介: 本文介绍了微服务治理下金丝雀发布的能力,解决了发布期间少量流量验证新功能的问题。 前言 本文,我们继续聊聊《揭秘大流量场景下发布如丝般顺滑背后的原因》中的另外一环,灰度发布,也叫金丝雀发布。 ​ 很多互…

匿名提问:rm -rf了怎么办?

整理 | 易璜珵出品 | 《新程序员》IT界流传着一个神秘的代码,老程序员听了总是意味深长地一笑,而新手程序员则总是手痒地想试试,那就是删库指令rm -rf。这一行代码下去,海量数据可能就荡然无存。近几年发生的“删库跑路”事件让这…

ubuntu matlab_有没有人和我一起整理Python的matlab代替

想找人一起整理Python中matlab代替的包,最好是能够将常用功能用tkinter封装起来,积少成多,逐步逼近完整。比如将scipy中的最小二乘法拟合功能,找个图形界面封装一下,就变成了曲线拟合工具,可以代替matlab的…

逸仙电商Seata企业级落地实践

简介: 本文将会以逸仙电商的业务作为背景, 先介绍一下seata的原理, 并给大家进行线上演示, 由浅入深去介绍这款中间件, 以便读者更加容易去理解 Seata 这个中间件。 作者 | 张嘉伟(GitHub ID:l…

“类云”的存储服务什么样?Pure Storage发布Pure Fusion等系列新品

一键部署自动化存储平台与云原生数据库即服务,无缝连接基础设施运营与应用程序。 编辑 | 宋慧 出品 | CSDN 云计算 近日,专为多云环境提供存储即服务的Pure Storage发布一系列现代化基础设施、运营及应用程序,这是Pure Storage迈向创新现代…

mac mongodb可视化工具_MongoDB从立地到成佛(介绍、安装、增删改查)

文章作者公众号bigsai,已收录在回车课堂,如有帮助还请不吝啬点个赞赞支持一下!课程导学大家好我是bigsai,我们都学过数据库,但你可能更熟悉关系(型)数据库例如MySQL,SQL SERVER,ORACLE等,对于非…