持久卷 Persistent Volume(PV)
描述的是持久化存储数据卷。主要定义一个持久化存储在宿主机上的目录。 持久卷不属于任何命名空间,它跟节点一样是集群层面的资源。 通常情况下,会先在kubernetes集群里创建PV对象,比如定义一个NFS类型的PV:
1 2 3 4 5 6 7 8 9 10 11 12 13 apiVersion: v1 kind: PersistentVolume metadata: name: nginx-pv-nfs spec: capacity: storage: 1Gi accessModes: - ReadWriteMany storageClassName: manual nfs: server: 172.21.0.5 path: "/pk1yjy13/"
注意
RWO
即ReadWriteOnce
,允许单个节点挂载读写。
ROX
即ReadOnlyMany
,允许多个节点挂载只读。
RWX
即ReadWriteMany
,允许多个节点挂载读写。
PVC描述的是Pod期望的持久化存储属性。·比如,卷存储的大小、可读写权限等。
可以声明一个1GiB大小的PVC,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 apiVersion: v1 kind: PersistentVolumeClaim metadata: name: nginx-pvc-nfs spec: accessModes: - ReadWriteMany resources: requests: storage: 1Gi storageClassName: manual volumeName: nginx-pv-nfs
当创建好PVC,kubernetes就会找到合适的pv将与pvc绑定,要想PVC和PV绑定,需要满足以下两个条件:
PV和PVC的spec字段。PV的大小(storage)必须满足PVC所声明的要求。 PV和PVC的storageClassName字段必须一样。
通过kubectl get pvc可以列举pvc的状态
1 2 3 [root@VM-20-9-centos ~]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE nginx-pvc-nfs Bound nginx-pv-nfs 1Gi RWX manual 5d22h
通过列举的pv中可以看到,持久卷现在已经与声明绑定在一起了,显示绑定在default/nginx-pvc-nfs这个声明上,default表示声明所在的命名空间
1 2 3 [root@VM-20-9-centos ~]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE nginx-pv-nfs 1Gi RWX Retain Bound default/nginx-pvc-nfs manual 5d23h
在pod中使用持久卷声明 在成功将PV和PVC进行绑定之后,Pod就能够像使用常规类型的Volume一样,在Pod的spec中声明使用这个PVC了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ...... spec: containers: - name: hexo-blog image: nginx:1.20.1 imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80 - name: https containerPort: 443 volumeMounts: - name: nginx-volume mountPath: /usr/share/nginx/html volumes: - name: nginx-volume persistentVolumeClaim: claimName: nginx-pvc ......
在spec.volumes中声明要使用的PVC名字。Pod创建之后,kubelet就会把该PVC对应的PV,挂载在这个Pod容器内的目录上。
在未创建PV时,pod启动会报错,因为pvc无法找到合适的pv进行绑定,所以pod中的容器想要使用的卷也不存在。
保护使用中的存储 这一功能特性确保仍被 Pod 使用的 PersistentVolumeClaim(PVC) 对象及其所绑定的 PersistentVolume(PV)对象在系统中不会被删除并导致数据丢失。
如果用户删除被某Pod使用的PVC对象,该PVC声明不会被立即移除。PVC 对象会在不被任何Pod使用时移除。 如果删除已绑定到某 PVC的PV卷,该PV卷也不会被立即移除。PV对象会在不被任何PVC绑定时被移除。
可以看到当PV和PVC的状态为 Terminating
且其 Finalizers
列表中包含 kubernetes.io/pvc-protection
时,PV和PVC对象是处于被保护状态的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 [root@VM-20-9-centos nginx]# kubectl describe pv prometheus-pv Name: prometheus-pv Labels: <none> Annotations: pv.kubernetes.io/bound-by-controller: yes Finalizers: [kubernetes.io/pv-protection] StorageClass: manual Status: Terminating (lasts 26d) Claim: monitor/prometheus-pvc Reclaim Policy: Retain Access Modes: RWO VolumeMode: Filesystem Capacity: 5Gi Node Affinity: <none> Message: Source: Type: HostPath (bare host directory volume) Path: /home/prometheus HostPathType: Events: <none>
回收持久卷 持久卷可以被 Retained
(保留)、Recycled
(回收)或 Deleted
(删除)
保留 通过设置策略 Retain
可以手动回收资源。当持久卷声明对象被删除时,持久卷仍然存在,对应的持久卷状态为released
。
让持久卷与持久卷声明的绑定释放后,持久卷仍然能够保留,如果想手动回收持久卷,需要删除并重新创建持久卷资源。
删除 Delete
回收策略的卷插件,会将持久卷对象随着持久卷声明的删除而从 Kubernetes 中移除。
回收 recyle可以删除持久卷的内容并使持久卷可以再次被声明使用,通过这种方式,持久卷可以被不同的持久卷声明和pod反复使用
警告 回收策略 Recycle
已被废弃。取而代之的建议方案是使用动态制备。
PV的动态卷配置 正如上面所说,当一个pod需要一个持久卷时,如未创建合适的pv与pvc进行绑定,pod就无法正常启动,kubernetes提供了一种可以自动创建PV的机制:Dynamic provisioning。而前面人工管理PV的方式叫作Static provisioning。
Dynamic provisioning的核心在于一个StorageClass的API对象。StorageClass的作用就是创建PV的模板。
StorageClass对象会定义如下两个内容:
PV的属性,如存储类型、卷的大小等 创建PV需要用到的插件,如ceph、nfs等
通过以上信息,kubernetes就能根据提交的pvc定义的StorageClass,然后通过StorageClass来创建一个合适的pv模板
通过StorageClass资源定义可用存储类型 创建ServiceAccount 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 apiVersion: v1 kind: ServiceAccount metadata: name: nfs-client-provisioner namespace: default --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: nfs-client-provisioner-runner rules: - apiGroups: ["" ] resources: ["persistentvolumes" ] verbs: ["get" , "list" , "watch" , "create" , "delete" ] - apiGroups: ["" ] resources: ["persistentvolumeclaims" ] verbs: ["get" , "list" , "watch" , "update" ] - apiGroups: ["storage.k8s.io" ] resources: ["storageclasses" ] verbs: ["get" , "list" , "watch" ] - apiGroups: ["" ] resources: ["events" ] verbs: ["create" , "update" , "patch" ] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: run-nfs-client-provisioner subjects: - kind: ServiceAccount name: nfs-client-provisioner namespace: default roleRef: kind: ClusterRole name: nfs-client-provisioner-runner apiGroup: rbac.authorization.k8s.io --- kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: leader-locking-nfs-client-provisioner namespace: default rules: - apiGroups: ["" ] resources: ["endpoints" ] verbs: ["get" , "list" , "watch" , "create" , "update" , "patch" ] --- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: leader-locking-nfs-client-provisioner namespace: default subjects: - kind: ServiceAccount name: nfs-client-provisioner namespace: default roleRef: kind: Role name: leader-locking-nfs-client-provisioner apiGroup: rbac.authorization.k8s.io
安装NFS存储插件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 apiVersion: apps/v1 kind: Deployment metadata: name: nfs-client-provisioner labels: app: nfs-client-provisioner namespace: default spec: replicas: 1 strategy: type : Recreate selector: matchLabels: app: nfs-client-provisioner template: metadata: labels: app: nfs-client-provisioner spec: serviceAccountName: nfs-client-provisioner nodeName: vm-20-9-centos tolerations: - key: node-role.kubernetes.io/master operator: Equal value: "true" containers: - name: nfs-client-provisioner image: registry.cn-beijing.aliyuncs.com/mydlq/nfs-subdir-external-provisioner:v4.0.0 imagePullPolicy: IfNotPresent volumeMounts: - name: nfs-client-root mountPath: /persistentvolumes env : - name: PROVISIONER_NAME value: k8s/nfs-subdir-external-provisioner - name: NFS_SERVER value: 172.21.0.5 - name: NFS_PATH value: /pk1yjy13/ volumes: - name: nfs-client-root nfs: server: 172.21.0.5 path: /pk1yjy13/
创建SotageClass 创建一个 StoageClass,声明 NFS 动态卷提供者名称为 nfs-storage-1。
1 2 3 4 5 6 7 8 9 10 11 apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: nfs-storage-1 provisioner: k8s/nfs-subdir-external-provisioner parameters: archiveOnDelete: "false" mountOptions: - nfsvers=3
当持久卷声明中请求此StorageClass时,StorageClass使用声明的插件来来提供持久卷
创建请求特定存储类的PVC定义 kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: nfs-storage-pvc-1
spec:
storageClassName: nfs-storage-1 #请求上面创建的StoageClass
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Mi
除了指定卷的大小和访问模式,还指定了要使用的存储类别。当PVC创建时,持久卷会由StorageClass(nfs-storage-1)资源中引用的provisioner创建
注意
RWO即ReadWriteOnce,允许单个节点挂载读写。
ROX即ReadOnlyMany,允许多个节点挂载只读。
RWX即ReadWriteMany,允许多个节点挂载读写。
通过命令查看pvc的状态,可以看到是bound状态
1 2 3 4 5 6 7 [root@VM-20-9-centos storageclass]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE nfs-storage-pvc-1 Bound pvc-450c1793-4831-48c5-a804-ae26eae3f63d 10Mi RWO nfs-storage-1 3d7h [root@VM-20-9-centos storageclass]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pvc-450c1793-4831-48c5-a804-ae26eae3f63d 10Mi RWO Delete Bound default/nfs-storage-pvc-1 nfs-storage-1 3d6h
可以看到动态配置自动创建的持久卷容量和访问模式是之前PVC中所要求的。回收策略是Delete,意味着PVC被删除时,持久卷也会被删除