Kubermetes对于有状态的容器应用或者对数据需要持久化的应用,不仅需要将容器内的目录挂载到宿主机的目录或者emptyDir临时存储卷,而且需要更加可靠的存储来保存应用产生的重要数据,以便容器应用在重建之后,仍然可以使用之前的数据。不过,存储资源和计算资源(CPU/内存)的管理方式完全不同。为了能够屏蔽底层存储实现的细节,让用户方便使用,同时能让管理员方便管理, Kubernetes从v1.0版本就引入PersistentVolumePersistentVolumeClaim两个资源对象来实现对存储的管理子系统。

PersistentVolume (PV)是对底层网络共享存储的抽象,将共享存储定义为一种“资源”,比如节点(Node) 也是一种容 器应用可以“消费”的资源。PV由管理员进行创建和配置,它与共享存储的具体实现直接相关,例如GlusterFS、iSCSI、 RBD或GCB/AWS公有云提供的共享存储,通过插件式的机制完成与共享存储的对接,以供应用访问和使用。

PersistentVolumeClaim (PVC)则是用户对于存储资源的一个“申请”。就像Pod“消费”Node的资源一-样, PVC会“消费”PV资源。PVC 可以申请特定的存储空间和访问模式。

StorageClass,使用PVC“申请”到一定的存储空间仍然不足以满足应用对于存储设备的各种需求。通常应用程序都会对存储设备的特性和性能有不同的要求,包括读写速度、并发性能、数据冗余等更高的要求,Kubernetes 从v1.4版本开始引入了-一个新的资源对象StorageClass,用于标记存储资源的特性和性能。到v1.6版本时,StorageClass动态资源供应的机制得到了完善,实现了存储卷的按需创建,在共享存储的自动化管理进程中实现了重要的一步。

通过StorageClass的定义,管理员可以将存储资源定义为某种类别(Class), 正如存储设备对于自身的配置描述(Profile),例如“快速存储”“慢速存储”“有数据冗余”“无数据冗余”等。用户根据StorageClas的描述就能够直观得知各种存储资源的特性,就可以根据应用对存储资源的需求去申请存储资源了。

下面对Kubermetes的PVPVCStorageClass动态资源供应等共享存储管理机制进行详细说明。

PV 详解

PV作为存储资源,主要包括存储能力、访问模式、存储类型、回收策略、后端存储类型等关键信息的设置。下面的例子声明的PV具有如下属性: 5Gi 存储空间,访问模式为“ReadWriteOnce”,存储类型为“slow" (要求系统中已存在名为slow的StorageClass),回收策略为“Recycle",并且后端存储类型为“nfs”(设置了NFS Server的IP地址和路径):

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv1
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: slow
  nfs:
    path: /tmp
    server: 172.17.0.2

Kubernetes支持的PV类型如下。

  • gcePersistentDisk: GCE公有云提供的PersistentDisk。
  • AWSElasticBlockStore: AWS公有云提供的ElasticBlockStore.
  • AzureFile: Azure公有云提供的File。
  • AzureDisk: Azure 公有云提供的Disk。
  • FC ( Fibre Channel)。
  • Flocker。
  • NFS:网络文件系统。
  • iSCSI。
  • RBD (Rados Block Device); Ceph块存储。
  • CephFS。
  • Cinder: OpenStack Cinder块存储。
  • GlusterFS。
  • VsphereVolume.
  • Quobyte Volumes。
  • VMware Photon。
  • Portworx Volumes。
  • ScaleIO Volumes。
  • HostPath:宿主机目录,仅用于单机测试。

每种存储类型都有各自的特点,在使用时需要根据它们各自的参数进行设置。

1、Capacity(容量)

描述存储设备具备的能力,目前仅支持对存储空间的设置(storage=xx),未来可能加入

2、访问模式(Access Modes)

  • ReadWriteOnce (简写为 RWO): 读写权限,并且只能被单个Node挂载。
  • ReadOnlyMany (简写为 ROX): 只读权限,允许被多个Node挂载。
  • ReadWriteMany (简写为 RWX): 读写权限,允许被多个Node挂载。

注意:即使volume支持很多种访问模式,但它同时只能使用一种访问模式。比如,GCEPersistentDisk可以被单个节点映射为ReadWriteOnce,或者多个节点映射为ReadOnlyMany,但不能同时使用这两种方式来映射。

 

Volume Plugin

ReadWriteOnce

ReadOnlyMany

ReadWriteMany

AWSElasticBlockStore


-

-

AzureFile




AzureDisk


-

-

CephFS




Cinder


-

-

FC



-

FlexVolume



-

Flocker


-

-

GCEPersistentDisk



-

Glusterfs




HostPath


-

-

iSCSI



-

PhotonPersistentDisk


-

-

Quobyte




NFS




RBD



-

VsphereVolume


-

-

PortworxVolume


-


ScaleIO



-

3、存储类别(Class)

PV可以设定其存储的类别(Class),通过storageClassName参数指定一个StorageClass资源对象的名称。具有特定“类别”的PV只能与请求该“类别”的PVC进行绑定。未设定“类别”的PV则只能与不请求任何“类别”的PVC进行绑定。

4、回收策略(Reclaim Policy)

目前支持如下三种回收策略。

  • 保留(Retain): 保留数据,需要手工处理。
  • 回收空间( Recycle): 简单清除文件的操作(例如执行rm -rf /thevolume/*命令)。
  • 删除(Delete): 与PV相连的后端存储完成volume的删除操作(如AWS EBS、GCE PD、Azure Disk、OpenStack Cinder等设备的内部volume清理)。

目前,只有NFS和HostPath两种类型的存储支持“Recycle”策略; AWS EBS、GCE PD、Azure Disk和Cinder volumes支持“Delete”策略。

2. PV生命周期的各个阶段( Phase )

某个PV在生命周期中,可能处于以下4个阶段之一。

  • Available: 可用状态,还未与某个PVC绑定。
  • Bound: 已与某个PVC绑定。
  • Released: 绑定的PVC已经删除,资源已释放,但没有被集群回收。
  • Failed: 自动资源回收失败。

3. PV的挂载参数( Mount Options )

在将PV挂载到一个Node上时,根据后端存储的特点,可能需要设置额外的挂载参数,目前可以通过在PV的定义中,设置一个名为“volume.beta.kubernetes.io/mount-options"的annotation来实现。下面的例子对一个类型为gcePersistentDisk的PV设置了挂载参数“discard":

apiVersion: "v1"
kind: "PersistentVolume"
metadata :
  name: gce-disk-1
  annotations:
  volume.beta.kubernetes.io/mount-options: "discard"
spec: 
  capacity:
    storage : "10Gi”
  accessModes :
    - ”ReadWriteOnce”
gcePersistentDisk:
  fsType: "ext4"
  pdName : "gce-disk-1

并非所有类型的存储都支持设置挂载参数。从Kubernetes v1.6版本开始,以下存储类型支持设置挂载参数。

  • gcePersistentDisk。
  • AWSElasticBlockStore.
  • AzureFile。
  • AzureDisk。
  • NFS。
  • iSCSI。
  • RBD
  • (Rados Block Device): Ceph 块存储。
  • CephFS。
  • Cinder: OpenStack 块存储。
  • GlusterFS。
  • VsphereVolume.
  • Quobyte Volumes.
  • VMware Photon。

PVC详解

PVC 作为用户对存储资源的需求申请,主要包括存储空间请求、访问模式、PV选择条件和存储类别等信息的设置。下面的例子中声明的PVC具有如下属性:申请8Gi存储空间,访问模式为"ReadWriteOnce",PV选择条件为包含标签"release=stable"并且包含条件为"environment In [dev]"的标签,存储类别为"slow"(要求系统中已存在名为slow的StorageClass)。

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: myclaim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 8Gi
  storageClassName: slow
  selector:
    matchLabels:
      release: "stable"
    matchExpressions:
     - {key: environment, operator: In, values: [dev]}

PVC的关键配置参数说明如下:

  • 资源请求(Resources):描述对存储资源的请求,目前仅支持request.storage的设置,即存储空间大小。
  • 访问模式(Access Modes):PVC也可以设置访问模式,用于描述用户应用对存储资源的访问权限。可以设置的三种访问模式与PV相同。
  • PV选择条件(Selector):通过Label Selector的设置,可使PVC对于系统中已存在的各种PV进行筛选。系统将根据标签选择出合适的PV与该PVC进行绑定。选择条件可以使用matchLabels和matchExpressions进行设置。如果两个条件都设置了,则Selector的逻辑是两组条件同时满足才能完成匹配。
  • 存储类别(Class):PVC在定义时可以设定需要的后端存储的"类别"(通过storageClassName字段指定),以降低对后端存储特性的详细信息的依赖。只有设置了该Class的PV才能被系统选出,并与该PVC进行绑定。

PVC也可以不设置Class需求。如果storageClassName字段的值被设置为空(storageClassName=""),则表示该PVC不要求特定的Class,系统将只选择未设定Class的PV与之匹配和绑定。PVC也可以完全不设置storageClassName字段,此时将根据系统是否启用了名为"DefaultStorageClass"的admission controller进行相应的操作。

  • 未启用DefaultStorageClass:等效于PVC设置storageClassName的值为空,即只能选择未设定Class的PV与之匹配和绑定。
  • 启用了DefaultStorageClass:要求集群管理员已定义默认的StorageClass。如果系统中不存在默认的StorageClass,则等效于不启用DefaultStorageClass的情况。如果存在默认的StorageClass,则系统将自动为PVC创建一个PV(使用默认StorageClass的后端存储),并将它们进行绑定。集群管理员设置默认StorageClass的方法为,在StorageClass的定义中加上一个annotation "storageclass.kubernetes.io/is-default-class=true"。如果管理员将多个StorageClass都定义为default,则由于不唯一,系统将无法为PVC创建相应的PV。

注意,PVC和PV都受限于namespace,PVC在选择PV时受到namespace的限制,只有相同namespace中的PV才可能与PVC绑定。Pod在引用PVC时同样受namespace的限制,只有相同namespace中的PVC才能挂载到Pod内。

当Selector和Class都进行了设置时,系统将选择两个条件同时满足的PV与之匹配。

另外,如果资源供应使用的是动态模式,即管理员没有预先定义PV,仅通过StorageClass交给系统自动完成PV的动态创建,那么PVC再设定Selector时,系统将无法为其供应任何存储资源了。

在启动动态供应模式的情况下,一旦用户删除了PVC,与之绑定的PV将根据其默认的回收策略"Delete"也会被删除。如果需要保留PV(用户数据),则在动态绑定成功后,用户需要将系统自动生成PV的回收策略从"Delete"改成"Retain"。

PV和PVC的生命周期

PV可以看作可用的存储资源,PVC则是对存储资源的需求,PV和PVC的相互关系遵循下图所示的生命周期。

Kubernetes 存储后端 kubernetes 对象存储_存储空间

 

 


1 资源供应(Provisioning)

k8s支持两种资源的供应模式:静态模式(Static)动态模式(Dynamic)。资源供应的结果就是创建好的PV。

  • 静态模式:集群管理员手工创建许多PV,在定义PV时需要将后端存储的特性进行设置。
  • 动态模式:集群管理员无须手工创建PV,而是通过StorageClass的设置对后端存储进行描述,标记为某种“类型(Class)”。此时要求PVC对存储类型进行声明,系统将自动完成PV的创建及与PVC的绑定。PVC可以声明Class为"",说明该PVC禁止使用动态模式。

2 资源绑定(Binding)

在用户定义好PVC之后,系统将根据PVC对存储资源的请求(存储空间和访问模式)在已存在的PV中选择一个满足PVC要求的PV,一旦找到,就将该PV与用户定义的PVC进行绑定,然后用户的应用就可以使用这个PVC了。如果系统中没有满足PVC要求的PV,PVC就会无限期处于Pending状态,直到等到系统管理员创建了一个符合其要求的PV。PV一旦绑定到某个PVC上,就被这个PVC独占,不能再与其他PVC进行绑定了。在这种情况下,当PVC申请的存储空间与PV的少时,整个PV的空间都会被PVC所用,可能会造成资源的浪费。如果资源供应使用的是动态模式,则系统在为PVC找到合适的StorageClass后,将自动创建一个PV并完成与PVC的绑定。

3 资源使用(Using)

Pod使用volume的定义,将PVC挂载到容器内的某个路径进行使用。volume的类型为"persistentVolumeClaim",在后面的示例中再进行详细说明。在容器应用挂载了一个PVC后,就能被持续独占使用。不过,多个Pod可以挂载同一个PVC,应用程序需要考虑多个实例共同访问同一块存储空间的问题。

4 资源释放(Releasing)

当用户对存储资源使用完毕后,用户可以删除PVC,与该PVC绑定的PV将会被标记为“已释放”,但还不能立刻与其他PVC进行绑定。通过之前PVC写入的数据可能还留在存储设备上,只有在清除之后该PV才能再次使用。

5 资源回收(Reclaimig)

对于PV,管理员可以设定回收策略(Reclaim Policy),用于设置与之绑定的PVC释放资源之后,对于遗留数据如何处理。只有PV的存储空间完成回收,才能供新的PVC绑定和使用。

下面通过两张图分别对在静态资源供应模式和动态资源供应模式下,PV、PVC、StorageClass及Pod使用PVC的原理进行说明。

在静态资源供应模式下,通过PV和PVC完成绑定,并供Pod使用的存储管理机制。

 

Kubernetes 存储后端 kubernetes 对象存储_存储类型_02

 

 在动态资源供应模式下,通过StorageClass和PVC完成资源动态绑定(系统自动生成PV),并供Pod使用的存储管理机制。

Kubernetes 存储后端 kubernetes 对象存储_Kubernetes 存储后端_03

 

 

StorageClass详解

StorageClass作为对存储资源的抽象定义,对用户设置的PVC申请屏蔽后端存储的细节。一方面减轻用户对于存储资源细节的关注,另一方面也减轻管理员手工管理PV的工作,由系统自动完成PV的创建和绑定,实现动态的资源供应。使用基于StorageClass的动态资源供应模式将逐步成为云平台的标准存储配置模式。

StorageClass的定义主要包括名称、后端存储的提供者(Provisioner)和后端存储的相关参数配置。StorageClass一旦被创建出来,就将无法修改,只能删除原StorageClass的定义重建。下面的例子中定义了一个名为“standard"的StorageClass,提供者为aws-ebs,其参数设置了一个type=gp2。

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: standard
provisioner: kubernetes.io/aws-ebs
parameters:
  type: gp2

1 StorageClass的关键配置参数

1)提供者(Provisioner)

描述存储资源的提供者,也可以看作后端存储驱动。
目前k8s支持的Provisioner都以"kubernetes.io/"为开头,用户也可以使用自定义的后端存储提供者。为了符合StorageClass的用法,自定义Provisioner需要符合存储卷的开发规范,详见该链接的说明:https://github.com/kubernetes/community/blob/master/contributors/design-proposals/storage/volume-provisioning.md 。

2)参数(Parameters)

后端存储资源提供者的参数设置,不同的Provisioner包括不同的参数设置。某些参数可以不显示设定,Provisioner将使用其默认值。

3)下面介绍几种常用的Provisioner对StorageClass的定义进行详细说明

AWS EBS存储卷
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: slow
provisioner: kubernetes.io/aws-ebs
parameters:
  type: io1
  zone: us-east-id
  iopsPerGB: "10"

参数说明如下:

  • type:可选项为io1, gp2, sc1, st1, 默认值为gp2
  • zone:AWS zone的名称
  • iopsPerGB:仅用于io1类型的volume,意为每秒每GiB的I/O操作数量
  • encrypted:是否加密
  • kmsKeyId:加密时的Amazon Resource Name
GCE PD存储卷
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: slow
provisioner: kubernetes.io/gce-pd
parameters:
  type: pd-standard
  zone: us-centrall-a

参数说明:

  • type:可选项为pd-standard, pd-ssd, 默认值为pd-standard
  • zone:GCE zone名称
GlusterFS存储卷
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: slow
provisioner: kubernetes.io/glusterfs
parameters:
  resturl: "https://127.0.0.1:8081"
  clusterid: "sadfa2435hfghsrg462345"
  restauthenabled: "true"
  restuser: "admin"
  secretNamespace: "default"
  secretName: "heketi-secret"
  gidMin: "40000"
  gidMax: "50000"
  volumetype: "replicate:3"

参数说明如下(详细说明请参考GlusterFS和Heketi的文档)。

  • resturl: Gluster REST服务(heketi)的URL地址,用于自动完成GlusterFSvolume的设置。
  • restauthenabled: 是否对Gluster REST服务启用安全机制。
  • restuser: 访问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份,冗余2份);none(Distribute类型)。
OpenStack Cinder存储卷
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: gold
provisioner: kubernetes.io/cinder
parameters:
  type: fast
  availability: nova

参数说明如下:

  • type: Cinder的VolumeType, 默认值为空。
  • availability: Availability Zone, 默认值为空。

其他Provisioner的StorageClass相关参数设置请参考它们各自的配置手册。

2 设置默认的StorageClass

要在系统中设置一个默认的StorageClass,首先需要启动名为"DefaultStorageClass"admission controller, 即在kube-apiserver的命令行参数--admission-controll中增加:
--admission-control=...,DefaultStorageClass

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

 

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: gold
  annotations:
    storageclass.beta.kubernetes.io/is-default-class="true"
provisioner: kubernetes.io/cinder
parameters:
  type: fast
  availability: nova

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

# kubectl get sc
gold (default)  kubernetes.io/cinder

更多信息请参考:https://www.orchome.com/1284