https://blog.csdn.net/liyingke112/article/details/76851145
https://blog.csdn.net/tiger435/article/details/54380542
https://www.cnblogs.com/styshoo/p/6731425.html
中文 官网:https://www.kubernetes.org.cn/pvpvcstorageclass
https://kubernetes.io/docs/concepts/storage/persistent-volumes/#storageclasses
实例:https://blog.csdn.net/idea77/article/details/72842723
https://blog.csdn.net/iiiiher/article/details/77865530
https://kubernetes.io/blog/2016/10/dynamic-provisioning-and-storage-in-kubernetes/
本文基于kubernetes 1.5.2版本编写
存储管理跟计算管理是两个不同的问题。理解每个存储系统是一件复杂的事情,特别是对于普通用户来说,有时并不需要关心各种存储实现,只希望能够安全可靠地存储数据。
为了简化对存储调度,K8S对存储的供应和使用做了抽象,以API形式提供给管理员和用户使用。要完成这一任务,引入了两个新的API资源:Persistent Volume(持久卷,以下简称PV)和Persistent Volume Claim(持久卷申请,以下简称PVC)。
PV是集群中的一块网络存储,跟Node一样,也是集群的资源。PV跟Volume(卷)类似,不过会有独立于Pod的生命周期。由系统管理员配置创建的一个数据卷(即PV类型),它代表了某一类存储插件实现。
PVC是用户的一个请求,跟Pod类似。Pod消费Node的资源,PVC消费PV的资源。Pod 能够申请特定的资源(CPU和内存);PVC能够申请特定的尺寸和访问模式(例如可以加载一个读写,以及多个只读实例),而无须感知后端的存储实现。.
Volume
Volume是Pod的挂载接口,生命周期同Pod,可以在Pod内的各个Container之间进行共享,主要用于存储Pod生命周期内的临时数据,当然,也可以挂在在Host主机或者其他后端存储介质上实现永久存储,根据选用的Volume Type可以实现不同的存储需求,下边是Volume支持的类型:
PV类型使用插件的形式来实现。K8S现在支持以下插件:
GCEPersistentDisk
AWSElasticBlockStore
AzureFile
AzureDisk
FC (FibreChannel)
Flocker
NFS
iSCSI
RBD (CephBlock Device)
CephFS
Cinder(OpenStack block storage)
Glusterfs
VsphereVolume
QuobyteVolumes
HostPath
VMware Photon
PortworxVolumes
ScaleIOVolumes
此处不作一一介绍,可以参考文档:Volume Docs。
PV是集群的资源。PVC是对这一资源的请求,也是对资源的所有权的检验。PV和PVC 之间的互动遵循如下的生命周期。
有两种PV提供的方式:静态和动态。
集群管理员创建多个PV,它们携带着真实存储的详细信息,这些存储对于集群用户是可用的。它们存在于Kubernetes API中,并可用于存储使用。集群管理员会创建一系列的PV。这些PV包含了为集群用户提供的真实存储资源。可利用 K8S API来消费。
当管理员创建的静态PV都不匹配用户的PVC时,集群可能会尝试专门地供给volume给PVC。这种供给基于StorageClass
:PVC必须请求这样一个等级,而管理员必须已经创建和配置过这样一个等级,以备发生这种动态供给的情况。请求等级配置为“”的PVC,有效地禁用了它自身的动态供给功能。
绑定
用户创建一个包含了容量和访问模式的PVC。Master会监听PVC的产生,并尝试根据请求内容查找匹配的PV,并把PV和PVC进行绑定。用户能够获取满足需要的资源,并且在使用过程中可能超出请求数量。
如果找不到合适的卷,这一申请就会持续处于非绑定状态,一直到出现合适的PV。例如一个集群准备了很多的50G大小的持久卷,(虽然总量足够)也是无法响应100G的申请的,除非把100G的PV加入集群。
Pod把PVC作为卷来使用。集群会通过PVC查找绑定的PV,并Mount给Pod。对于支持多种访问方式的卷,用户在使用 PVC 作为卷时,可以指定需要的访问方式。
一旦用户拥有了一个已经绑定的PVC,被绑定的PV就归该用户所有了。用户的Pods能够通过在Pod的卷中包含的PVC来访问他们占有的PV。
Pod使用PVC就像使用volume一样。集群检查PVC,查找绑定的PV,并映射PV给Pod。对于支持多种访问模式的PV,用户可以指定想用的模式。
一旦用户拥有了一个PVC,并且PVC被绑定,那么只要用户还需要,PV就一直属于这个用户。用户调度Pod,通过在Pod的volume
块中包含PVC来访问PV。
当用户完成对卷的使用时,就可以利用API删除PVC对象了,而且还可以重新申请。删除PVC后,对应的卷被视为“被释放”,但这时还不能给其他的PVC使用。之前的PVC数据还保存在卷中,要根据策略来进行后续处理。
PV的回收策略向集群阐述了在PVC释放卷时,应如何进行后续工作。目前可以采用三种策略:保留,回收或者删除。保留策略允许重新申请这一资源。在PVC能够支持的情况下,删除策略会同时删除卷以及AWS EBS/GCE PD或者Cinder卷中的存储内容。如果插件能够支持,回收策略会执行基础的擦除操作(rm -rf /thevolume/*),这一卷就能被重新申请了。
如果PV卷支持再利用,再利用会在PV卷上执行一个基础的擦除操作(rm -rf /thevolume/*),使得它可以再次被其他PVC声明利用。
管理员可以通过Kubernetes controller manager的命令行工具(点击查看),来配置自定义的再利用Pod模板。自定义的再利用Pod模板必须包含PV卷的详细内容,如下示例:
apiVersion: v1
kind: Pod
metadata:
name: pv-recycler-
namespace: default
spec:
restartPolicy: Never
volumes:
- name: vol
hostPath:
path: /any/path/it/will/be/replaced
containers:
- name: pv-recycler
image: "gcr.io/google_containers/busybox"
command: ["/bin/sh", "-c", "test -e /scrub && rm -rf /scrub/..?* /scrub/.[!.]* /scrub/* && test -z \"$(ls -A /scrub)\" || exit 1"]
volumeMounts:
- name: vol
mountPath: /scrub
如上,在volumes
部分的指定路径,应该被替换为PV卷需要再利用的路径。
PersistentVolume(PV)
假如有一个独立的存储后端,底层实现可以是NFS、GlusterFS、Cinder、HostPath等等,可以使用PV从中划拨一部分资源用于kubernetes的存储需求,其生命周期不依赖于Pod,是一个独立存在的虚拟存储空间,但是不能直接被Pod的Volume挂载,此时需要用到PVC。
PV支持的后端存储插件:
PersistentVolumeClaim(PVC)
Pod使用PV资源是通过PVC来实现的,PVC可以理解为资源使用请求,一个Pod需要先明确使用的资源大小、访问方式,创建PVC申请提交到kubernetes中的PersistentVolume Controller,由其调度合适的PV来与PVC绑定,然后Pod中的Volume就可以通过PVC来使用PV的资源。
StorageClasse
用于定义动态PV资源调度,相比起静态PV资源来说,动态PV不需要预先创建PV,而是通过PersistentVolume Controller动态调度,根据PVC的资源请求,寻找StorageClasse定义的符合要求的底层存储来分配资源。提供了一种方式,使得管理员能够描述他提供的存储的等级。集群管理员可以将不同的等级映射到不同的服务等级、不同的后端策略。
请查看https://kubernetes.io/docs/tasks/configure-pod-container/configure-persistent-volume-storage/
PersistentVolume
,这里使用hostPath
作为存储底层。每个PV都包含一个spec和状态,即说明书和PV卷的状态。
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv0003
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: slow
nfs:
path: /tmp
server: 172.17.0.2
一般来说,PV会指定存储容量。这里需要使用PV的capcity属性。
用于定义PV的存储容量,当前只支持定义大小,未来会实现其他能力如:IOPS、吞吐量
目前存储大小是唯一一个能够被申请的指标。
用于定义资源的访问方式,受限于存储底层的支持,访问方式包括以下几种:
下边途中列举了k8s支持的存储插件的访问方式:
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的访问模式也会被设置成为该卷所支持的特定模式。例如NFS能够支持多个读写客户端,但某个NFS PV可能会在服务器上以只读方式使用。每个PV都有自己的一系列的访问模式,这些访问模式取决于PV的能力。
访问模式的可选范围如下:
ReadWriteOnce:该卷能够以读写模式被加载到一个节点上。
ReadOnlyMany:该卷能够以只读模式加载到多个节点上。
ReadWriteMany:该卷能够以读写模式被多个节点同时加载。
在 CLI 下,访问模式缩写为:
RWO:ReadWriteOnce
ROX:ReadOnlyMany
RWX:ReadWriteMany
重要!一个卷不论支持多少种访问模式,同时只能以一种访问模式加载。例如一个 GCEPersistentDisk既能支持ReadWriteOnce,也能支持ReadOnlyMany。
用于定义资源的回收方式,也首先与存储底层的支持,现有的回收策略:
目前只有NFS和HostPath支持Recycle策略,AWS EBS、GCE PD、Azure Disk、Cinder支持Delete策略。
注意:Recycle策略会通过运行一个busybox容器来执行数据删除命令,默认定义的busybox镜像是:
gcr.io/google_containers/busybox:latest
,并且imagePullPolicy: Always
,如果需要调整配置,需要增加kube-controller-manager 启动参数:--pv-recycler-pod-template-filepath-hostpath=/etc/kubernetes/manifests/recycler.yml
apiVersion: v1
kind: Pod
metadata:
name: pv-recycler-
namespace: default
spec:
restartPolicy: Never
volumes:
- name: vol
hostPath:
path: [Path of Persistent Volume hosted]
containers:
- name: pv-recycler
image: "gcr.io/google_containers/busybox"
imagePullPolicy: IfNotPresent
command: ["/bin/sh", "-c", "test -e /scrub && rm -rf /scrub/..?* /scrub/.[!.]* /scrub/* && test -z \"$(ls -A /scrub)\" || exit 1"]
volumeMounts:
- name: vol
mountPath: /scrub
一个PV可以有一种class,通过设置storageClassName
属性来选择指定的StorageClass
。有指定class的PV只能绑定给请求该class的PVC。没有设置storageClassName
属性的PV只能绑定给未请求class的PVC。
过去,使用volume.beta.kubernetes.io/storage-class
注解,而不是storageClassName
属性。该注解现在依然可以工作,但在Kubernetes的未来版本中已经被完全弃用了。
一个卷会处于如下阶段之一:
Available:可用资源,尚未被绑定到PVC上
Bound:该卷已经被绑定
Released:PVC已经被删除,但该资源尚未被集群回收
Failed:该卷的自动回收过程失败。
CLI 会显示绑定到该 PV 的 PVC。
当PV被映射到一个node上时,Kubernetes管理员可以指定额外的映射选项。可以通过使用标注volume.beta.kubernetes.io/mount-options
来指定PV的映射选项。
比如:
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
映射选项是当映射PV到磁盘时,一个可以被递增地添加和使用的字符串。
注意,并非所有的PV类型都支持映射选项。在Kubernetes v1.6中,以下的PV类型支持映射选项。
● GCEPersistentDisk
● AWSElasticBlockStore
● AzureFile
● AzureDisk
● NFS
● iSCSI
● RBD (Ceph Block Device)
● CephFS
● Cinder (OpenStack block storage)
● Glusterfs
● VsphereVolume
● Quobyte Volumes
● VMware Photon
spec
和
status
,即该PVC的规则说明和状态。
定义PersistentVolumeClaim
。
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: pvc-lykops-sfs-0
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
selector:
matchLabels:
release: pv-lykops-sfs-0
每个PVC都包含一个spec
和status
,即该PVC的规则说明和状态。
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]}
与PersistentVolume的访问方式一致,PersistentVolume Controller调度访问方式一致PV资源与PVC绑定。
resources
用于定义申请使用的存储资源大小,适用于kubernetes的resource模型,具体信息可以查看Resource Model docs。
selector
定义PVC申请过滤PV卷集,搭配label定义使用,同kubernetes中其他的selector概念一致,用法上稍有不同,增加了匹配选项:
此外还有volume.beta.kubernetes.io/storage-class
定义,具有相同定义的PV和PVC才会绑定,具体用法可以查看PersistentVolume docs。
PVC可以使用属性storageClassName
来指定StorageClass
的名称,从而请求指定的等级。只有满足请求等级的PV,即那些包含了和PVC相同storageClassName
的PV,才能与PVC绑定。
PVC并非必须要请求一个等级。设置storageClassName
为“”的PVC总是被理解为请求一个无等级的PV,因此它只能被绑定到无等级的PV(未设置对应的标注,或者设置为“”)。未设置storageClassName
的PVC不太相同,DefaultStorageClass
的权限插件打开与否,集群也会区别处理PVC。
• 如果权限插件被打开,管理员可能会指定一个默认的StorageClass
。所有没有指定StorageClassName
的PVC只能被绑定到默认等级的PV。要指定默认的StorageClass
,需要在StorageClass
对象中将标注storageclass.kubernetes.io/is-default-class
设置为“true”。如果管理员没有指定这个默认值,集群对PVC创建请求的回应就和权限插件被关闭时一样。如果指定了多个默认等级,那么权限插件禁止PVC创建请求。
• 如果权限插件被关闭,那么久没有默认StorageClass
的概念。所有没有设置StorageClassName
的PVC都只能绑定到没有等级的PV。因此,没有设置StorageClassName
的PVC就如同设置StorageClassName
为“”的PVC一样被对待。
根据安装方法的不同,默认的StorageClass
可能会在安装过程中被插件管理默认的部署在Kubernetes集群中。
当PVC指定selector
来请求StorageClass
时,所有请求都是与操作的。只有满足了指定等级和标签的PV才可能绑定给PVC。当前,一个非空selector
的PVC不能使用PV动态供给。
过去,使用volume.beta.kubernetes.io/storage-class注解,而不是storageClassName属性。该注解现在依然可以工作,但在Kubernetes的未来版本中已经被完全弃用了。
Pod通过使用PVC(使用方式和volume一样)来访问存储。PVC必须和使用它的pod在同一个命名空间,集群发现pod命名空间的PVC,根据PVC得到其后端的PV,然后PV被映射到host中,再提供给pod。
PV和PVC创建并绑定之后,类似这样:
NAME CAPACITY ACCESSMODES RECLAIMPOLICY STATUS CLAIM REASON AGE
pv/pv001 5Gi RWO Recycle Bound default/myclaim-1 11m
NAME STATUS VOLUME CAPACITY ACCESSMODES AGE
pvc/myclaim-1 Bound pv001 5Gi RWO 3s
PersistentVolume有四种状态:
挂载创建好的PVC:myclaim-1到Pod上:
kind: Pod
apiVersion: v1
metadata:
name: mypod
spec:
containers:
- name: myfrontend
image: hub.c.163.com/library/nginx:latest
volumeMounts:
- mountPath: "/var/www/html"
name: mypd
volumes:
- name: mypd
persistentVolumeClaim:
claimName: pvc-lykops-sfs-0
PV绑定是独有的,因为PVC是命名空间对象,映射PVC时只能在同一个命名空间中使用多种模式(ROX
,RWX
)。
如果是NFS:kuberctl exec -it bash ls /var/www/html 就会有挂载的内容
如果是HostPath Volum:挂载成功后,Pod所在的Host上会自动创建/tmp/data
用于存储数据,HostPath Volume便于测试调试,但是只适用于单节点环境,多节点环境中如果Pod漂移或者重建后不在原先节点,则无法访问原来的数据。
(https://blog.csdn.net/Michaelwubo/article/details/80763586)
Pod能够借助PVC来访问存储。PVC必须跟Pod处于同一个命名空间。集群找到Pod命名空间中的PVC,然后利用PVC获取到PV。这个卷就会被加载到主机上,让Pod使用。
每个StorageClass
都包含字段provisioner
和parameters
,在所属的PV需要动态供给时使用这些字段。
StorageClass
对象的命名是非常重要的,它是用户请求指定等级的方式。当创建StorageClass
对象时,管理员设置等级的名称和其他参数,但对象不会在创建后马上就被更新。
管理员可以指定一个默认的StorageClass
,用于绑定到那些未请求指定等级的PVC。详细信息可参考PersistentVolumeClaim章节。
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: standard
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp2
StorageClass
都有存储供应商provisioner,用来决定哪种volume插件提供给PV使用。必须制定该字段。
你不限于指定此处列出的“内部”供应商(其名称前缀为“kubernetes.io”并与Kubernetes一起分发)。你还可以运行和指定外部供应商,它们是遵循Kubernetes定义的规范的独立程序。外部提供者的作者对代码的生命周期,供应商的分发方式,运行状况以及使用的卷插件(包括Flex)等都有充分的自主权。库kubernetes-incubator/external-storage存放了一个库, 用于编写外部存储供应商,而这些提供者实现了大量的规范,并且是各种社区维护的。
StorageClass
有一些参数用于描述归属于该StorageClass
的volume。不同的存储提供商可能需要不同的参数。比如,参数type
对应的值io1
,还有参数iopsPerGB
,都是EBS专用的参数。当参数省略时,就会使用它的默认值。
...
...
...
...
...
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
● monitors
:Ceph的monitor,逗号分隔。该参数是必须的。
● adminId
:Ceph的客户端ID,可在pool中创建镜像。默认的是“admin”。
● adminSecretNamespace
:adminSecret的命名空间,默认值是“default”。
● adminSecretName
:adminId
的Secret Name。改参数是必须的,提供的秘钥必须有类型“kubernetes.io/rbd”。
● pool
:Ceph的RBD pool,默认值是“rbd”。
● userId
:Ceph的客户ID,用于映射RBD镜像的,默认值和adminId
参数相同。
● userSecretName
:Ceph Secret的名称,userId
用该参数来映射RBD镜像。它必须和PVC在相同的命名空间。该参数也是必须的。提供的秘钥必须有类型“kubernetes.io/rbd”。比如,按照下面的方式来创建:
$ kubectl create secret generic ceph-secret --type="kubernetes.io/rbd" --from-literal=key='QVFEQ1pMdFhPUnQrSmhBQUFYaERWNHJsZ3BsMmNjcDR6RFZST0E9PQ==' --namespace=kube-system
...
...
...
...
如果你在写配置模板和示例,用于在需要持久化存储的集群中使用,那么,我们建议你使用以下的一些模式:
● 在你的捆绑配置(如Deployment、ConfigMap胖)中包含PVC对象。
● 在配置中不要包含PersistentVolume对象,因为实例化配置的用户可能没有创建PersistentVolumes的权限
● 当用户提供实例化模板时,给用户提供存储类名称的选项。
▷ 如果用户提供了一个StorageClass
名称,并且Kubernetes版本是1.4及以上,那么将该值设置在PVC的volume.beta.kubernetes.io/storage-class
标注上。这会使得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
,并且能有一些可用的存储形式。然而,可能没有行在所有集群都能运的StorageClass
,所以默认情况下不要只设置一种。在某些时候,alpha标注将不再具有意义,但复位PVC的storageClass
字段将具有所需的效果。
PVC、PV不能使用在deployment、rc、rs等场景下
如上面的例子:
调用PVC的StatefulSet:StatefulSet名称为test-sfs,卷名为pvc
PV:pv-test-sfs-{0,1}
PVC:pvc-test-sfs-{0,1}
规则如下:
PVC和PV的命名规则为:资源类型-StatefulSet名称-副本数序号(从0开始)
除了命名规则外,还需要保证访问accessModes、resources这两个一样
按照以上规则创建后,可以看到PV和PVC能关联起来