Volume 提供了非常好的数据持久化方案,不过在可管理性上还有不足。
例如之前的AWS EBS,要使用Volume,Pod 必须事先知道如下信息:
- 当前Volume 来自 AWS EBS
- EBS Volume 已经提前创建,并且知道确切的volume-id。
Pod通常是由应用的开发人员维护,而Volume则通常是由存储系统的管理员维护。开发人员要获得上面的信息,要么询问管理员,要么自己就是管理员。
这样就带了一个管理上的问题:应用开发人员和系统管理员的职责耦合在一起了。
Kubernetes 给出的解决方案是 PersistentVolume 和 PersistentVolumeClaim。
PV(PersistentVolume)是外部存储系统中的一块存储空间,由管理员创建和维护。与Volume一样,PV 具有持久性,生命周期独立于Pod。
PVC (PersistentVolumeClaim) 是对PV的申请(Claim)。PVC 通常由普通用户创建和维护。需要为Pod分配存储资源时,用户可以创建一个PVC,指明存储资源的容量大小和访问模式(比如只读)等信息,Kubernetes 会查找并提供满足条件的PV。
有了PVC,用户只需要告诉Kubernetes 需要什么样的存储资源,而不需关心真正的空间从哪里分配、如何访问等底层细节信息。这些Storage Provider的底层信息交给管理员来处理,只有管理员才应该关心创建PV 的细节信息。
Kubernetes 支持多种类型的PV,比如AWS EBS、Ceph、NFS 等,完整列表参考:https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes
同样,我们通过NFS的示例来了解 PV 的使用方法。
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv1
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: nfs
nfs:
path: /tmp
server: 10.138.0.34
- capacity 指定PV 的容量为1GB。
- accessModes 指定访问模式为ReadWriteOnce
- persistentVolumeReclaimPolicy 指定PV的回收策略为 Recycle
- storageClassName 指定PV 的class为nfs。相当于为PV 设置了一个分类,PVC 可以指定class 申请相应 class 的 PV。
- path 指定 PV在NFS 服务器上对应的目录。
访问模式包括:
- ReadWriteOnce——该卷可以被单个节点以读/写模式挂载
- ReadOnlyMany——该卷可以被多个节点以只读模式挂载
- ReadWriteMany——该卷可以被多个节点以读/写模式挂载
在命令行中,访问模式缩写为:
- RWO - ReadWriteOnce
- ROX - ReadOnlyMany
- RWX - ReadWriteMany 一个卷一次只能使用一种访问模式挂载,即使它支持很多访问模式。
回收策略包括:
- Retain(保留)—— 手动回收
- Recycle(回收)—— 清除PV中的数据(相当于 rm -rf /thevolume/*)
- Delete(删除)—— 删除Storage Provider上的对应存储资源(例如 AWS EBS、GCE PD、Azure Disk 和 OpenStack Cinder 卷)
当前,只有 NFS 和 HostPath 支持Recycle策略。AWS EBS、GCE PD、Azure Disk 和 Cinder 卷支持Delete策略。
PV可以指定一个StorageClass来动态绑定PV和PVC,其中通过 storageClassName 属性来指定具体的StorageClass,如果没有指定该属性的PV,它只能绑定到不需要特定类的 PVC。
PersistentVolumeClaim(PVC)是用户存储的请求,PVC消耗PV的资源,可以请求特定的大小和访问模式,需要指定归属于某个Namespace,在同一个Namespace的Pod才可以指定对应的PVC。
当需要不同性质的PV来满足存储需求时,可以使用StorageClass来实现。
创建PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mypvc1
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: nfs
PVC只需要指定PV的容量、访问模式和class即可。
只有与 PVC 具有相同 storageClassName 的 PV 才能绑定到 PVC。
PVC可以不指定storageClassName,或者将该值设置为空,如果打开了准入控制插件,并且指定一个默认的 StorageClass,则PVC会使用默认的StorageClass,否则就绑定到没有StorageClass的 PV上。
将PVC作为Pod的Volume,PVC与Pod需要在同一个命名空间下,Pod的声明如下:
kind: Pod
apiVersion: v1
metadata:
name: mypod1
spec:
containers:
- name: mypod1
image: busybox
args:
- /bin/sh
- -c
- sleep 30000
volumeMounts:
- mountPath: "/mydata"
name: mydata
volumes:
- name: mydata
persistentVolumeClaim: # 使用PVC
claimName: mypvc1
当不需要使用PV 时,可用删除PVC回收 PV
$ kubectl delete pvc mypvc1
$ kubectl get pod -o wide
$ kubectl get pv
当PVC mypvc1 被删除后,会发现Kubernetes 启动了一个新的 Pod recycler-for-pv1,这个Pod 的作用就是清除PV pv1 的数据。此时 pv1 的状态为Released,表示已经解除了与 mypvc1 的绑定,正在清除数据,不过此时还不可用。
当数据清除完毕,pv1 的状态重新变为Available,此时可以被新的PVC申请。
因为PV的回收策略设置为Recycle,所以数据会被清除。如果我们希望保留数据,可以将策略设置为 Retain。
如果需要其能被其他PVC 申请,可以删除并重新创建pv1,删除操作只是删除了PV 对象,存储空间中的数据并不会被删除。
PV 还支持Delete 的回收策略,会删除PV 在Storage Provider 上对应的存储空间。NFS 的 PV 还不支持Delete,支持Delete 的 Provider有AWS EBS、GCE PD、Azure Disk 和 OpenStack Cinder Volume 等
前面讲述的提前创建PV,然后通过PVC 申请PV 并在 Pod 中使用,这种方式叫做静态供给(Static Provision)。
与之对应的是动态供给(Dynamical Provision),即如果没有满足PVC条件的PV,会动态创建PV。相比静态供给,动态供给有明显的优势:不需要提前创建PV,减少了管理员的工作量,效率高。
动态供给是通过 StorageClass 实现的,StorageClass 定义了如何创建PV。详见StorageClass
需要先提前创建StorageClass对象,StorageClass中定义了使用哪个provisioner,并且在provisioner被调用时传入哪些参数,详见StorageClass。
-
磁盘类存储
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: slow provisioner: kubernetes.io/gce-pd parameters: type: pd-standard
-
SSD类存储
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: fast provisioner: kubernetes.io/gce-pd parameters: type: pd-ssd
创建一个PVC对象,并且在其中storageClassName字段指明需要用到的StorageClass的名称,例如:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: claim1
spec:
accessModes:
- ReadWriteOnce
storageClassName: fast
resources:
requests:
storage: 30Gi
当使用到PVC的时候会自动创建对应的外部存储,当PVC被删除的时候,会自动销毁(或备份)外部存储。
当没有对应的StorageClass配置时,可以设定默认的StorageClass,需要执行以下操作:
- 在API Server开启 DefaultStorageClass admission controller 。
- 设置默认的StorageClass对象。
可以通过添加storageclass.kubernetes.io/is-default-class
注解的方式设置某个StorageClass
为默认的StorageClass
。当用户创建了一个PersistentVolumeClaim
,但没有指定storageClassName
的时候,会自动将该PVC的storageClassName
指向默认的StorageClass
。
- Provisioner - Storage Classes
- CloudMan. 每天 5 分钟玩转 Kubernetes[M]. 清华大学出版社, 2018.