目录
一、概述
集群级别资源,StorageClass 是 Kubernetes 中的一种资源对象,它定义了创建 Persistent Volume (PV) 的策略和方法。StorageClass 主要用于实现 PV 的动态供应,这意味着当用户创建了一个 Persistent Volume Claim (PVC) 时,Kubernetes 会根据所指定的 StorageClass 主动创建一个符合要求的 PV 并将其绑定到 PVC 上
StorageClass 作为对存储资源的抽象定义,对用户设置的 PVC 申请屏蔽后端存储的细节,一方面减少了用户对于存储资源细节的关注,另一方面减轻了管理员手工管理 PV 的工作,由系统主动完成 PV 的创建和绑定,实现动态的资源供应。基于 StorageClass 的动态资源供应模式将逐步成为云平台的标准存储管理模式。
1、StorageClass 对象定义
StorageClass 资源对象的定义主要包罗:名称、后端存储的提供者 (provisioner)、后端存储的相关参数配置(parameters)和回收策略(reclaimPolicy)、卷绑定模式(volumeBindingMode)
- StorageClass 的名称很重要,将在创建 PVC 时引用,管理员应该正确定名具有不同存储特性的 StorageClass。
- StorageClass 一旦被创建,则无法修改,如需更改,则只能删除原 StorageClass 资源对象并重新创建。
2、StorageClass YAML 示例
- apiVersion: storage.k8s.io/v1
- kind: StorageClass
- metadata:
- # 存储类的名称,用户在 PVC 中引用
- name: example-storage-class
- storageclass.kubernetes.io/is-default-class: "true" # 设置为默认的 StorageClass
- # 动态制备器的名称,需要与已安装的制备器匹配
- provisioner: kubernetes.io/aws-ebs # 例子中使用的是 AWS EBS 制备器
- # reclaimPolicy 定义了当 PVC 被删除时,PV 应该如何处理
- reclaimPolicy: Delete # 可选值为 Retain 或 Delete
- # 允许卷扩展
- allowVolumeExpansion: true # 可选值为 true 或 false
- # 定义了卷绑定到 Pod 的模式
- volumeBindingMode: Immediate # 可选值为 Immediate 或 WaitForFirstConsumer
- # 定义了存储系统需要的参数,这些参数会传递给制备器
- parameters:
- # 存储类型,根据制备器和存储系统的要求设置
- type: gp2 # AWS EBS 的例子,对于其他系统可能有不同的值
- # 存储 IOPS 性能,某些存储系统可能需要这个参数
- iopsPerGB: "10" # 例子,具体值根据需求和制备器支持设置
- # 存储的最小 IOPS 值,某些存储系统可能需要这个参数
- minimumIOPS: "1000" # 例子,具体值根据需求和制备器支持设置
- # 存储的最大 IOPS 值,某些存储系统可能需要这个参数
- maximumIOPS: "20000" # 例子,具体值根据需求和制备器支持设置
- # 存储的加密选项,某些存储系统可能支持加密
- encrypted: "true" # 例子,具体值根据需求和制备器支持设置
- # 存储的区域,对于跨区域存储系统可能需要这个参数
- availabilityZone: "us-east-1a" # 例子,具体值根据制备器和存储系统的要求设置
- # 存储的性能等级,某些存储系统可能提供不同的性能等级
- performance: "high" # 例子,具体值根据制备器和存储系统的要求设置
- # 定义了挂载选项,这些选项会在 PV 被挂载到节点时使用
- mountOptions:
- - debug # 例子,具体值根据需求设置,可能包括 "debug", "defaults", "ro" 等
- # - other-option # 可以添加额外的挂载选项
- # 允许的拓扑约束,定义了存储可以被哪些节点访问
- allowedTopologies:
- - matchLabelExpressions:
- - key: topology.kubernetes.io/region
- values:
- - us-east-1
- - key: topology.kubernetes.io/zone
- values:
- - us-east-1a
复制代码
二、StorageClass 字段
1、provisioner(存储制备器)
provisioner 指定了用于动态创建 PersistentVolume (PV) 的制备器(Provisioner)。制备器是一个插件,它负责在后端存储系统中根据 PersistentVolumeClaim (PVC) 的哀求来创建存储资源,不同的存储插件支持不同的存储后端和服务提供商。当 PVC 被创建而且与之关联的 StorageClass 指定了一个制备器时,Kubernetes 会调用这个制备器来主动创建相应的 PV。
卷插件内置制备器配置示例AWSElasticBlockStore√AWS EBSAzureFile√Azure文件(已弃用)AzureDisk√Azure DiskCephFS--Cinder√Open Stack CinderFC--FlexVolume--GCEPersistentDisk√gcePDGlusterfs√GlusterFSiSCSI--Local-LocalNFS-NFSPortworxVolume√portworx-volumeRBD√ceph-rbdVsphereVolume√Vsphere1.1、内置制备器
Kubernetes 内置支持的 Provisioner 的定名都以 "kubernetes.io/" 开头
- kubernetes.io/aws-ebs:用于在 AWS 上创建 Elastic Block Store (EBS) 卷。
- kubernetes.io/azure-disk:用于在 Azure 上创建磁盘。
- kubernetes.io/gce-pd:用于在 Google Cloud Platform (GCP) 上创建持久磁盘。
- kubernetes.io/cinder:用于在 OpenStack 上创建 Cinder 卷。
1.2、第三方制备器
为了符合 StorageClass 的用法,自定义 Provisioner 必要符合存储卷的开发规范,外部存储供应商的作者对代码、提供方式、运行方式、存储插件(包罗Flex)等具有完全的自由控制权。
代码堆栈 kubernetes-sigs/sig-storage-lib-external-provisioner 包含一个用于为外部制备器编写功能实现的类库。你可以访问代码堆栈 kubernetes-sigs/sig-storage-lib-external-provisioner 了解外部驱动列表。
比方,对NFS范例,Kubernetes没有提供内部的Provisioner,但可以使用外部的Provisioner。也有很多第三方存储提供商自行提供外部的Provisioner。
2、reclaimPolicy(回收策略)
通过动态资源供应模式创建的PV将继承在StorageClass资源对象上设置的回收策略,配置字段名称为“reclaimPolicy“,可以设置的选项包罗Delete(删除)和 Retain(保留)。
- 如果StorageClass没有指定reclaimPolicy,则默认值为Delete。
- 对于管理员手工创建的仍被StorageClass管理的PV,将使用创建PV时设置的资源回收策略。
3、allowVolumeExpansion(允许卷扩展)
PV 可以被配置为允许扩容,当 StorageClass 资源对象的 allowVolumeExpansion字段被设置为true时,将允许用户通过编辑PVC的存储空间主动完成PV的扩容。
下表形貌了支持存储扩容的Volume范例和要求的Kubernetes最低版本:
支持存储扩容的 Volume 范例Kubernetes 最低版本gcePersistentDisk1.11awsElasticBlock Store1.11Cinder1.11glusterfs1.11RBD1.11Azure File1.11Azure Disk1.11Portworx1.13FlexVolume1.14(Alpha)CSI1.16(Beta)此功能仅可用于扩容卷,不能用于缩小卷。
4、mountOptions(挂载选项)
通过StorageClass资源对象的mountOptions字段,系统将为动态创建的PV设置挂载选项。
并不是所有 PV范例都支持挂载选项,如果 PV不支持但 StorageClass 设置了该字段,则 PV将会创建失败。另外,系统不会对挂载选项进行验证,如果设置了错误的选项,则容器在挂载存储时将直接失败。
5、volumeBindingMode(卷绑定模式)
StorageClass 资源对象的 volumeBindingMode 字段设置用于控制何时将 PVC 与动态创建的 PV 绑定。
目前支持的绑定模式包罗: Immediate 和 WaitForFirstConsumer。
5.1、Immediate
存储绑定模式的默认值为 Immediate,表示当一个PersistentVolumeClaim (PVC)创建出来时,就动态创建PV并进行PVC与PV的绑定操纵。
必要注意的是,对于拓扑受限 (Topology-limited) 或无法从全部Node访问的后端存储,将在不了解Pod调度需求的情况下完成PV的绑定操纵,这大概会导致某些Pod无法完成调度。
5.2、WaitForFirstConsumer
WaitForFirstConsumer绑定模式表示PVC与PV的绑定操纵延迟到第一个使用 PVC的Pod创建出来时再进行。
系统将根据Pod的调度需求,在Pod所在的Node上创建PV,这些调度需求可以通过以下条件(不限于)进行设置:
- Pod对资源的需求
- Node Selector
- Pod亲和性和反亲和性设置
- Taint和Toleration设置
目前支持 WaitForFirstConsumer 绑定模式的存储卷包罗:
- AWSElasticBlockStore
- AzureDisk
- GCEPersistentDisk.
另外,有些存储插件通过预先创建好的PV绑定支持WaitForFirstConsumer模式,好比:
- AWSElasticBlockStore
- AzureDisk
- GCEPersistentDisk
- Local
6、allowedTopologies(允许的拓扑结构)
在使用WaitForFirstConsumer模式的环境中,如果仍然希望基于特定拓扑信息(Topology)进行PV绑定操纵,则在StorageClass的定义中还可以通过 allowedTopologies字段进行设置。
6.1、示例
下面的例子通过 matchLabelExpressions 设置目标 Node 的标签选择条件 (zone=us-central1-a或 us-central1-b) PV 将在满足这些条件的 Node 上允许创建- apiVersion: storage.k8s.io/v1
- kind: StorageClass
- metadata:
- name: standard
- provisioner: kubernetes.io/example
- parameters:
- type: pd-standard
- volumeBindingMode: WaitForFirstConsumer
- allowedTopologies:
- - matchLabelExpressions:
- - key: topology.kubernetes.io/zone
- values:
- - us-central-1a
- - us-central-1b
复制代码 7、parameters(存储参数)
后端存储资源提供者的参数设置,不同的 Provisioner 大概提供不同的参数设置。某些参数可以不显示设定,Provisioner 将使用其默认值。
目前 StorageClass 资源对象支持设置的存储参数最多为 512个,全部 key 和 value 所占的空间不能超过 256KiB。
7.1、示例
下面举常见存储提供商(Provisioner)提供的 StorageClass 存储参数示例(以AWSElasticBlockStore存储卷为例子):- apiVersion: storage.k8s.io/v1
- kind: StorageClass
- metadata:
- name: ebs-sc
- provisioner: ebs.csi.aws.com
- volumeBindingMode: WaitForFirstConsumer
- parameters:
- csi.storage.k8s.io/fstype: xfs
- type: io1
- iopsPerGB: "50"
- encrypted: "true"
- allowedTopologies:
- - matchLabelExpressions:
- - key: topology.ebs.csi.aws.com/zone
- values:
- - us-east-2c
复制代码 7.2、存储参数(AWSElasticBlockStore)
AWS EBS 存储参数

- type (必需)
- 定义 EBS 卷的存储范例(默认值gp3)。比方:
- gp2:通用目的 SSD
- io1:提供高 IOPS 的 SSD
- io2:适用于必要大量 IOPS 的应用程序的新一代 SSD
- st1:通过 HDD 存储优化的卷
- sc1:通过冷 HDD 存储优化的卷
- iopsPerGB (可选,仅当 type 为 io1 或 io2 时有效)
- 定义每个 GiB 提供的 IOPS 数量。
- 比方,如果 type 为 io1 而且 iopsPerGB 设置为 10,则 100 GiB 的卷将提供 1000 IOPS。
- iops (可选,仅当 type 为 io1 时有效)
- 直接定义卷的 IOPS 总数。比方,iops: "1000" 表示卷将提供 1000 IOPS。
- throughput (可选,仅当 type 为 st1 时有效)
- 定义卷的吞吐量,以 MiB/s 为单元。比方,throughput: "500" 表示卷的吞吐量为 500 MiB/s。
- encrypted (可选)
- 布尔值,指示是否应该加密 EBS 卷。比方,encrypted: "true"。
- kmsKeyId (可选)
- 指定用于加密 EBS 卷的 KMS 密钥 ID。比方,kmsKeyId: "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab"。
- fsType (可选)
- 定义文件系统范例。比方,fsType: "ext4"。
- volumeSize (可选)
- 定义哀求的卷大小(以 GiB 为单元)。比方,volumeSize: "100" 表示哀求 100 GiB 的卷。
- availabilityZone (可选)
- 定义 EBS 卷应该创建在哪个可用区。比方,availabilityZone: "us-west-2a"。
- multiAttachEnabled (可选)
- 布尔值,指示是否启用多附加。比方,multiAttachEnabled: "true" 允许卷同时附加到多个实例。
- snapshotId (可选)
- 定义用于创建 EBS 卷的快照 ID。比方,snapshotId: "snap-0123456789abcdef0"。
- tags (可选)
- 定义一组键值对,用于标记 EBS 卷。比方:
- tags:
- - key: "project"
- value: "myproject"
- - key: "owner"
- value: "myteam"
复制代码
8、设置默认的 StorageClass(storageclass.kubernetes.io/is-default-class)
在创建 SC 的 YAML 文件时,必要在 metadata 部分添加一个注解,以标记该 SC 为默认。
8.1、示例
- apiVersion: storage.k8s.io/v1
- kind: StorageClass
- metadata:
- name: low-latency
- annotations:
- storageclass.kubernetes.io/is-default-class: "false"
- provisioner: csi-driver.example-vendor.example
- reclaimPolicy: Retain # 默认值是 Delete
- allowVolumeExpansion: true
- mountOptions:
- - discard # 这可能会在块存储层启用 UNMAP/TRIM
- volumeBindingMode: WaitForFirstConsumer
- parameters:
- guaranteedReadWriteLatency: "true" # 这是服务提供商特定的
复制代码 8.2、修改已有的 StorageClass
8.2.1、将存在的 SC 设置为默认
- kubectl patch storageclass <sc-name> -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
复制代码 8.2.2、将存在的 SC 设置为非默认
- kubectl patch storageclass <sc-name> -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'
复制代码如果你在集群中的多个 StorageClass 上将 storageclass.kubernetes.io/is-default-class 注解设置为 true,然后创建一个未设置 storageClassName 的 PersistentVolumeClaim (PVC), Kubernetes 将使用近来创建的默认 StorageClass。
三、实例 -- 使用 NFS 范例的 StorageClass 动态创建 PV
角色主机名ip地址nfs 服务端 + master 节点k8s-master1192.168.112.10nfs 客户端 + node 节点k8s-node1192.168.112.20nfs 客户端 + node 节点k8s-node2192.168.112.301、配置 NFS 服务端
1.1、master 节点安装 nfs-utils 包
1.2、master 节点创建共享目录
1.3、编辑/etc/exports文件
- echo "/data/nfs 192.168.112.0/24(rw,sync,no_root_squash)" > /etc/exports
复制代码
1.4、应用新的导出设置
1.5、重启并设置 NFS 开机自启
- systemctl restart nfs && systemctl enable nfs
复制代码
1.6、检查 NFS 共享
2、配置 NFS 客户端
所有 node 节点
2.1、安装 nfs-utils 包
2.2、创建目录挂载 NFS 共享
- mkdir -pv /mnt/nfs
- mount -t nfs 192.168.112.10:/data/nfs /mnt/nfs
复制代码
2.2.1、卸载错误的挂载点
如果在执行 mount -t nfs 下令时出现了错误,好比使用了错误的参数或者路径,你可以通过卸载当前的挂载点然后再重新挂载来修正错误。
- 确认当前的挂载状态
- 使用 mount 下令查看当前的所有挂载情况,找到错误挂载的条目。
- 卸载错误的挂载点
- # 知道错误的挂载点
- sudo umount /mnt/nfs
复制代码- # 知道 nfs 服务端 IP 地址和共享目录路径
- sudo umount 192.168.112.10:/data/nfs
复制代码
- 卸载时碰到设备/文件正在使用中
- 强制卸载大概会导致数据丢失,因此只有在确定没有数据写入的情况下才这样做。
2.3、重启并设置 NFS 开机自启
- systemctl restart nfs && systemctl enable nfs
复制代码
2.4、系统启动主动挂载 NFS 共享(非须要)
- echo '192.168.112.10:/data/nfs /mnt/nfs nfs defaults 0 0' >> /etc/fstab
复制代码 2.5、查看挂载状态
- mount | grep 192.168.112.10
复制代码
3、创建存储类
- cat >> nfs-storage.yaml << EOF
- apiVersion: storage.k8s.io/v1
- kind: StorageClass
- metadata:
- name: nfs-storage
- namespace: default
- labels:
- environment: test
- provisioner: fuseim.pri/ifs
- reclaimPolicy: Retain
- volumeBindingMode: Immediate
- EOF
复制代码 10、从另一个 Pod 读取数据
- kubectl apply -f nfs-storage.yaml
复制代码
11、查看 nfs 服务端与客户端的共享目录
- cat >> rbac.yaml << EOF
- apiVersion: v1
- kind: ServiceAccount
- metadata:
- name: nfs-client-provisioner
- namespace: default
- ---
- kind: ClusterRole
- apiVersion: rbac.authorization.k8s.io/v1
- metadata:
- name: nfs-client-provisioner-runner
- rules:
- - apiGroups: [""]
- resources: ["persistentvolumes"]
- verbs: ["get", "list", "watch", "create", "delete"]
- - apiGroups: [""]
- resources: ["persistentvolumeclaims"]
- verbs: ["get", "list", "watch", "update"]
- - apiGroups: ["storage.k8s.io"]
- resources: ["storageclasses"]
- verbs: ["get", "list", "watch"]
- - apiGroups: [""]
- resources: ["events"]
- verbs: ["create", "update", "patch"]
- ---
- kind: ClusterRoleBinding
- apiVersion: rbac.authorization.k8s.io/v1
- metadata:
- name: run-nfs-client-provisioner
- subjects:
- - kind: ServiceAccount
- name: nfs-client-provisioner
- namespace: default
- roleRef:
- kind: ClusterRole
- name: nfs-client-provisioner-runner
- apiGroup: rbac.authorization.k8s.io
- ---
- kind: Role
- apiVersion: rbac.authorization.k8s.io/v1
- metadata:
- name: leader-locking-nfs-client-provisioner
- namespace: default
- rules:
- - apiGroups: [""]
- resources: ["endpoints"]
- verbs: ["get", "list", "watch", "create", "update", "patch"]
- ---
- kind: RoleBinding
- apiVersion: rbac.authorization.k8s.io/v1
- metadata:
- name: leader-locking-nfs-client-provisioner
- namespace: default
- subjects:
- - kind: ServiceAccount
- name: nfs-client-provisioner
- namespace: default
- roleRef:
- kind: Role
- name: leader-locking-nfs-client-provisioner
- apiGroup: rbac.authorization.k8s.io
- EOF
复制代码


这个新出现的目录(PV 目录) default-nginx-pvc-pvc-c8a8b825-1577-4f76-ba1f-a1302941b333 用于映射 PersistentVolume (PV) 到 NFS 服务器上的具体路径
11.1、PV 目录创建的流程
- 创建 PVC:
- 当你创建 PVC 时,Kubernetes 会根据 StorageClass 主动创建 PV。
- Provisioner 创建 PV:
- Provisioner 会在 NFS 服务器上的共享目录下创建一个新目录,目录名称包含了 PVC 的名称和 UUID。
- 挂载到 Pod:
11.2、PV 目录的结构
- kubectl apply -f rbac.yaml
复制代码
- 共享目录:
- 这是你在 NFS 服务器上创建并共享出去的目录,好比 nfs 服务端的 /data/nfs 以及 nfs 客户端的 /mnt/nfs
- 定名空间:
- 这是 Kubernetes 中的一个逻辑分组,用于隔离不同的应用程序和服务。PVC 所属的定名空间名称。
- PVC 名称:
- 这是在 Kubernetes 中创建的 PersistentVolumeClaim 的名称。
- PV 名称:
- 这是根据 PVC 动态创建出来的 PersistentVolume 的名称,通常是一个带有 UUID 的字符串。
- cat >> nfs-provisioner.yaml << EOF
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: nfs-client-provisioner
- labels:
- app: nfs-client-provisioner
- namespace: default
- spec:
- replicas: 1
- strategy:
- type: Recreate
- selector:
- matchLabels:
- app: nfs-client-provisioner
- template:
- metadata:
- labels:
- app: nfs-client-provisioner
- spec:
- serviceAccountName: nfs-client-provisioner
- containers:
- - name: nfs-client-provisioner
- image: registry.cn-beijing.aliyuncs.com/mydlq/nfs-subdir-external-provisioner:v4.0.0
- volumeMounts:
- - name: nfs-client-root
- mountPath: /persistentvolumes
- env:
- - name: PROVISIONER_NAME
- value: fuseim.pri/ifs # 这里必须要填写storageclass中的PROVISIONER名称信息一致
- - name: NFS_SERVER
- value: 192.168.112.10 # 指定NFS服务器的IP地址
- - name: NFS_PATH
- value: /data/nfs # 指定NFS服务器中的共享挂载目录
- volumes:
- - name: nfs-client-root # 定义持久化卷的名称,必须要上面volumeMounts挂载的名称一致
- nfs:
- server: 192.168.112.10 # 指定NFS所在的IP地址
- path: /data/nfs # 指定NFS服务器中的共享挂载目录
- EOF
复制代码
12、修改 NFS 服务器共享目录内容查看容器内部变化
可以发现也是同步更新的
- kubectl apply -f nfs-provisioner.yaml
复制代码
四、实例 -- 动态创建 PVC 和 PV
1、创建 Headless Service
[code]cat >> nginx-headless.yaml > sts.yaml |