本文描述了目前kubernetes中持久卷(PersistentVolume)的情况,建议先熟悉卷(Volume)的概念。 在云环境下,存储资源管理和计算资源管理有区别。持久卷(PersistentVolume)子系统提供了API,屏蔽了底层的细节,用户和管理员不用关心存储如何提供,如何消耗等。为此,我们在kubernetes 1.4中引入了两个新的API资源(kind):PersistentVolume和PersistentVolumeClaim。
持久卷(PV) 通常我们把存储做成集群,对外表现为一个网络存储,持久卷(PV)是这个资源中的一个片段,就像node和cluster的关系。PV是跟Volume一样是卷插件【详见kubernetes Volume概念】,但其生命周期不依赖任何单个的pod,底层存储实现可以是NFS,iSCSI,云存储等,都通过API对象对外暴露,对用户透明。
持久卷请求(PVC) 用户通过持久卷请求(Persistent Volume Claim – PVC) 申请存储资源,PVC vs PV可以类比pod和node的关系,pod会消耗node的资源,PVC消耗PV的资源。pod可以申请计算资源的粒度(CPU、内存),PVC 可以申请大小、访问方式(例如mount rw一次或mount ro多次等多种方式)。
存储级别 经过API抽象,用户可以通过PVC使用存储资源,通常用户还会关心PV的很多属性,例如对不同的应用场景需要不同的性能,仅仅提供存储大小和访问模式不能满足要求。集群管理员一方面要提供不同PV的多种属性,一方面要隐藏底层的细节,就引入了StorageClass资源。管理员用存储级别StorageClass描述存储的分类,不同的分类可以对应不同的质量服务Qos等级、备份策略和其他自定义的策略。kubernetes本身不参与存储级别的划分,StorageClass概念在有的存储系统里被称为”profiles”。
如果想尝试PersistentVolumeClaim,请点击详细案例。
生命周期
PV是集群的资源,PVC请求资源并检查资源是否可用,PV和PVC生命周期如下:
资源提供
包含静态和动态两种提供方式。
静态
存储集群先创建一定数量的PV,PV包含了真实存储的底层细节,用户通过kubernetes API使用存储。
动态
在现有PV不满足PVC的请求时,管理员可以使用依据存储分类(StorageClass),描述具体过程为:PV先创建分类,PVC请求已创建的某个类的资源,这样就达到动态配置的效果。请求类有效的禁止了动态配置自己。
绑定
用户根据所需存储空间大小和访问模式创建(或在动态部署中已创建)一个 PersistentVolumeClaim。Kubernetes的Master节点循环监控新产生的PVC,找到与之匹配的PV(如果有的话),并把他们绑定在一起。动态配置时,循环会一直将PV与这个PVC绑定,直到PV完全匹配PVC。避免PVC请求和得到的PV不一致。绑定一旦形成,PersistentVolumeClaim绑定就是独有的,不管是使用何种模式绑定的。
如果找不到匹配的volume,用户请求会一直保持未绑定状态。在匹配的volume可用之后,用户请求将会被绑定。比如,一个配置了许多50Gi PV的集群不会匹配到一个要求100Gi的PVC。 只有在100Gi PV被加到集群之后,这个PVC才可以被绑定。
使用
Pods 使用Claims做为volumes。集群检查Claim,查找绑定的volume,并为Pod挂载这个volume。对于支持多访问模式的volume,用户在Pod中使用Claim时可指定自己想要的访问模式。
用户一旦有了Claim,并且被绑定,那么被绑定的PV将一直属于该用户。用户可通过在Pod volume块中包涵PersistentVolumeClaim的方式来调度Pods,并访问他们所要求的PV。
释放
当用户使用完volume后,可以从API中删除PVC对象,这样资源就可以被回收了。Claim被删除之后,volume被认为是‘释放’状态,但它还不能被其它claim使用。之前使用者的数据还保留在volume上,这个必须按一定策略进行处理。
回收利用
PersistentVolume的重用策略将告诉集群在volume被释放之后该如何进行处理。volume被释放后可用保留,回收或删除。保留支持手工重分配资源。
删除(需要volume插件支持),支持从Kubernetes中删除PersistentVolume对象,并支持从外部设施中(比如AWS EBS, GCE PD or Cinder volume)删除对应的存储资源。动态部署的volumes会被直接删除。
回收(需要volume插件支持),可对volume执行基本的删除操作(rm -rf /thevolume/*) ,并使它对新的claim可用。
持久存储的种类
Kubernetes通过插件支持下列存储:
- GCEPersistentDisk
- AWSElasticBlockStore
- AzureFile
- FC (Fibre Channel)
- NFS
- iSCSI
- RBD (Ceph块设备)
- CephFS
- Cinder (openstack的快存储)
- Glusterfs
- VsphereVolume
- HostPath (只能用于单节点)
持久卷(PV)
每个PV定义中包含spec和status,下面是一个简单的例子:
apiVersion: v1 kind: PersistentVolume metadata: name: pv0003 annotations: volume.beta.kubernetes.io/storage-class: "slow" spec: capacity: storage: 5Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Recycle nfs: path: /tmp server: 172.17.0.2
容量
一般来说,PV通过capacity属性定义容量大小。可以通过查看Kubernetes资源模型理解容量需求。
目前仅支持容量大小,将来会包括iops,吞吐量等属性。
访问方式
存储有很多种,每种存储又有自己的特性,PV访问不同的存储会有不同的访问方式,例如NFS支持多个rw的客户端,但具体到NFS PV可能会用只读方式export。对不同PV的特性,每个PV有自己的访问方式。
访问方式包括:
ReadWriteOnce – 被单个节点mount为读写rw模式
ReadOnlyMany – 被多个节点mount为只读ro模式
ReadWriteMany – 被多个节点mount为读写rw模式
在CLI下,访问方式被简写为:
RWO – ReadWriteOnce
ROX – ReadOnlyMany
RWX – ReadWriteMany
重要的是,在同一时刻,一个卷只能使用一种访问方式mount,例如GCEPersistentDisk被可以一个节点mount为ReadWriteOnce也可以被多个节点mount为ReadOnlyMany,但不能同时做。
下图列举了Kubernetes支持的存储插件的访问方式:
Volume Plugin | ReadWriteOnce | ReadOnlyMany | ReadWriteMany |
---|---|---|---|
AWSElasticBlockStore | x | – | – |
AzureFile | x | x | x |
CephFS | x | x | x |
Cinder | x | – | – |
FC | x | x | – |
FlexVolume | x | x | – |
GCEPersistentDisk | x | x | – |
Glusterfs | x | x | x |
HostPath | x | – | – |
iSCSI | x | x | – |
NFS | x | x | x |
RDB | x | x | – |
VsphereVolume | x | – | – |
分类
PV分类通过设置注释volume.beta.kubernetes.io/storage-class定义StorageClass的名称。一个特定的PV分类与PVC请求绑定。PV没有注释或注释为””表示没有分类,只能绑定到通用PVC。
未来正式版,volume.beta.kubernetes.io/storage-class注释会成为属性。
回收策略
现有回收策略有:
- Retain – 手动重新使用
- Recycle – 基本的删除操作 (“rm -rf /thevolume/*”)
- Delete – 关联的后端存储卷一起删除,后端存储例如AWS EBS, GCE PD或OpenStack Cinder
目前只有NFS和HostPath支持回收,AWS EBS, GCE PD和Cinder volumes只支持删除。
卷的状态
卷有四种状态,一个卷必属于其中之一:
- Available –闲置状态,没有被绑定到PVC
- Bound – 绑定到PVC
- Released – PVC被删掉,资源没有被在利用
- Failed – 自动回收失败
- CLI会显示绑定到PV的PVC名。
持久卷请求(PVC)
PVC包涵spec和status:
kind: PersistentVolumeClaim apiVersion: v1 metadata: name: myclaim annotations: volume.beta.kubernetes.io/storage-class: "slow" spec: accessModes: - ReadWriteOnce resources: requests: storage: 8Gi selector: matchLabels: release: "stable" matchExpressions: - {key: environment, operator: In, values: [dev]}
访问方式
PVC使用特定的访问方式式请求存储资源,并统一约定为卷。
资源
PVC可以像pod一样申请一定数量的资源,不过申请的是存储资源,kubernetes的资源模型同样适用于卷和PVC。
选择器
PVC可以指定一个标签选择器来进一步过滤卷集,只有匹配的的卷标签会被绑定到PVC,Selector包涵2项内容:
- matchLabels – 匹配标签,卷标签必须匹配某个值
- matchExpressions – 匹配表达式,由键值对,操作符构成,操作符包括 In,NotIn,Exists,和 DoesNotExist。
所有请求,必须全部满足matchLabels 和 matchExpressions的定义。
分类
PVC可以用特定的StorageClass名称,通过volume.beta.kubernetes.io/storage-class注释请求特定的PV分类。PV和PVC注释一致时,才能绑定。
PVC请求可以不带分类。PVC的注释为空“”表示此请求没有分类要求,所以只能被绑定到没有分类的PV(没有注释或注释为空“”)。集群有一个DefaultStorageClass准入插件的开关决定了无类PVC是否相同。
如果准入插件打开,管理员会指定一个缺省的存储类型StorageClass,所有无类PVC会被绑定到缺省PV, 把storageclass.beta.kubernetes.io/is-default-class 设置为“true”,就打开了缺省StorageClass。当没有缺省PV或is-default-class为false或缺省PV不唯一,准入插件会禁止创建PVC。
如果准入插件关闭,就没有缺省StorageClass的概念了。无类PVC只能被绑定到无类的PV,这样无类PV和PV注解为空””是一样的。
当PVC指定Selector请求StorageClass,所有请求做与连接:只有PV类和标签都符合请求才能绑定到PVC。需要注意,目前具有非空选择器的PVC不能使用动态配置的PV
未来正式版,volume.beta.kubernetes.io/storage-class注释会成为属性。
把PVC用作卷
pods 通过将PVC当做volume来访问存储。在pod使用PVC时,PVC必须存在于相同的namespace下。集群在pod的namespace中找到PVC,并用它获取支持PVC的PV。之后,volume将会被加载至host和pod中。
kind: Pod apiVersion: v1 metadata: name: mypod spec: containers: - name: myfrontend image: dockerfile/nginx volumeMounts: - mountPath: "/var/www/html" name: mypd volumes: - name: mypd persistentVolumeClaim: claimName: myclaim
Namespaces注意事项
PV的绑定是独占式的,而且因为PVC是namespace的对象,所以mount多种模式(ROX, RWX)的PVC只在同一namespace中。
存储级别
每个StorageClasse都包括provisioner和parameters字段。当属于class的PV需要动态提供时,他们会被派上用场。
StorageClass对象的名字非常重要,决定着用户该如何请求一个特定的class。在第一次创建StorageClass对象时,要设置class的名字和其他参数。对象一旦创建将无法更新。
管理员可单独为不需要绑定任何class的PVCs定义一个默认的StorageClass。详细请参考PersistentVolumeClaim部分。
kind: StorageClass apiVersion: storage.k8s.io/v1beta1 metadata: name: standard provisioner: kubernetes.io/aws-ebs parameters: type: gp2
Provisioner
storage classes的provisioner字段决定着哪个volumn插件被用来部署PV。这个字段必须指定。在beta版本中,可用的provisioner类型有 kubernetes.io/aws-ebs 和 kubernetes.io/gce-pd。
Parameters
Storage classes 的parameter字段用来描述属于该storage class的volume。不同的provisioner其参数也不同。比如说,io1对应type参数;iopsPerGB则被指定给EBS。当参数未被指定时,会用到一些缺省值。
AWS:
kind: StorageClass apiVersion: storage.k8s.io/v1beta1 metadata: name: slow provisioner: kubernetes.io/aws-ebs parameters: type: io1 zone: us-east-1d iopsPerGB: "10"
- type:io1, gp2, sc1, st1. 详细请参考 AWS docs for details. 缺省: gp2.
- zone:AWS zone. 如果未指定,将从Kubernetes cluster 节点所在的zone中随机选取一个。
- iopsPerGB:只对 io1 volumes。每秒每GiB的I/O操作。AWS volume 插件将这个值乘以所请求的volume大小来计算该volume的IOPS ,最大值为20000 IOPS(AWS所支持的最大值,参考AWS docs. 该字段为字符格式,即 “10”,非 10) encrypted: 指定EBS volume是否应该被加密。合法的值为 “true” or “false”. 该字段为字符格式,即 “true”,非 true.
- kmsKeyId:可选。当volume被加密时 Amazon Resource Name全名会被使用。如未指定,但 encrypted 是 true时,AWS会生成一个key值。 请参考 AWS docs 有效ARN值。
GCE:
kind: StorageClass apiVersion: storage.k8s.io/v1beta1 metadata: name: slow provisioner: kubernetes.io/gce-pd parameters: type: pd-standard zone: us-central1-a
- type:pd-standard 或 pd-ssd. 缺省: pd-ssd
- zone:GCE zone。 如未指定,将从控制管理器所在的区域中随机选取一个zone。
GlusterFS:
apiVersion: storage.k8s.io/v1beta1 kind: StorageClass metadata: name: slow provisioner: kubernetes.io/glusterfs parameters: endpoint: "glusterfs-cluster" resturl: "http://127.0.0.1:8081" restauthenabled: "true" restuser: "admin" restuserkey: "password"
- endpoint:glusterfs-cluster 是 endpoint/service 名字,包括 GlusterFS 信任的IP地址池。这个参数是必须的。
- resturl:Gluster REST 服务 url,它按需部署gluster volumes。格式应为 http://IPaddress:Port 。当使用GlusterFS dynamic provisioner时,这个参数是必须的。
- restauthenabled : 布尔值,用于指定REST服务器上的Gluster REST 服务认证是否启用。如该值为”true”,你必须为‘restuser’ and ‘restuserkey’ 参数赋值。
- restuser:Gluster REST 服务用户, 用户可以在Gluster 信任池中创建volume。
- restuserkey:Gluster REST 服务用户的密码, 用于REST 服务器认证。
OpenStack Cinder:
kind: StorageClass apiVersion: storage.k8s.io/v1beta1 metadata: name: gold provisioner: kubernetes.io/cinder parameters: type: fast availability: nova
- type:Cinder中创建的VolumeType ,缺省为空。
- availability:可用的Zone,缺省为空。
可移植配置
如果你在为一个大规模集群编写配置模板或样例,并且需要持久存储,我们建议你使用以下模式:
- 在配置组合中一定包涵PersistentVolumeClaim对象(以及Deployments, ConfigMaps等)
- 一定不要在配置中包涵PersistentVolume对象,因为使用配置的用户也许没有权限创建PersistentVolumes.
- 当创建模板时,让用户可选择是否提供storage class名字
- 如果用户提供了storage class名字,并且集群版本是1.4或以上,把这个值放到PVC volume.beta.kubernetes.io/storage-class的注释中. 如果集群的StorageClasses已被管理员启用,这会使PVC寻找匹配合适的StorageClass。
- 如果用户未提供StorageClass名字,或集群版本是1.3,那就在PVC中加入volume.alpha.kubernetes.io/storage-class: default注释。
- 这会使PV对一些集群中有默认特性的用户进行自动部署,尽管名字显示alpha,这个注释的后台是beta级别的支持。
- 不要给volume.beta.kubernetes.io/storage-class: 赋予任何值,包括空值。因为它会阻止DefaultStorageClass 的准入控制器执行(如果已经启用了的话)。
- 一定要使用监视那些经过一段时间后未被绑定的PVC,并反馈给用户。因为这或许表明该集群没有动态存储支持(这种情况下用户应该创建一个匹配的PV),或者该集群没有存储系统 (这种情况下用户不能够部署配置来请求PVC)。
- 未来我们期待更多的集群启用DefaultStorageClass,并且有各种存储可用。然而,也许没有什么storage class的名字可适用于所有集群,所以不要设置默认名字。到某个阶段后,alpha注释将失去意义,但PVC上未赋值的storageClass字段将会达到预期的效果。
评论前必须登录!
注册