csi-provisioner到底做了什么

1,841 阅读5分钟

介绍

  在《CSI插件注册》中提到容器存储接口(CSI)为外部存储接入云原生Kubernetes提供了标准化的注册方案,而作为CSI中的重要成员csi-provisioner,在其中发挥着重要的作用。在CSI Plugin注册完成之后,csi-driver作为服务端对外提供标准的存储服务,其中包括卷创建、删除,容量获取,插件能力获取等。csi-provisioner作为客户端,通过GRPC方式与CSI插件进行交互,最终与远端存储服务器完成对接。
  本文主要讲解csi-provisioner的基本原理,以及在整个CSI环节中发挥的作用。不管是刚接触Kubernetes存储的初学者,还是想要着手进行CSI插件开发的同学,通过本文对csi-provisioner的介绍都能有所收获。

csi-provisioner.png

原理

  全篇基于csi-provisioner的v3.0版本,主要由三个控制器(Controller)组成,分别是ProvisionController、CapacityController和CloningProtectionController,它们监听PersistentVolumeClaim(PVC)、PersistentVolume(PV)、StorgaeClass、CSINode等资源,及时处理资源变更。

  • ProvisionController是核心控制器,主要职责是为PVC创建或删除PV并与CSI插件交互创建并删除存储资源。
  • CapacityController的职责是对存储的容量进行管理,并创建CSIStorageCapacity资源供Kubernetes Pod调度使用。
  • CloningProtectionController负责克隆存储卷场景下对PVC进行保护,及时添加或删除CloneFinalizer标记。

作用

ProvisionController控制器

动态供应

  Kubernetes中PV的供应有2种方式,动态供应和静态供应。

  • 静态供应指用户需要手动在存储服务器上创建存储卷,然后需要创建一个PV资源显示存储卷相关的信息,最后再创建一个PVC与PV进行绑定后,才能供pod进行使用。
  • 动态供应,即用户无需关心PV资源创建以及存储服务器上的存储卷创建,ProvisionController根据StorageClass资源中parameters信息以及PVC的请求容量,自动创建PV资源。   通过动态供应的方式,能大大降低用户创建PVC的效率。实质上ProvisionController在进行自动供应时,必须完成CreateVolume和DeleteVolume的2个接口调用,一方面ProvisionController需要维护PVC和PV的资源状态,另一方面还需要与csi-plugin进行存储资源的新建与删除。

provisionController.png

存储拓扑管理

  ProvisionController存储拓扑管理,本质是对CSINode资源进行整合,用于创建存储卷的节点调度。该功能需要Kubernetes 1.17版本以上支持,并且需要在csi-provisioner上开启特性--feature-gates=Topology=True,同时需要插件支持PluginCapability_Service_VOLUME_ACCESSIBILITY_CONSTRAINTS能力。在《CSI插件注册》中有讲到CSI插件最终会生成CSINode资源,并在node资源上添加annotation——csi.volume.kubernetes.io/nodeid
  此时,ProvisionController将在调用CreateVolume接口时,将根据CSINode和Node资源进行整合,生成可调度的节点拓扑,设置在AccessibilityRequirements参数中。如果PVC上存在annotation——volume.kubernetes.io/selected-node,并且该值在节点拓扑中存在,则节点拓扑中只存在一个可被调度的节点。如果selected-node值不存在,则pod在进行调度时,将调度失败。最终,插件会将调度的节点信息nodeAffinity生成在PV中,如下所示:

apiVersion: v1
kind: PersistentVolume
metadata:
  finalizers:
  - kubernetes.io/pv-protection
  name: pv-test
spec:
  accessModes:
  - ReadWriteOnce
  、、、、、、
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - <nodeName>

In-tree插件与Out-tree插件转义

  目前,In-tree插件中driverName为以下名称,才允许被转义。In-tree插件被转义前必须满足2个条件,一是需要Kubernetes 1.17版本以上,二是在创建PVC时添加annotation——pv.kubernetes.io/migrated-to: <driverName>

// In-tree driverName
// gce_pd
pd.csi.storage.gke.io
// aws_ebs
ebs.csi.aws.com
// openstack_cinder
cinder.csi.openstack.org
// azure_disk
disk.csi.azure.com
// azure_file
file.csi.azure.com
// vsphere_volume
csi.vsphere.vmware.com

  ProvisionController转义In-tree插件的实质,是将早期的内置插件逻辑转移至外部插件。主要表现在,一是将StorageClass资源中的parameters参数转义成能被外部插件认可的参数,能完成外部插件中的CreateVolume和DeleteVolume接口调用;其二,将PV资源中csi参数转义成内部插件的参数,防止被内部插件修改;最后,在删除存储卷时,将PV中内部插件的参数转义成csi参数,以便外部插件完成DeleteVolume操作。
  以vSphere_volume存储为例:

StorageClass: parameters

In-treeOut-tree
fstypecsi.storage.k8s.io/fstype
storagepolicynamestoragepolicyname
datastoredatastore-migrationparam
diskformatdatastore-migrationparam
hostfailurestotoleratehostfailurestotolerate-migrationparam
forceprovisioningforceprovisioning-migrationparam
cachereservationcachereservation-migrationparam
diskstripesdiskstripes-migrationparam
objectspacereservationobjectspacereservation-migrationparam
iopslimitiopslimit-migrationparam
csimigration

PersistentVolume: csi => vsphereVolume

csivsphereVolume
fstypefstype
initialvolumefilepathvolumePath

PersistentVolume: vsphereVolume => csi

vsphereVolumecsi
driver
fstypefstype
volumePathvolumeHandle
storagePolicyNamevolumeAttributes.storagePolicyName

CapacityController控制器

容量管理

  CapacityController是在Kubernetes 1.19版本引入的控制器,主要通过CSIStorageCapacity管理存储总容量,

  • 控制器完成PV创建操作后,CapacityController更新CSIStorageCapacity消耗容量;
  • 控制器完成PV删除操作后,CapacityController更新CSIStorageCapacity释放空闲容量。

CapacityController.png

  开启容量管理,需要在csi-provisioner启动时,添加命令参数--enable-capacity=true,注入环境变量NAMESPACEPOD_NAME(csi-provisioner的pod名称和分区)。容量不足时,用户可以先通过CSIStorageCapacity资源查看剩余容量,避免创建PVC后出现Pending的情况。

CloningProtectionController控制器

克隆finalizer管理

  ProvisionController在克隆存储卷时,会对dataSource指向的PVC设置克隆保护。

  finalizers:
  - provisioner.storage.kubernetes.io/cloning-protection

  之后,CloningProtectionController会监听克隆保护的PVC,发现目标PVC已完成克隆操作,则会删除克隆finalizer成员。这样可以避免PVC在进行克隆卷创建时,出现源PVC被删除的情况。克隆卷PVC定义如下,前提是csi-plugin需要支持克隆能力(ControllerServiceCapability_RPC_CLONE_VOLUME)。

spec:
  dataSource:
    kind: PersistentVolumeClaim
    name: <source PVC>

总结

  csi-provisioner实质是多个控制器的集成,通过与csi-plugin交互,管理Kubernetes中存储相关的资源。所以,csi-provisioner离不开csi-plugin,特别是在进行csi-plugin探究过程中,了解清楚csi-provisioner的作用,有利于csi-plugin顺利开发。