十、k8s入门系列----PV、PVC、StorageClass

  关于PV、PVC、StorageClass ,这篇文章讲的不错:https://www.cnblogs.com/rexcheny/p/10925464.html

  容器的设计理念就是一次性,也就是容器销毁后容器里的所有数据都会销毁,所以需要将容器里面需要保留的数据挂载到持久性存储中,这里就涉及到三个概念:PV、PVC、StorageClass 。

  HostPath

  当使用docker创建container的时候,一般都是加参数 -v 挂载宿主机的目录到container里面,k8s 也可以实现该功能,先讲解一下 挂载到宿主机目录的方法。 

  创建一个deployment资源配置文件,挂载到宿主机目录:

[root@ylserver10686071 ~]# cat volumes001.yml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: volumes001
  namespace: prod
spec:
  replicas: 1
  selector:
    matchLabels:
      k8s-app: volumes001
  template:
    metadata:
      labels:
        k8s-app: volumes001
    spec:
      containers:
      - name: nginx
        image: nginx:1.21
        volumeMounts:
        - mountPath: /usr/share/nginx/html/
          name: html
      volumes:
      - name: html
        hostPath:
          path: /data/nginx/html/
          type: DirectoryOrCreate
  • volumeMounts 挂载到container 指定目录的相关配置,根据name来匹配volumes对象的下的name,据此来找到挂载对象
  • volumes              声明挂载对象
  • hostPath             存储类型
  • type: DirectoryOrCreate  如果宿主机路径不存在则创造该路径,当值为Directory 是,宿主机必须有该目录,否则会导致pod创建失败

 

  创建deployment资源,查看pod在哪台Node上运行:

[root@ylserver10686071 ~]# kubectl apply -f volumes001.yml 
deployment.apps/volumes001 created
[root@ylserver10686071 ~]# kubectl get pods -n prod -o wide
NAME                          READY   STATUS    RESTARTS   AGE   IP             NODE               NOMINATED NODE   READINESS GATES
volumes001-66767f866f-rc5qk   1/1     Running   0          21s   10.233.72.59   ylserver10686073   <none>           <none>
[root@ylserver10686071 ~]# 

  在ylserver10686071 Node上查看目录是否创建,然后到Pod运行的节点上查看目录是否创建:

[root@ylserver10686071 ~]# ll /data/nginx/html/
ls: cannot access /data/nginx/html/: No such file or directory
[root@ylserver10686071 ~]# 
[root@ylserver10686073 ~]# ll /data/nginx/html/
total 0
[root@ylserver10686073 ~]# 

  给挂载目录创建文件,验证是否挂载到Pod里面:

[root@ylserver10686073 ~]# echo "Hello K8S" > /data/nginx/html/index.html
[root@ylserver10686073 ~]# curl http://10.233.72.59/index.html
Hello K8S
[root@ylserver10686073 ~]# 

  

   PV

  上面的实验中宿主机挂载的目录只有在 Pod 运行的 Node 上才会创建,换言之,Pod要挂载的目录必须跟Node做绑定,这会增加运维的难度,也失去k8s的故障转移特性。

  针对这个问题,可以使用存储券解决,这里就要引入一个概念:PV。

  PV全称叫做Persistent Volume,持久化存储卷。它是用来描述或者说用来定义一个存储卷的,这个通常都是有运维或者数据存储工程师来定义。本节使用NFS来作为存储端,NFS搭建这里不做讲解。

  先创建一个PV资源配置文件:

[root@ylserver10686071 ~]# cat pv001.yml 
apiVersion: v1
kind: PersistentVolume  ###PV资源不属于任何命名空间,属于集群级别的
                        ###kubectl api-resources --namespaced=true 命令可以查看哪些资源属于命名空间              
metadata:  
  name: pv001  
  labels:   ###Label可以不定义        
    name: pv001
    storetype: nfs
spec:    ###定义PV资源规格
  storageClassName: normal
  accessModes:  ###设置访问模型
    - ReadWriteMany
    - ReadWriteOnce
    - ReadOnlyMany
  capacity:  ###设置存储空间大小
    storage: 500Mi
  persistentVolumeReclaimPolicy: Retain  ###回收策略
  nfs:  
    path: /data/nfs/k8s/
    server: 10.68.60.193
[root@ylserver10686071 ~]# 

  

  accessModes 有3种属性值:

  • ReadWriteMany     多路读写,卷能被集群多个节点挂载并读写
  • ReadWriteOnce     单路读写,卷只能被单一集群节点挂载读写
  • ReadOnlyMany      多路只读,卷能被多个集群节点挂载且只能读

 

  persistentVolumeReclaimPolicy 回收策略也有3种属性值:

  • Retain

     当删除与之绑定的PVC时候,这个PV被标记为released(PVC与PV解绑但还没有执行回收策略)且之前的数据依然保存在该PV上,但是该PV不可用,需要手动来处理这些数据并删除该PV

   这种方式是最常用的,可以避免误删pvc或者pv而造成数据的丢失

  • Delete       删除存储资源,AWS EBS, GCE PD, Azure Disk, and Cinder volumes支持这种方式
  • Recycle     这个在1.14版本中以及被废弃,取而代之的是推荐使用动态存储供给策略,它的功能是当删除与该PV关联的PVC时,自动删除该PV中的所有数据

   

  创建完PV后,PV会有几种状态:

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

   

  创建PV资源,并查看PV信息:

[root@ylserver10686071 ~]# kubectl apply -f pv001.yml 
persistentvolume/pv001 created
[root@ylserver10686071 ~]# kubectl get pv 
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv001   500Mi      RWO,ROX,RWX    Retain           Available           normal                  6s

  


   PVC

  PV只是定义了一个存储卷实体,还需要一层抽象的接口使其与POD关联,这层抽象的接口就是PVC,全称 Persistent Volume Claim,也就是持久化存储声明。开发人员使用这个来描述该容器需要一个什么存储。

  创建一个PVC资源配置文件:

[root@ylserver10686071 ~]# cat pvc001.yml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc001
  namespace: prod   ###PVC资源属于命名空间级别
  labels:       ###Label可以不定义
    name: pvc001
    storetype: nfs
    capacity: 500Mi
spec:
  storageClassName: normal
  accessModes:    ###PVC也需要定义访问模式,不过它的模式一定是和现有PV相同或者是它的子集,否则匹配不到PV
  - ReadWriteMany
  resources:   ###定义资源要求PV满足这个PVC的要求才会被匹配到
    requests:
      storage: 500Mi  # 定义要求有多大空间

  创建PVC资源,查看PVC资源和PV资源绑定情况,可以看到PV和PVC已经实现绑定:

[root@ylserver10686071 ~]# kubectl apply -f pvc001.yml 
persistentvolumeclaim/pvc001 created
[root@ylserver10686071 ~]# kubectl get pvc -n prod
NAME     STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
pvc001   Bound    pv001    500Mi      RWO,ROX,RWX    normal         15s
[root@ylserver10686071 ~]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv001 500Mi RWO,ROX,RWX Retain Bound prod/pvc001 normal 62m
[root@ylserver10686071 ~]#

  

  PVC是如何跟PVC绑定的呢,有以下几个原则:

  • PV和PVC中的spec关键字段要匹配,比如存储(storage)大小
  • PVC的访问模式一定是和现有PV相同或者是它的子集,否则匹配不到PV
  • PV和PVC中的 StorageClass  Name字段必须一致,StorageClass后面会讲到
  • Label 标签在这里只做描述作用,跟 PV 和 PVC 的绑定没有任何关系

 

  看到这里,回想总结一下就会发现 k8s 里面会通过定义一层抽象概念来管理实体或者连接实体,类似于 Pod 和 Container , PVC 和 PV ;对象和对象的匹配设计原理也是一直,例如 deployment匹配replicaset通过matchLabels ,PV 和 PVC通过 StorageClass  Name以及 resources等,即对象与对象之间通过匹配关系进行绑定。

 

  更新上面的deployment资源配置文件,使其使用创建好的PVC资源:

[root@ylserver10686071 ~]# cat volumes001.yml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: volumes001
  namespace: prod   ###要和指定的PVC同一个命名空间
spec:
  replicas: 1
  selector:
    matchLabels:
      k8s-app: volumes001
  template:
    metadata:
      labels:
        k8s-app: volumes001
    spec:
      containers:
      - name: nginx
        image: nginx:1.21
        volumeMounts:   ###container的挂载声明没有改变
        - mountPath: /usr/share/nginx/html/
          name: html
      volumes:     ###依然使用volumes声明挂载卷
      - name: html
        persistentVolumeClaim:   ###指定PVC
          claimName: pvc001

  更新资源deployment资源配置文件,查看pod关于volumes相关信息:

[root@ylserver10686071 ~]# kubectl apply -f volumes001.yml 
deployment.apps/volumes001 configured
[root@ylserver10686071 ~]# kubectl describe pod volumes001 -n prod|grep -5 Volumes
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  html:
    Type:       PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
    ClaimName:  pvc001
    ReadOnly:   false
  default-token-lx75g:
[root@ylserver10686071 ~]# 

  写一个文件到NFS挂载目录中,测试一下效果:

[root@ylserver106860193 ~]# echo "K8S PV" > /data/nfs/k8s/index.html
[root@ylserver10686071 ~]# kubectl get pods -n prod -o wide
NAME                          READY   STATUS    RESTARTS   AGE   IP             NODE               NOMINATED NODE   READINESS GATES
volumes001-55f5bb9585-nx9xd   1/1     Running   0          11m   10.233.72.60   ylserver10686073   <none>           <none>
[root@ylserver10686071 ~]# curl http://10.233.72.60
K8S PV
[root@ylserver10686071 ~]# 

  

  

十、k8s入门系列----PV、PVC、StorageClass

上一篇:sed 去除行尾多个字母


下一篇:免交互