持久卷PV和PVC概念

未命名绘图.svg
假如没有PVC,你需要自己判断PV大小是否可用。非常耗时

PersistentVolume(PV)是由管理员设置的存储,它是群集的一部分。就像节点是集群中的资源一样, PV也是集群中的资源。PV 是Volume之类的卷插件,但具有独立于使用PV的Pod的生命周期。此API对象包含存储实现的细节,即NFS、iSCSI或特定于云供应商的存储系统

PersistentVolumeClaim(PVC)是用户存储的请求。它与Pod相似。Pod 消耗节点资源,PVC 消耗PV资源。Pod可以请求特定级别的资源(CPU和内存)。声明可以请求特定的大小和访问模式(例如,可以以读/写次或只读多次模式挂载),对于真正使用存储的用户不需要关心底层的存储实现细节,只需要直接使用 PVC 即可。
持久卷PV和PVC - 图2

PV分类 静态PV: 集群管理员创建一些PV。它们带有可供群集用户使用的实际存储的细节。它们存在于Kubernetes API中,可用于消费

动态PV:(可以跟云存储上申请存储,以后的趋势,暂时并不友好,需要收费且麻烦,不太成熟。了解即可

  • 当管理员创建的静态PV都不匹配用户的PersistentVolumeClaim 时,集群可能会尝试动态地为PVC创建卷。此配置基于StorageClasses : PVC 必须请求[存储类],并且管理员必须创建并配置该类才能进行动态创建。声明该类为“ “可以有效地禁用其动态配置
  • 要启用基于存储级别的动态存储配置,集群管理员需要启用API server上的DefaultstorageClass[准入控制器]。例如,通过确保DefaultStorageClass位于API server组件的–admission-control标志,使用逗号分隔的有序值列表中,可以完成此操作

Binding绑定

master中的控制环路监视新的PVC,寻找匹配的PV (如果可能) ,并将它们绑定在一 起。如果为新的PVC动态调配PV,则该环路将始终将该PV绑定到PVC。否则,用户总会得到他们所请求的存储,但是容量可能超出要求的数量。一旦PV和PVC绑定后,PersistentVolumeClaim绑定是排他性的, 不管它们是如何绑定的。PVC跟PV绑定是一对一的

如果匹配的卷不存在,PVC将保持无限期。 随着匹配卷变得可用,PVC将被绑定。 例如,提供许多50Gi PV的集群将不匹配要求100Gi的PVC。 当集群中添加100Gi PV时,可以绑定PVC。

持久化卷声明的保护

PVC保护的目的是确保由pod正在使用的PVC不会从系统中移除,因为如果被移除的话可能会导致数据丢失

当启用PVC保护alpha功能时,如果用户删除了一个pod正在使用的PVC,则该PVC不会被立即删除。PVC的删除将被推迟,直到PVC不再被任何pod使用

PV访问模式

PersistentVolume可以以资源提供者支持的任何方式挂载到主机上。例如,NFS 可以支持多个读/写客户端,但特定的 NFS PV 可能 以只读方式导出到服务器上。每个 PV 都有一套自己的用来描述特定功能的访问模式。

  • ReadWriteOnce——该卷可以被单个节点以读/写模式挂载
  • ReadOnlyMany——该卷可以被多个节点以只读模式挂载
  • ReadWriteMany——该卷可以被多个节点以读/写模式挂载

在命令行中,访问模式缩写为:

  • RWO - ReadWriteOnce
  • ROX - ReadOnlyMany
  • RWX - ReadWriteMany

但不是所有的类型的底层存储都支持以上三种,每种底层存储类型支持的都不一样。各种底层存储具体支持的访问模式如下

Volume Plugin ReadWriteOnce ReadOnlyMany ReadWriteMany
AWSElasticBlockStore × ×
AzureFile
AzureDisk × ×
CephFS
Cinder × ×
FC ×
FlexVolume ×
Flocker × ×
GCEPersistentDisk ×
Glusterfs
HostPath × ×
iSCSI ×
PhotonPersistentDisk × ×
Quobyte
NFS
RBD ×
VsphereVolume × ×
PortworxVolume ×
ScaleIO ×

PV的回收策略(spec.persistentVolumeReclaimPolicy)

回收策略的三种策略

  • Retain(保留): pv被删除后会保留内存,手动回收
  • Recycle(回收): 删除卷下的所有内容(rm-rf /thevolume/*)
  • Delete(删除): 关联的存储资产(例如AWS EBS、GCE PD、Azure Disk 和OpenStack Cinder卷)将被删除。即直接把卷给删除了

回收策略注意事项

持久卷PV和PVC - 图3

PV的状态

PV可以处于以下的某种状态:

  • Available(可用): 块空闲资源还没有被任何声明绑定
  • Bound(已绑定): 卷已经被声明绑定, 注意:但是不一定不能继续被绑定,看accessModes而定
  • Released(已释放): 声明被删除,但是资源还未被集群重新声明
  • Failed(失败): 该卷的自动回收失败

命令行会显示绑定到PV的PVC的名称

hostPath实例演示

创建PV

pv-volume.yaml

  1. apiVersion: v1
  2. kind: PersistentVolume
  3. metadata:
  4. name: task-pv-volume
  5. labels:
  6. type: local
  7. spec:
  8. storageClassName: manual
  9. capacity:
  10. storage: 10Gi
  11. accessModes:
  12. - ReadWriteOnce
  13. hostPath:
  14. path: "/data"

创建好了显示如下:

[root@k8s-master01 pv-pvc]# kubectl apply -f pv-volume.yaml
persistentvolume/task-pv-volume created
[root@k8s-master01 pv-pvc]# kubectl get pv
NAME             CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM               STORAGECLASS   REASON   AGE                     101m
task-pv-volume   10Gi       RWO            Retain           Available                       manual                  33s

可以看到这个PV为10G,访问模式为RWO,卸载后保留,目前的STATUS为可用状态。

创建PVC

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: task-pv-claim
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 3Gi

要求的资源要大于3G,类型为manual,这里一定要跟创建PV时对应上。

[root@k8s-master01 pv-pvc]# kubectl apply -f pv-claim.yaml
persistentvolumeclaim/task-pv-claim created
[root@k8s-master01 pv-pvc]# kubectl get pvc
NAME            STATUS   VOLUME           CAPACITY   ACCESS MODES   STORAGECLASS   AGE
task-pv-claim   Bound    task-pv-volume   10Gi       RWO            manual         8s
www-web-0       Bound    nfspv4           1Gi        RWO            nfs            99m

主要看状态,变成Bound了。查看pvc的状态,也可以看到分配到了10G的资源。

创建pod

apiVersion: v1
kind: Pod
metadata:
  name: task-pv-pod
spec:
  volumes:
    - name: task-pv-storage
      persistentVolumeClaim:
        claimName: task-pv-claim
  containers:
    - name: task-pv-container
      image: nginx:1.18.0
      ports:
        - containerPort: 80
          name: "http-server"
      volumeMounts:
        - mountPath: "/usr/share/nginx/html"
          name: task-pv-storage
  nodeSelector:
    kubernetes.io/hostname: k8s-node01

注意,创建的PV是在master上,目录是在/data下,但是POD被调度到node1上,这样来访问一下:

[root@k8s-master01 pv-pvc]# kubectl get pod -o wide task-pv-pod
NAME          READY   STATUS    RESTARTS   AGE     IP               NODE         NOMINATED NODE   READINESS GATES
task-pv-pod   1/1     Running   0          3m13s   192.168.85.225   k8s-node01   <none>           <none>
[root@k8s-master01 pv-pvc]# curl 192.168.85.225
Thu Apr 29 23:29:45 UTC 2021
2021年 05月 01日 星期六 10:40:34 CST
[root@k8s-master01 pv-pvc]# 
[root@k8s-master01 pv-pvc]# kubectl exec task-pv-pod -- ls -l /usr/share/nginx/html
total 4
-rw-r--r-- 1 root root 72 May  1 02:40 index.html
[root@k8s-master01 pv-pvc]# cat /data/index.html
cat: /data/index.html: 没有那个文件或目录

创建成功之后,可以看到一个curl 与 cat出现的内容不一样。POD里面的的文件内容是node1上面的,而不是master节点上面的。所以hostPath只能调度到自己的机器上。

持久化演示说明-NFS

安装NFS服务器

  1. 在hub仓库机器上创建NFS服务器 ```shell yum install -y nfs-common nfs-utils rpcbind mkdir /nfsdata mkdir /nfsdata{1..3} chmod 777 /nfsdata /nfsdata1 /nfsdata2 /nfsdata3 chown nfsnobody /nfsdata /nfsdata1 /nfsdata2 /nfsdata3

    一下创建四个挂载目录

    vim /etc/exports /nfsdata (rw,no_root_squash,no_all_squash,sync) /nfsdata1 (rw,no_root_squash,no_all_squash,sync) /nfsdata2 (rw,no_root_squash,no_all_squash,sync) /nfsdata3 (rw,no_root_squash,no_all_squash,sync) systemctl start rpcbind systemctl start nfs

    如果修改配置 重启生效

    systemctl restart rpcbind systemctl restart nfs

    其他k8s节点安装客户端

    yum install -y nfs-utils rpcbind

在任意节点测试是否能挂载成功

mkdir /test

查看共享目录

showmount -e 192.168.1.100 mount -t nfs 192.168.1.100:/nfsdata /test/ cd /test/ ls vim index.html

解除挂载

cd - umount /test/ rm -rf /test

<a name="jCgc0"></a>
## 部署PV
部署PV, 创建kubectl apply-f pv.yaml.这里一下创建四个pv

- 查看创建的pv: kubectl get pv
```yaml
apiVersion: v1 
kind: PersistentVolume 
metadata:
  name: nfspv1 
spec:
  capacity:
    storage: 10Gi 
  accessModes:
    - ReadWriteOnce 
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs
  nfs:
   path: /nfsdata
   server: 192.168.18.131
---
apiVersion: v1 
kind: PersistentVolume 
metadata:
  name: nfspv2 
spec:
  capacity:
    storage: 5Gi 
  accessModes:
    - ReadWriteOnce 
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs
  nfs:
   path: /nfsdata1
   server: 192.168.18.131
---
apiVersion: v1 
kind: PersistentVolume 
metadata:
  name: nfspv3
spec:
  capacity:
    storage: 5Gi 
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: slow
  nfs:
   path: /nfsdata2
   server: 192.168.18.131
---
apiVersion: v1 
kind: PersistentVolume 
metadata:
  name: nfspv4
spec:
  capacity:
    storage: 1Gi 
  accessModes:
    - ReadWriteOnce 
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs
  nfs:
   path: /nfsdata3
   server: 192.168.18.131

创建服务并使用PVC

一般我们不会直接用PV,而是用PVC的方案去调度。创建服务并使用PVC。kubectl apply -f pod.yaml

apiVersion: v1 
kind: Service 
metadata:
  name: nginx 
  labels:
    app: nginx 
spec:
  ports:
  - port: 80 
    name: web 
  clusterIP: None # 无头服务
  selector:
    app: nginx
---
apiVersion: apps/v1 
kind: StatefulSet # 要使用StatefulSet控制器,必须建立一个无头服务
metadata:
  name: web 
spec:
  selector:
    matchLabels:
      app: nginx 
  serviceName: "nginx" # 无头服务名称
  replicas: 3 
  template:
    metadata:
      labels:
        app: nginx 
    spec:
      containers:
      - name: nginx 
        image: hub.qnhyn.com/library/myapp
        ports:
        - containerPort: 80 
          name: web 
        volumeMounts: # 挂载下面声明的PVC
        - name: www 
          mountPath: /usr/share/nginx/html  # nginx的共享目录
  volumeClaimTemplates: # 声明一个PVC名称为www
  - metadata:
      name: www 
    spec:
      accessModes: [ "ReadWriteOnce" ] 
      storageClassName: "nfs"
      resources:
        requests:
          storage: 1Gi # 大小

上面创建pod时候会不成功。报错:没有匹配的volume,原因如下:

  • 既满足accessModes: [ “ReadWriteOnce” ]和 storageClassName: “nfs”的只有第一个PV
  • 而我们需要三个副本数。所以创建第二个时就卡住了。
  • 更改下PV的创建文件。重新创建PV即可。