在Kubernetes中,对存储资源的管理方式与计算资源(CPU/内存)截然不同。为了能够屏蔽底层存储实现的细节,让用户方便使用及管理员方便管理,Kubernetes从1.0版本开始就引入了Persistent Volume(PV)和Persistent Volume Claim(PVC)两个资源对象来实现存储管理子系统。
PV(持久卷)是对存储资源的抽象,将存储定义为一种容器应用可以使用的资源。PV由管理员创建和配置,它与存储提供商的具体实现直接相关,例如GlusterFS、iSCSI、RBD或GCE或AWS公有云提供的共享存储,通过插件式的机制进行管理,供应用访问和使用。除了EmptyDir类型的存储卷,PV的生命周期独立于使用它的Pod。
PVC则是用户对存储资源的一个申请。就像Pod消耗Node的资源一样,PVC消耗PV资源。PVC可以申请存储空间的大小(size)和访问模式(例如ReadWriteOnce、ReadOnlyMany或ReadWriteMany)。
使用PVC申请的存储空间可能仍然不满足应用对存储设备的各种需求。在很多情况下,应用程序对存储设备的特性和性能都有不同的要求,包括读写速度、并发性能、数据冗余等要求,Kubernetes从1.4版本开始引入了一个新的资源对象StorageClass,用于标记存储资源的特性和性能,根据PVC的需求动态供给合适的PV资源。到Kubernetes 1.6版本时,StorageClass和存储资源动态供应的机制得到完善,实现了存储卷的按需创建,在共享存储的自动化管理进程中实现了重要的一步。
通过StorageClass的定义,管理员可以将存储资源定义为某种类别(Class),正如存储设备对于自身的配置描述(Profile),例如快速存储、慢速存储、有数据冗余、无数据冗余等。用户根据StorageClass的描述就可以直观地得知各种存储资源的特性,根据应用对存储资源的需求去申请存储资源了。
Kubernetes从1.9版本开始引入容器存储接口Container Storage Interface(CSI)机制,目标是在Kubernetes和外部存储系统之间建立一套标准的存储管理接口,具体的存储驱动程序由存储提供商在Kubernetes之外提供,并通过该标准接口为容器提供存储服务,类似于CRI(容器运行时接口)和CNI(容器网络接口),目的是将Kubernetes代码与存储相关代码解耦。
本节对Kubernetes的PV、PVC、StorageClass、动态资源供应和CSI等共享存储的概念、原理和应用进行详细说明。
我们可以将PV看作可用的存储资源,PVC则是对存储资源的需求。PV和PVC的生命周期如图8.1所示,其中包括资源供应(Provisioning)、资源绑定(Binding)、资源使用(Using)、资源回收(Reclaiming)几个阶段。

图8.1 PV和PVC的生命周期
本节对PV和PVC生命周期中各阶段的工作原理进行说明。
Kubernetes支持两种资源供应模式:静态模式(Static)和动态模式(Dynamic),资源供应的结果就是将适合的PV与PVC成功绑定。
◎ 静态模式:集群管理员预先创建许多PV,在PV的定义中能够体现存储资源的特性。
◎ 动态模式:集群管理员无须预先创建PV,而是通过StorageClass的设置对后端存储资源进行描述,标记存储的类型和特性。用户通过创建PVC对存储类型进行申请,系统将自动完成PV的创建及与PVC的绑定。如果PVC声明的Class为空"",则说明PVC不使用动态模式。另外,Kubernetes支持设置集群范围内默认的StorageClass设置,通过kube-apiserver开启准入控制器DefaultStorageClass,可以为用户创建的PVC设置一个默认的存储类StorageClass。
下面通过两张图分别对静态资源供应模式和动态资源供应模式下,PV、PVC、StorageClass及Pod使用PVC的原理进行说明。
图8.2描述了静态资源供应模式下,通过PV和PVC完成绑定并供Pod使用的原理。

图8.2 静态资源供应模式下的原理
图8.3描述了动态资源供应模式下,通过StorageClass和PVC完成资源动态绑定(系统自动生成PV),并供Pod使用的原理。

图8.3 动态资源供应模式下的原理
在用户定义好PVC之后,系统将根据PVC对存储资源的请求(存储空间和访问模式)在已存在的PV中选择一个满足PVC要求的PV,一旦找到,就将该PV与用户定义的PVC绑定,用户的应用就可以使用这个PVC了。如果在系统中没有满足PVC要求的PV,PVC则会无限期处于Pending状态,直到系统管理员创建了一个符合其要求的PV。
PV一旦与某个PVC上完成绑定,就会被这个PVC独占,不能再与其他PVC绑定了。PVC与PV的绑定关系是一对一的,不会存在一对多的情况。如果PVC申请的存储空间比PV拥有的空间少,则整个PV的空间都能为PVC所用,可能造成资源的浪费。
如果资源供应使用的是动态模式,则系统在为PVC找到合适的StorageClass后,将自动创建一个PV并完成与PVC的绑定。
Pod需要使用存储资源时,需要在Volume的定义中引用PVC类型的存储卷,将PVC挂载到容器内的某个路径下进行使用。Volume的类型字段为“persistentVolumeClaim”,在后面的示例中再进行详细举例说明。
Pod在挂载PVC后,就能使用存储资源了。同一个PVC还可以被多个Pod同时挂载使用,在这种情况下,应用程序需要处理好多个进程访问同一个存储的问题。
关于使用中的存储对象(Storage Object in Use Protection)的保护机制的说明如下。
存储资源(PV、PVC)相对于容器应用(Pod)是独立管理的资源,可以单独删除。在做删除操作的时候,系统会检测存储资源当前是否正在被使用,如果仍被使用,则对相关资源对象的删除操作将被推迟,直到没被使用才会执行删除操作,这样可以确保资源仍被使用的情况下不会被直接删除而导致数据丢失。这个机制被称为对使用中的存储对象的保护机制(Storage Object in Use Protection)。
该保护机制适用于PVC和PV两种资源,如下所述。
举例来说,当用户删除一个正在被Pod使用的PVC时,PVC对象不会被立刻删除,查看PVC对象的状态,可以看到其状态为“Terminating”,以及系统为其设置的Finalizer为“kubernetes.io/pvc-protection”:

举例来说,当用户删除一个仍被PVC绑定的PV时,PV对象不会被立刻删除,查看PV对象的状态,可以看到其状态为“Terminating”,以及系统为其设置的Finalizer为“kubernetes.io/pvc-protection”:


用户在使用存储资源完毕后,可以删除PVC。与该PVC绑定的PV将被标记为“已释放”,但还不能立刻与其他PVC绑定。通过之前PVC写入的数据可能还被留在存储设备上,只有在清除这些数据之后,该PV才能再次使用。
管理员可以对PV设置资源回收策略(Reclaim Policy),可以设置3种回收策略:Retain、Delete和Recycle。
Retain策略表示在删除PVC之后,与之绑定的PV不会被删除,仅被标记为已释放(released)。PV中的数据仍然存在,在清空之前不能被新的PVC使用,需要管理员手工清理之后才能继续使用,清理步骤如下。
(1)删除PV资源对象,此时与该PV关联的某些外部存储提供商(例如AWSElasticBlockStore、GCEPersistentDisk、AzureDisk、Cinder等)的后端存储资产(asset)中的数据仍然存在。
(2)手工清理PV后端存储资产(asset)中的数据。
(3)手工删除后端存储资产。如果希望重用该存储资产,则可以创建一个新的PV与之关联。
Delete策略表示自动删除PV资源对象和相关后端存储资产,并不是所有类型的存储提供商都支持Delete策略,目前支持Delete策略的存储提供商包括AWSElasticBlockStore、GCEPersistentDisk、Azure Disk、Cinder等。
通过动态供应机制创建的PV将继承StorageClass的回收策略,默认为Delete策略。管理员应该基于用户的需求设置StorageClass的回收策略,或者在创建出PV后手工更新其回收策略。
目前只有HostPort和NFS类型的Volume支持Recycle策略,其实现机制为运行rm-rf/thevolume/*命令,删除Volume目录下的全部文件,使得PV可以被新的PVC使用。
此外,管理员可以创建一个专门用于回收HostPort或NFS类型的PV数据的自定义Pod来实现数据清理工作,这个Pod的YAML配置文件所在的目录需要通过kube-controller-manager服务的启动参数--pv-recycler-pod-template-filepath-hostpath或--pv-recycler-pod-template-filepath-nfs进行设置(还可以设置相应的timeout参数)。在这个目录下创建一个Pod的YAML文件,示例如下:

经过这个自定义Pod的设置,系统将通过创建这个Pod来完成PV的数据清理工作,完成PV的回收。
注意,Recycle策略已被弃用,推荐以动态供应机制管理容器所需的存储资源。
PVC在首次创建成功之后,还应该能够在使用过程中实现空间的扩容,对PVC扩容机制的支持到Kubernetes 1.11版本时达到Beta阶段。
目前支持PVC扩容的存储类型有AWSElasticBlockStore、AzureFile、AzureDisk、Cinder、FlexVolume、GCEPersistentDisk、Glusterfs、Portworx Volumes、RBD和CSI等。
如需扩容PVC,则首先需要在PVC对应的StorageClass定义中设置allowVolumeExpansion=true,例如:

对PVC进行扩容操作时,只需修改PVC的定义,将resources.requests.storage设置为一个更大的值即可,例如通过以下设置,系统将会基于PVC新设置的存储空间触发后端PV的扩容操作,而不会创建一个新的PV资源对象:

此外,存储资源扩容还存在以下几种情况。
(1)CSI类型存储卷的扩容。对于CSI类型存储卷的扩容,在Kubernetes 1.16版本时达到Beta阶段,同样要求CSI存储驱动能够支持扩容操作,请参考各存储提供商的CSI驱动的文档说明。
(2)包含文件系统(File System)存储卷的扩容。对于包含文件系统存储卷的扩容,文件系统的类型必须是XFS、Ext3或Ext4,同时要求Pod使用PVC时设置的是可读可写(ReadWrite)模式。文件系统的扩容只能在Pod启动时完成,或者底层文件系统在Pod运行过程中支持在线扩容。对于FlexVolume类型的存储卷,在驱动程序支持RequiresFSResize=true参数设置的情况下才支持扩容。另外,FlexVolume支持在Pod重启时完成扩容操作。
(3)使用中的PVC在线扩容。Kubernetes从1.11版本开始引入了对使用中的PVC进行在线扩容的支持,到1.15版本时达到Beta阶段,以实现扩容PVC时无须重建Pod。为了使用该功能,需要设置kube-apiserver、kube-controller-manager、kubelet服务的启动参数--feature-gates=ExpandInUsePersistentVolumes=true来开启该特性开关。PVC在线扩容机制要求使用了PVC的Pod成功运行,对于没被任何Pod使用的PVC,不会有实际的扩容效果。FlexVolume类型的存储卷也可以在Pod使用时在线扩容,这需要底层存储驱动提供支持。
(4)扩容失败的恢复机制。如果扩容存储资源失败,则集群管理员可以手工恢复PVC的状态并且取消之前的扩容请求,否则系统将不断尝试扩容请求。执行恢复操作的步骤:设置与PVC绑定的PV资源的回收策略为“Retain”;删除PVC,此时PV的数据仍然存在;删除PV中的claimRef定义,这样新的PVC可以与之绑定,结果将使得PV的状态为“Available”;新建一个PVC,设置比PV空间小的存储空间申请,同时设置volumeName字段为PV的名称,结果将使得PVC与PV完成绑定;恢复PVC的原回收策略。
PV作为对存储资源的定义,主要涉及存储能力、访问模式、存储类型、回收策略、后端存储类型等关键信息的设置。
下面的示例声明的PV具有如下属性:5GiB存储空间,存储卷模式为Filesystem,访问模式为ReadWriteOnce,存储类型为slow(要求在系统中已存在名称为“slow”的StorageClass),回收策略为Recycle,并且后端存储类型为nfs(设置了NFS Server的IP地址和路径),同时设置了挂载选项(mountOptions)。


Kubernetes支持的PV类型如下。
◎ AWSElasticBlockStore:AWS公有云提供的Elastic Block Store。
◎ AzureFile:Azure公有云提供的File。
◎ AzureDisk:Azure公有云提供的Disk。
◎ CephFS:一种开源共享存储系统。
◎ Cinder:OpenStack块存储系统。
◎ FC(Fibre Channel):光纤存储设备。
◎ FlexVolume:一种插件式的存储机制。
◎ Flocker:一种开源共享存储系统。
◎ GCEPersistentDisk:GCE公有云提供的Persistent Disk。
◎ Glusterfs:一种开源共享存储系统。
◎ HostPath:宿主机目录,仅用于单机测试。
◎ iSCSI:iSCSI存储设备。
◎ Local:本地存储设备,从Kubernetes 1.7版本开始引入,到1.14版本时达到稳定版本,目前可以通过指定块设备(Block Device)提供Local PV,或通过社区开发的sig-storage-local-static-provisioner插件管理Local PV的生命周期。
◎ NFS:网络文件系统。
◎ Portworx Volumes:Portworx提供的存储服务。
◎ Quobyte Volumes:Quobyte提供的存储服务。
◎ RBD(Ceph Block Device):Ceph块存储。
◎ ScaleIO Volumes:DellEMC的存储设备。
◎ StorageOS:StorageOS提供的存储服务。
◎ VsphereVolume:VMWare提供的存储系统。
每种存储类型都有各自的特点,在使用时需要根据它们各自的参数进行设置。
PV资源对象需要设置的关键配置参数如下。
描述存储的容量,目前仅支持对存储空间的设置(storage=xx),未来可能加入IOPS、吞吐率等设置。
Kubernetes从1.13版本开始引入存储卷类型的设置(volumeMode=xxx),到1.18版本时达到稳定阶段。
可以设置的选项包括Filesystem(文件系统,默认值)和Block(块设备)。文件系统模式的PV将以目录(Directory)形式挂载到Pod内。如果模式为块设备,但是设备是空的,则Kubernetes会自动在块设备上创建一个文件系统。支持块设备的存储类型会以裸设备(Raw Block Device)的形式挂载到容器内,并且不会创建任何文件系统,适用于需要直接操作裸设备(速度最快)的应用程序。
目前有以下PV类型支持裸块设备类型:AWSElasticBlockStore、AzureDisk、FC(Fibre Channel)、GCEPersistentDisk、iSCSI、Local volume、OpenStack Cinder、RBD(Ceph Block Device)、VsphereVolume。
下面的示例使用了块设备的PV定义:

PV存储卷在挂载到宿主机系统上时,可以设置不同的访问模式(Access Modes)。PV支持哪些访问模式由存储提供商提供支持,例如NFS可以支持多个客户端同时读写(ReadWriteMany)模式,但一个特定的NFS PV也可以以只读(Read-only)模式导出到服务器上。
Kubernetes支持的访问模式如下。
◎ ReadWriteOnce(RWO):读写权限,并且只能被单个Node挂载。
◎ ReadOnlyMany(ROX):只读权限,允许被多个Node挂载。
◎ ReadWriteMany(RWX):读写权限,允许被多个Node挂载。
某些PV可能支持多种访问模式,但PV在挂载时只能使用一种访问模式,多种访问模式不能同时生效。
表8.2描述了不同的存储提供者支持的访问模式。
表8.2 不同的存储提供者支持的访问模式

▼续表

PV可以设定其存储的类别,通过storageClassName参数指定一个StorageClass资源对象的名称。具有特定类别的PV只能与请求了该类别的PVC绑定。未设定类别的PV则只能与不请求任何类别的PVC绑定。
通过PV定义中的persistentVolumeReclaimPolicy字段进行设置,可选项如下。
◎ Retain:保留数据,需要手工处理。
◎ Recycle:简单清除文件的操作(例如运行rm-rf/thevolume/*命令)。
◎ Delete:与PV相连的后端存储完成Volume的删除操作。
目前只有NFS和HostPath两种类型的PV支持Recycle策略;AWSElasticBlockStore、GCEPersistentDisk、AzureDisk和Cinder类型的PV支持Delete策略。
在将PV挂载到一个Node上时,根据后端存储的特点,可能需要设置额外的挂载选项的参数,这个可以在PV定义中的mountOptions字段进行设置。下面的例子为对一个类型为gcePersistentDisk的PV设置挂载选项的参数:


目前,以下PV类型支持设置挂载选项:AWSElasticBlockStore、AzureDisk、AzureFile、CephFS、Cinder (OpenStack block storage)、GCEPersistentDisk、Glusterfs、NFS、Quobyte Volumes、RBD (Ceph Block Device)、StorageOS、VsphereVolume、iSCSI。
注意,Kubernetes不会对挂载选项进行验证,如果设置了错误的挂载选项,则挂载将会失败。
PV可以设置节点亲和性来限制只能通过某些Node访问Volume,可以在PV定义的nodeAffinity字段中进行设置。使用这些Volume的Pod将被调度到满足条件的Node上。
公有云提供的存储卷(如AWSElasticBlockStore、GCEPersistentDisk、AzureDisk等)都由公有云自动完成节点亲和性设置,无须用户手工设置。对于Local类型的PV,需要手工设置,例如:


某个PV在生命周期中可能处于以下4个阶段(Phase)之一。
◎ Available:可用状态,还未与某个PVC绑定。
◎ Bound:已与某个PVC绑定。
◎ Released:与之绑定的PVC已被删除,但未完成资源回收,不能被其他PVC使用。
◎ Failed:自动资源回收失败。
在定义了PV资源之后,就需要通过定义PVC来使用PV资源了。
PVC作为用户对存储资源的需求申请,主要涉及存储空间请求、访问模式、PV选择条件和存储类别等信息的设置。下例声明的PVC具有如下属性:申请8GiB存储空间,访问模式为ReadWriteOnce,PV选择条件为包含release=stable标签并且包含条件为environment In[dev] 的标签,存储类别为“slow”(要求在系统中已存在名为slow的StorageClass)。


对PVC的关键配置参数说明如下。
(1)资源请求(Resources):描述对存储资源的请求,通过resources.requests.storage字段设置需要的存储空间大小。
(2)访问模式(Access Modes):PVC也可以设置访问模式,用于描述用户应用对存储资源的访问权限。其三种访问模式的设置与PV的设置相同。
(3)存储卷模式(Volume Modes):PVC也可以设置存储卷模式,用于描述希望使用的PV存储卷模式,包括文件系统(Filesystem)和块设备(Block)。PVC设置的存储卷模式应该与PV存储卷模式相同,以实现绑定;如果不同,则可能出现不同的绑定结果。在各种组合模式下是否可以绑定的结果如表8.3所示。
表8.3 PV和PVC各种组合模式下是否可以绑定

(4)PV选择条件(Selector):通过Label Selector的设置,可使PVC对于系统中已存在的各种PV进行筛选。系统将根据标签选出合适的PV与该PVC进行绑定。对选择条件可以使用matchLabels和matchExpressions进行设置,如果两个字段都已设置,则Selector的逻辑将是两组条件同时满足才能完成匹配。
(5)存储类别(Class):PVC在定义时可以设定需要的后端存储的类别(通过storageClassName字段指定),以减少对后端存储特性的详细信息的依赖。只有设置了该Class的PV才能被系统选出,并与该PVC进行绑定。PVC也可以不设置Class需求,如果storageClassName字段的值被设置为空(storageClassName=""),则表示该PVC不要求特定的Class,系统将只选择未设定Class的PV与之匹配和绑定。PVC也可以完全不设置storageClassName字段,此时将根据系统是否启用了名为DefaultStorageClass的admission controller进行相应的操作。
◎ 启用DefaultStorageClass:要求集群管理员已定义默认的StorageClass。如果在系统中不存在默认的StorageClass,则等效于不启用DefaultStorageClass的情况。如果存在默认的StorageClass,则系统将自动为PVC创建一个PV(使用默认StorageClass的后端存储),并将它们进行绑定。集群管理员设置默认StorageClass时,会在StorageClass的定义中加上一个annotation“storageclass.kubernetes.io/is-default-class=true”。如果管理员将多个StorageClass都定义为default,则由于不唯一,系统将无法创建PVC。
◎ 未启用DefaultStorageClass:等效于PVC设置storageClassName的值为空(storageClassName=""),即只能选择未设定Class的PV与之匹配和绑定。
当Selector和Class都进行了设置时,系统将选择两个条件同时满足的PV与之匹配。
另外,如果PVC设置了Selector,则系统无法使用动态供给模式为其分配PV。
在PVC创建成功之后,Pod就可以以存储卷(Volume)的方式使用PVC的存储资源了。PVC受限于命名空间,Pod在使用PVC时必须与PVC处于同一个命名空间。
Kubernetes为Pod挂载PVC的过程如下:系统在Pod所在的命名空间中找到其配置的PVC,然后找到PVC绑定的后端PV,将PV存储挂载到Pod所在Node的目录下,最后将Node的目录挂载到Pod的容器内。
在Pod中使用PVC时,需要在YAML配置中设置PVC类型的Volume,然后在容器中通过volumeMounts.mountPath设置容器内的挂载目录,示例如下:


如果存储卷模式为块设备(Block),则PVC的配置与默认模式(Filesystem)略有不同。下面对如何使用裸块设备(Raw Block Device)进行说明。
假设使用裸块设备的PV已创建,例如:

PVC的YAML配置示例如下:


使用裸块设备PVC的Pod定义如下。与文件系统模式PVC的用法不同,容器不使用volumeMounts设置挂载目录,而是通过volumeDevices字段设置块设备的路径devicePath:

在某些应用场景中,同一个Volume可能会被多个Pod或者一个Pod中的多个容器共享,此时可能存在各应用程序需要使用不同子目录的需求。这可以通过Pod的volumeMounts定义的subPath字段进行设置。通过对subPath的设置,在容器中将以subPath设置的目录而不是在Volume中提供的默认根目录作为根目录使用。
下面的两个容器共享同一个PVC(及后端PV),但是各自在Volume中可以访问的根目录由subPath进行区分,mysql容器使用Volume中的mysql子目录作为根目录,php容器使用Volume中的html子目录作为根目录:


注意,subPath中的路径名称不能以“/”开头,需要用相对路径的形式。
在一些应用场景中,如果希望通过环境变量来设置subPath路径,例如使用Pod名称作为子目录的名称,则可以通过subPathExpr字段提供支持。subPathExpr字段用于将Downward API的环境变量设置为存储卷的子目录,该特性在Kubernetes 1.17版本时达到稳定阶段。
需要注意的是,subPathExpr字段和subPath字段是互斥的,不能同时使用。
下面的例子通过Downward API将Pod名称设置为环境变量POD_NAME,然后在挂载存储卷时设置subPathExpr=$(POD_NAME)子目录:


关于Downward API的概念和应用请参考3.6节的说明。
StorageClass作为对存储资源的抽象定义,对用户设置的PVC申请屏蔽后端存储的细节,一方面减少了用户对于存储资源细节的关注,另一方面减轻了管理员手工管理PV的工作,由系统自动完成PV的创建和绑定,实现动态的资源供应。基于StorageClass的动态资源供应模式将逐步成为云平台的标准存储管理模式。
StorageClass资源对象的定义主要包括名称、后端存储的提供者(provisioner)、后端存储的相关参数配置和回收策略。StorageClass的名称尤为重要,将在创建PVC时引用,管理员应该准确命名具有不同存储特性的StorageClass。
StorageClass一旦被创建,则无法修改。如需更改,则只能删除原StorageClass资源对象并重新创建。
下例定义了一个StorageClass,名称为standard,provisioner为aws-ebs,type为gp2,回收策略为Retain等:


StorageClass资源对象需要设置的关键配置参数如下。
描述存储资源的提供者,用于提供具体的PV资源,也可以将其看作后端存储驱动。目前,Kubernetes内置支持的Provisioner包括AWSElasticBlockStore、AzureDisk、AzureFile、Cinder(OpenStack Block Storage)、Flocker、GCEPersistentDisk、GlusterFS、Portworx Volume、Quobyte Volumes、RBD(Ceph Block Device)、ScaleIO、StorageOS、VsphereVolume。
Kubernetes内置支持的Provisioner的命名都以“kubernetes.io/”开头,用户也可以使用自定义的后端存储提供者。为了符合StorageClass的用法,自定义Provisioner需要符合存储卷的开发规范。外部存储供应商的作者对代码、提供方式、运行方式、存储插件(包括Flex)等具有完全的自由控制权。目前,在Kubernetes的kubernetes-sigs/sig-storage-lib-external-provisioner库中维护外部Provisioner的代码实现,其他一些Provisioner也在kubernetes-incubator/external-storage库中进行维护。
例如,对NFS类型,Kubernetes没有提供内部的Provisioner,但可以使用外部的Provisioner。也有许多第三方存储提供商自行提供外部的Provisioner。
通过动态资源供应模式创建的PV将继承在StorageClass资源对象上设置的回收策略,配置字段名称为“reclaimPolicy”,可以设置的选项包括Delete(删除)和Retain(保留)。
如果StorageClass没有指定reclaimPolicy,则默认值为Delete。
对于管理员手工创建的仍被StorageClass管理的PV,将使用创建PV时设置的资源回收策略。
PV可以被配置为允许扩容,当StorageClass资源对象的allowVolumeExpansion字段被设置为true时,将允许用户通过编辑PVC的存储空间自动完成PV的扩容,该特性在Kubernetes 1.11版本时达到Beta阶段。
表8.4描述了支持存储扩容的Volume类型和要求的Kubernetes最低版本。
表8.4 支持存储扩容的Volume类型和要求的Kubernetes最低版本

注意,该特性仅支持扩容存储空间,不支持减少存储空间。
通过StorageClass资源对象的mountOptions字段,系统将为动态创建的PV设置挂载选项。并不是所有PV类型都支持挂载选项,如果PV不支持但StorageClass设置了该字段,则PV将会创建失败。另外,系统不会对挂载选项进行验证,如果设置了错误的选项,则容器在挂载存储时将直接失败。
StorageClass资源对象的volumeBindingMode字段设置用于控制何时将PVC与动态创建的PV绑定。目前支持的绑定模式包括Immediate和WaitForFirstConsumer。
存储绑定模式的默认值为Immediate,表示当一个PersistentVolumeClaim(PVC)创建出来时,就动态创建PV并进行PVC与PV的绑定操作。需要注意的是,对于拓扑受限(Topology-limited)或无法从全部Node访问的后端存储,将在不了解Pod调度需求的情况下完成PV的绑定操作,这可能会导致某些Pod无法完成调度。
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。
在使用WaitForFirstConsumer模式的环境中,如果仍然希望基于特定拓扑信息(Topology)进行PV绑定操作,则在StorageClass的定义中还可以通过allowedTopologies字段进行设置。下面的例子通过matchLabelExpressions设置目标Node的标签选择条件(zone=us-central1-a或us-central1-b),PV将在满足这些条件的Node上允许创建:

后端存储资源提供者的参数设置,不同的Provisioner可能提供不同的参数设置。某些参数可以不显示设定,Provisioner将使用其默认值。目前StorageClass资源对象支持设置的存储参数最多为512个,全部key和value所占的空间不能超过256KiB。
下面是一些常见存储提供商(Provisioner)提供的StorageClass存储参数示例。

可以配置的参数如下(详细说明请参考AWSElasticBlockStore文档)。
◎ type:可选项为io1、gp2、sc1、st1,默认值为gp2。
◎ iopsPerGB:仅用于io1类型的Volume,意为每秒每GiB的I/O操作数量。
◎ fsType:文件系统类型,默认值为ext4。
◎ encrypted:是否加密。
◎ kmsKeyId:加密时使用的Amazon Resource Name。

可以配置的参数如下(详细说明请参考GCEPersistentDisk文档)。
◎ type:可选项为pd-standard、pd-ssd,默认值为pd-standard。
◎ fsType:文件系统类型,默认值为ext4。
◎ replication-type:复制类型,可选项为none、regional-pd,默认值为none。

可以配置的参数如下(详细说明请参考GlusterFS和Heketi的文档)。
◎ resturl:Gluster REST服务(Heketi)的URL地址,用于自动完成GlusterFSvolume的设置。
◎ restauthenabled:是否对Gluster REST服务启用安全机制。
◎ restuser:访问Gluster REST服务的用户名。
◎ restuserkey:访问Gluster REST服务的密码。
◎ secretNamespace和secretName:保存访问Gluster REST服务密码的Secret资源对象名。
◎ clusterid:GlusterFS的Cluster ID。
◎ gidMin和gidMax:StorageClass的GID范围,用于动态资源供应时为PV设置的GID。
◎ volumetype:设置GlusterFS的内部Volume类型,例如replicate:3(Replicate类型,3份副本);disperse:4:2(Disperse类型,数据4份,冗余两份);none(Distribute类型)。


Local类型的PV在Kubernetes 1.14版本时达到稳定阶段,它不能以动态资源供应的模型进行创建,但仍可为其设置一个StorageClass,以延迟到一个使用PVC的Pod创建出来再进行PV的创建和绑定,这可以通过设置参数volumeBindingMode=WaitForFirstConsumer进行控制。
其他Provisioner的StorageClass相关参数设置请参考它们各自的配置手册。
在Kubernetes中,管理员可以为有不同存储需求的PVC创建相应的StorageClass来提供动态的存储资源(PV)供应,同时在集群级别设置一个默认的StorageClass,为那些未指定StorageClass的PVC使用。当然,管理员要明确系统默认提供的StorageClass应满足和符合PVC的资源需求,同时注意避免资源浪费。
要在集群中启用默认的StorageClass,就需要在kube-apiserver服务准入控制器--enable-admission-plugins中开启DefaultStorageClass(从Kubernetes 1.10版本开始默认开启):

然后,在StorageClass的定义中设置一个annotation:

通过kubectl create命令创建成功后,查看StorageClass列表,可以看到名为gold的StorageClass被标记为default:

后续在创建未指定StorageClass的PVC时,系统将自动为其设置集群中的默认StorageClass。