一、简介
StorageClass (存储类)为管理员提供了描述存储”类”的方法。不同的类型可能会映射到不同的服务质量等级或备份策略,或者由集群管理员制定的任意策略。Kubernetes本身并不清楚各种类代表的是什么,这个类的概念在其他存储系统中有时被称为”配置文件”。
二、StorageClass资源
每个 StorageClass 都包含 provisioner、parameters 和 reclaimPolicy 字段, 这些字段会在 StorageClass 需要动态制备 PersistentVolume 时会使用到。
StorageClass 对象的命名很重要,用户使用这个命名来请求生成一个特定的类。 当创建 StorageClass 对象时,管理员设置 StorageClass 对象的命名和其他参数。
管理员可以为没有申请绑定到特定 StorageClass 的 PVC 指定一个默认的存储类:
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: standard provisioner: kubernetes.io/aws-ebs parameters: type: gp2 reclaimPolicy: Retain allowVolumeExpansion: true mountOptions: - debug volumeBindingMode: Immediate
三、默认StorageClass
当一个 PVC 没有指定 storageClassName 时,会使用默认的 StorageClass。 集群中只能有一个默认的 StorageClass。如果不小心设置了多个默认的 StorageClass, 当 PVC 动态配置时,将使用最新设置的默认 StorageClass。某些云服务提供商可能已经定义了一个默认的 StorageClass。
四、存储制备器
每个 StorageClass 都有一个制备器(Provisioner),用来决定使用哪个卷插件制备 PV。 该字段必须指定。
卷插件 | 内置制备器 | 配置示例 |
AzureFile | ✓ | Azure File |
CephFS | – | – |
FC | – | – |
FlexVolume | – | – |
GCEPersistentDisk | ✓ | GCE PD |
iSCSI | – | – |
NFS | – | NFS |
RBD | ✓ | Ceph RBD |
VsphereVolume | ✓ | vSphere |
PortworxVolume | ✓ | Portworx Volume |
Local | – | Local |
不限于指定此处列出的 “内置” 制备器(其名称前缀为 “kubernetes.io” 并打包在 Kubernetes 中)。 还可以运行和指定外部制备器,这些独立的程序遵循由 Kubernetes 定义的规范。 外部供应商的作者完全可以自由决定他们的代码保存于何处、打包方式、运行方式、使用的插件(包括 Flex)等。 代码仓库 kubernetes-sigs/sig-storage-lib-external-provisioner 包含一个用于为外部制备器编写功能实现的类库。
例如,NFS 没有内部制备器,但可以使用外部制备器。 也有第三方存储供应商提供自己的外部制备器。
五、回收策略
由 StorageClass 动态创建的 PersistentVolume 会在类的 reclaimPolicy 字段中指定回收策略,可以是 Delete 或者 Retain。 如果 StorageClass 对象被创建时没有指定 reclaimPolicy,它将默认为 Delete。
通过 StorageClass 手动创建并管理的 PersistentVolume 会使用它们被创建时指定的回收策略。
六、允许卷扩展
PersistentVolume 可以配置为可扩展。将此功能设置为 true 时,允许用户通过编辑相应的 PVC 对象来调整卷大小。当下层 StorageClass 的 allowVolumeExpansion 字段设置为 true 时,以下类型的卷支持卷扩展。
卷类型 | Kubernetes 版本要求 |
gcePersistentDisk | 1.11 |
rbd | 1.11 |
Azure File | 1.11 |
Portworx | 1.11 |
FlexVolume | 1.13 |
CSI | 1.14 (alpha), 1.16 (beta) |
注意:此功能仅可用于扩容卷,不能用于缩小卷。
七、挂载选项
由 StorageClass 动态创建的 PersistentVolume 将使用类中 mountOptions 字段指定的挂载选项。
如果卷插件不支持挂载选项,却指定了挂载选项,则制备操作会失败。 挂载选项在 StorageClass 和 PV 上都不会做验证。如果其中一个挂载选项无效,那么这个 PV 挂载操作就会失败。
八、卷绑定模式
volumeBindingMode 字段控制了卷绑定和动态制备应该发生在什么时候。 当未设置时,默认使用 Immediate 模式。
Immediate 模式表示一旦创建了 PersistentVolumeClaim 也就完成了卷绑定和动态制备。 对于由于拓扑限制而非集群所有节点可达的存储后端,PersistentVolume 会在不知道 Pod 调度要求的情况下绑定或者制备。
集群管理员可以通过指定 WaitForFirstConsumer 模式来解决此问题。 该模式将延迟 PersistentVolume 的绑定和制备,直到使用该 PersistentVolumeClaim 的 Pod 被创建。 PersistentVolume 会根据 Pod 调度约束指定的拓扑来选择或制备。 这些包括但不限于资源需求、 节点筛选器、 Pod 亲和性和互斥性、 以及污点和容忍度。
以下插件支持动态制备的 WaitForFirstConsumer 模式:
- GCEPersistentDisk
以下插件支持预创建绑定 PersistentVolume 的 WaitForFirstConsumer 模式:
- 上述全部
- Local
动态制备和预先创建的 PV 也支持 CSI 卷, 但是需要查看特定 CSI 驱动的文档以查看其支持的拓扑键名和例子。
注意:
- 如果选择使用 WaitForFirstConsumer,请不要在 Pod 规约中使用 nodeName 来指定节点亲和性。 如果在这种情况下使用 nodeName,Pod 将会绕过调度程序,PVC 将停留在 pending 状态。
- 相反,在这种情况下,可以使用节点选择器作为主机名,如下所示。
apiVersion: v1 kind: Pod metadata: name: task-pv-pod spec: nodeSelector: kubernetes.io/hostname: kube-01 volumes: - name: task-pv-storage persistentVolumeClaim: claimName: task-pv-claim containers: - name: task-pv-container image: nginx ports: - containerPort: 80 name: "http-server" volumeMounts: - mountPath: "/usr/share/nginx/html" name: task-pv-storage
九、允许的拓扑结构
当集群操作人员使用了 WaitForFirstConsumer 的卷绑定模式, 在大部分情况下就没有必要将制备限制为特定的拓扑结构。 然而,如果还有需要的话,可以使用 allowedTopologies。
这个例子描述了如何将制备卷的拓扑限制在特定的区域, 在使用时应该根据插件支持情况替换 zone 和 zones 参数。
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: standard provisioner: kubernetes.io/gce-pd parameters: type: pd-standard volumeBindingMode: WaitForFirstConsumer allowedTopologies: - matchLabelExpressions: - key: topology.kubernetes.io/zone values: - us-central-1a - us-central-1b
十、参数
Storage Classes 的参数描述了存储类的卷,取决于制备器,可以接受不同的参数。 例如,参数 type 的值 io1 和参数 iopsPerGB 特定于 EBS PV。 当参数被省略时,会使用默认值。
一个 StorageClass 最多可以定义 512 个参数。这些参数对象的总长度不能超过 256 KiB,包括参数的键和值。
1、AWS EBS
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: slow provisioner: kubernetes.io/aws-ebs parameters: type: io1 iopsPerGB: "10" fsType: ext4
- type:io1、gp2、sc1、st1;
- zone(已弃用):AWS 区域。如果没有指定 zone 和 zones, 通常卷会在 Kubernetes 集群节点所在的活动区域中轮询调度分配。 zone 和 zones 参数不能同时使用;
- zones(已弃用):以逗号分隔的 AWS 区域列表。 如果没有指定 zone 和 zones,通常卷会在 Kubernetes 集群节点所在的活动区域中轮询调度分配。 zone和zones参数不能同时使用;
- iopsPerGB:只适用于 io1 卷。每 GiB 每秒 I/O 操作。 AWS 卷插件将其与请求卷的大小相乘以计算 IOPS 的容量, 并将其限制在 20000 IOPS。 这里需要输入一个字符串,即 “10”,而不是 10;
- fsType:受 Kubernetes 支持的文件类型。默认值:”ext4″;
- encrypted:指定 EBS 卷是否应该被加密。合法值为 “true” 或者 “false”。 这里需要输入字符串,即 “true”,而非 true;
- kmsKeyId:可选。加密卷时使用密钥的完整 Amazon 资源名称。 如果没有提供,但 encrypted 值为 true,AWS 生成一个密钥。
注意:zone 和 zones 已被弃用并被允许的拓扑结构取代。
2、GCE PD
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: slow provisioner: kubernetes.io/gce-pd parameters: type: pd-standard fstype: ext4 replication-type: none
- type:pd-standard 或者 pd-ssd,默认:pd-standard;
- zone(已弃用):GCE 区域。如果没有指定 zone 和 zones, 通常卷会在 Kubernetes 集群节点所在的活动区域中轮询调度分配, zone 和 zones 参数不能同时使用;
- zones(已弃用):逗号分隔的 GCE 区域列表,如果没有指定 zone 和 zones, 通常卷会在 Kubernetes 集群节点所在的活动区域中轮询调度(round-robin)分配, zone 和 zones 参数不能同时使用;
- fstype:ext4 或 xfs。默认:ext4,宿主机操作系统必须支持所定义的文件系统类型;
- replication-type:none 或者 regional-pd,默认值:none;
- 如果 replication-type 设置为 none,会制备一个常规(当前区域内的)持久化磁盘。
如果 replication-type 设置为 regional-pd, 会制备一个区域性持久化磁盘(Regional Persistent Disk)。
强烈建议设置 volumeBindingMode: WaitForFirstConsumer,这样设置后, 当创建一个 Pod,它使用的 PersistentVolumeClaim 使用了这个 StorageClass, 区域性持久化磁盘会在两个区域里制备。其中一个区域是 Pod 所在区域, 另一个区域是会在集群管理的区域中任意选择,磁盘区域可以通过 allowedTopologies 加以限制。
zone 和 zones 已被弃用并被 allowedTopologies 取代。 当启用 GCE CSI 迁移时, GCE PD 卷可能被制备在某个与所有节点都不匹配的拓扑域中,但任何尝试使用该卷的 Pod 都无法被调度。 对于传统的迁移前 GCE PD,这种情况下将在制备卷的时候产生错误。 从 Kubernetes 1.23 版本开始,GCE CSI 迁移默认启用。
3、NFS
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: example-nfs provisioner: example.com/external-nfs parameters: server: nfs-server.example.com path: /share readOnly: "false"
- server:NFS 服务器的主机名或 IP 地址;
- path:NFS 服务器导出的路径
- readOnly:是否将存储挂载为只读的标志(默认为 false)。
Kubernetes 不包含内部 NFS 驱动。需要使用外部驱动为 NFS 创建 StorageClass。 这里有些例子:
- NFS Ganesha 服务器和外部驱动;
- NFS subdir 外部驱动。
4、vSphere
vSphere 存储类有两种制备器:
- CSI 制备器:csi.vsphere.vmware.com;
- vCP 制备器:kubernetes.io/vsphere-volume。
树内制备器已经被弃用。
5、CSI 制备器
vSphere CSI StorageClass 制备器在 Tanzu Kubernetes 集群下运行。
6、vCP 制备器
以下示例使用 VMware Cloud Provider(vCP)StorageClass 制备器。
- 使用用户指定的磁盘格式创建一个 StorageClass;
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: fast provisioner: kubernetes.io/vsphere-volume parameters: diskformat: zeroedthick
diskformat:thin、zeroedthick 和 eagerzeroedthick。默认值:”thin”。
- 在用户指定的数据存储上创建磁盘格式的 StorageClass;
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: fast provisioner: kubernetes.io/vsphere-volume parameters: diskformat: zeroedthick datastore: VSANDatastore
datastore:用户也可以在 StorageClass 中指定数据存储。 卷将在 StorageClass 中指定的数据存储上创建,在这种情况下是 VSANDatastore。 该字段是可选的。 如果未指定数据存储,则将在用于初始化 vSphere Cloud Provider 的 vSphere 配置文件中指定的数据存储上创建该卷。
- Kubernetes 中的存储策略管理;
使用现有的 vCenter SPBM 策略:
vSphere 用于存储管理的最重要特性之一是基于策略的管理。 基于存储策略的管理(SPBM)是一个存储策略框架,提供单一的统一控制平面的跨越广泛的数据服务和存储解决方案。 SPBM 使得 vSphere 管理员能够克服先期的存储配置挑战,如容量规划、差异化服务等级和管理容量空间。
SPBM 策略可以在 StorageClass 中使用 storagePolicyName 参数声明。
Kubernetes 内的 Virtual SAN 策略支持:
Vsphere Infrastructure(VI)管理员将能够在动态卷配置期间指定自定义 Virtual SAN 存储功能。现在可以在动态制备卷期间以存储能力的形式定义存储需求,例如性能和可用性。 存储能力需求会转换为 Virtual SAN 策略,之后当持久卷(虚拟磁盘)被创建时, 会将其推送到 Virtual SAN 层。虚拟磁盘分布在 Virtual SAN 数据存储中以满足要求。
7、Ceph RBD
Ceph RBD 的内部驱动程序已被弃用。请使用 CephFS RBD CSI驱动程序。
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: fast provisioner: kubernetes.io/rbd parameters: monitors: 10.16.153.105:6789 adminId: kube adminSecretName: ceph-secret adminSecretNamespace: kube-system pool: kube userId: kube userSecretName: ceph-secret-user userSecretNamespace: default fsType: ext4 imageFormat: "2" imageFeatures: "layering"
- monitors:Ceph monitor,逗号分隔。该参数是必需的;
- adminId:Ceph 客户端 ID,用于在池 ceph 池中创建映像。默认是 “admin”;
- adminSecret:adminId 的 Secret 名称。该参数是必需的。 提供的 secret 必须有值为 “kubernetes.io/rbd” 的 type 参数;
- adminSecretNamespace:adminSecret 的命名空间。默认是 “default”;
- pool:Ceph RBD 池。默认是 “rbd”;
- userId:Ceph 客户端 ID,用于映射 RBD 镜像。默认与 adminId 相同;
- userSecretName:用于映射 RBD 镜像的 userId 的 Ceph Secret 的名字。 它必须与 PVC 存在于相同的namespace 中。该参数是必需的。 提供的 secret 必须具有值为 “kubernetes.io/rbd” 的 type 参数,例如以这样的方式创建:
kubectl create secret generic ceph-secret --type="kubernetes.io/rbd" \ --from-literal=key='QVFEQ1pMdFhPUnQrSmhBQUFYaERWNHJsZ3BsMmNjcDR6RFZST0E9PQ==' \ --namespace=kube-system
- userSecretNamespace:userSecretName 的命名空间;
- fsType:Kubernetes 支持的 fsType。默认:”ext4″;
- imageFormat:Ceph RBD 镜像格式,”1″ 或者 “2”。默认值是 “1”;
- imageFeatures:这个参数是可选的,只能在将 imageFormat 设置为 “2” 才使用。 目前支持的功能只是 layering。默认是 “”,没有功能打开。
8、Azure磁盘
Azure Unmanaged Disk Storage Class(非托管磁盘存储类):
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: slow provisioner: kubernetes.io/azure-disk parameters: skuName: Standard_LRS location: eastus storageAccount: azure_storage_account_name
- skuName:Azure 存储帐户 Sku 层。默认为空;
- location:Azure 存储帐户位置。默认为空;
- storageAccount:Azure 存储帐户名称。 如果提供存储帐户,它必须位于与集群相同的资源组中,并且 location 是被忽略的。如果未提供存储帐户,则会在与集群相同的资源组中创建新的存储帐户。
9、Azure 磁盘 Storage Class(从 v1.7.2 开始)
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: slow provisioner: kubernetes.io/azure-disk parameters: storageaccounttype: Standard_LRS kind: managed
- storageaccounttype:Azure 存储帐户 Sku 层。默认为空;
- kind:可能的值是 shared、dedicated 和 managed(默认)。 当 kind 的值是 shared 时,所有非托管磁盘都在集群的同一个资源组中的几个共享存储帐户中创建。 当 kind 的值是 dedicated 时,将为在集群的同一个资源组中新的非托管磁盘创建新的专用存储帐户;
- resourceGroup:指定要创建 Azure 磁盘所属的资源组。必须是已存在的资源组名称。 若未指定资源组,磁盘会默认放入与当前 Kubernetes 集群相同的资源组中;
- Premium VM 可以同时添加 Standard_LRS 和 Premium_LRS 磁盘,而 Standard 虚拟机只能添加 Standard_LRS 磁盘;
- 托管虚拟机只能连接托管磁盘,非托管虚拟机只能连接非托管磁盘。
10、Azure 文件
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: azurefile provisioner: kubernetes.io/azure-file parameters: skuName: Standard_LRS location: eastus storageAccount: azure_storage_account_name
- skuName:Azure 存储帐户 Sku 层。默认为空;
- location:Azure 存储帐户位置。默认为空;
- storageAccount:Azure 存储帐户名称。默认为空。 如果不提供存储帐户,会搜索所有与资源相关的存储帐户,以找到一个匹配 skuName 和 location 的账号。 如果提供存储帐户,它必须存在于与集群相同的资源组中,skuName 和 location 会被忽略;
- secretNamespace:包含 Azure 存储帐户名称和密钥的密钥的名字空间。 默认值与 Pod 相同;
- secretName:包含 Azure 存储帐户名称和密钥的密钥的名称。 默认值为 azure-storage-account-<accountName>-secret;
- readOnly:指示是否将存储安装为只读的标志。默认为 false,表示”读/写”挂载。 该设置也会影响 VolumeMounts 中的 ReadOnly 设置。
在存储制备期间,为挂载凭证创建一个名为 secretName 的 Secret。如果集群同时启用了 RBAC 和控制器角色, 为 system:controller:persistent-volume-binder 的 clusterrole 添加 Secret 资源的 create 权限。
在多租户上下文中,强烈建议显式设置 secretNamespace 的值,否则其他用户可能会读取存储帐户凭据。
11、Portworx 卷
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: portworx-io-priority-high provisioner: kubernetes.io/portworx-volume parameters: repl: "1" snap_interval: "70" priority_io: "high"
- fs:选择的文件系统:none/xfs/ext4(默认:ext4);
- block_size:以 Kbytes 为单位的块大小(默认值:32);
- repl:同步副本数量,以复制因子 1..3(默认值:1)的形式提供。 这里需要填写字符串,即,”1″ 而不是 1;
- io_priority:决定是否从更高性能或者较低优先级存储创建卷 high/medium/low(默认值:low);
- snap_interval:触发快照的时钟/时间间隔(分钟)。 快照是基于与先前快照的增量变化,0 是禁用快照(默认:0)。 这里需要填写字符串,即,是 “70” 而不是 70;
- aggregation_level:指定卷分配到的块数量,0 表示一个非聚合卷(默认:0)。 这里需要填写字符串,即,是 “0” 而不是 0;
- ephemeral:指定卷在卸载后进行清理还是持久化。 emptyDir 的使用场景可以将这个值设置为 true, persistent volumes 的使用场景可以将这个值设置为 false (例如 Cassandra 这样的数据库) true/false(默认为 false)。这里需要填写字符串,即, 是 “true” 而不是 true。
12、本地
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: local-storage provisioner: kubernetes.io/no-provisioner volumeBindingMode: WaitForFirstConsumer
本地卷还不支持动态制备,然而还是需要创建 StorageClass 以延迟卷绑定, 直到完成 Pod 的调度。这是由 WaitForFirstConsumer 卷绑定模式指定的。
延迟卷绑定使得调度器在为 PersistentVolumeClaim 选择一个合适的 PersistentVolume 时能考虑到所有 Pod 的调度限制。