在Kubernetes(K8s)中,PersistentVolumeClaim(PVC)是用于声明对持久化存储资源的需求的一种资源对象。以下是PVC在K8s中的常见使用方式和步骤:

  1. 定义PVC
  • 创建一个PVC对象,用于声明对存储资源的需求。这包括指定所需的存储大小、访问模式(如ReadWriteOnce、ReadOnlyMany或ReadWriteMany)以及存储类别(如果使用了StorageClass进行动态存储配置)。
  • PVC的定义通常包含apiVersionkindmetadataspec等字段。其中,spec字段用于描述对存储的具体需求。
  1. PVC与PV的绑定
  • Kubernetes系统会根据PVC中的声明自动寻找合适的PersistentVolume(PV)进行绑定。PV是集群中由管理员配置或动态创建的存储资源。
  • 绑定过程可以基于PV的标签和PVC的选择器进行精确匹配,或者在没有指定选择器时,Kubernetes会基于PVC的存储需求和PV的可用空间进行自动匹配。
  1. 使用PVC
  • 一旦PVC与PV成功绑定,用户就可以在Pod的定义中引用PVC,将其作为存储卷(Volume)挂载到Pod中。
  • Pod通过挂载PVC来使用PV提供的存储资源,从而实现了数据的持久化存储。
  1. PVC的生命周期
  • PVC的生命周期与Pod类似,可以创建、更新、删除等操作。当PVC不再需要时,可以通过删除PVC对象来释放与其绑定的PV资源。
  1. 动态存储配置
  • 如果集群中没有现成的PV与PVC的存储需求匹配,Kubernetes可以基于StorageClass(存储类)进行动态存储配置。StorageClass定义了如何为PVC动态创建PV的模板。
  • 当PVC需要动态创建PV时,Kubernetes会调用StorageClass中定义的存储后端(如NFS、Ceph、AWS EBS等)来创建满足PVC需求的PV,并将其与PVC进行绑定。
  1. 注意事项
  • PVC需要分配在特定的命名空间中,如果不指定命名空间,则默认在default命名空间中创建。
  • 一个Pod只能使用当前命名空间中的PVC。
  • PVC和PV是一一对应的,即一个PV只能为一个PVC服务。

实操

PVC手动绑定PV   

创建PV     

在前文,使用nfs创建了PV,在这里可以对其进行手动绑定。


apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv01
spec:
  accessModes:
  - ReadOnlyMany
    #ReadWriteOnce:   【RWO】 允许单个节点【读写】这个存储卷;
    #ReadOnlyMany:    【ROX】 允许多个节点【只读】这个存储卷;
    #ReadWriteMany:   【RWX】 允许多个节点【读写】这个存储卷;
    #ReadWriteOncePod:【RWOP】允许单个 pod【读写】这个存储卷;1.22版本后新功能;
  persistentVolumeReclaimPolicy: Retain
  #声明数据的回收策略
  #Retain: 删除PVC时,PV不被删除,状态:已释放,需要手动回收,其他pod否则无法直接使用
  #Delete: 删除PVC时,PV和数据都将被删除;
  #Recycle:官方已经弃用;(删除PVC时,自动清理对应数据,其他pod可以继续使用)
  capacity:
    storage: 100Mi
  mountOptions:
  - hard
  - vers=4.1
  nfs:
    path: /opt/nfs/data/pv1
    server: 192.168.0.190

从0开始搞K8S:PersistentVolumeClaim_PVC

关联PVC

pvc链接pv的方式有两种:

指定pv;在spec中指定volumeName来指定PV

根据资源限制条件自动匹配,pvc会自动去寻找系统中存在的所有pv,从中匹配一个合适的,进行自动化存储;

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc01
spec:
  # 声明要是用的pv;PVC会根据资源限制自动选择pv存储卷;
  # volumeName: pv03 #不写volumeName就会自动根据资源限制自动选择; 
  # 声明资源的访问模式
  accessModes:
  - ReadOnlyMany
  # 声明资源的使用量
  resources:
    limits:
       storage: 100Mi
    requests:
       storage: 10Mi

查看PV和PVC可以看到两者已经绑定,ACCESS MODE是RWX即ReadOnlyMany

如果PV不满足PVC的条件,PVC的status将一直是pending。

从0开始搞K8S:PersistentVolumeClaim_PVC_02

使用PVC

使用一个deployment来使用这个pvc

apiVersion: apps/v1
kind: Deployment
metadata:
  name: dp-pvc
spec:
  selector:
    matchLabels:
      app: pvc
  replicas: 2
  
  template:
    metadata:
      labels:
        app: pvc
    spec:
      volumes:
      - name: pod-pvc
        persistentVolumeClaim:
          claimName: pvc01
      containers:
      - name: c
        image: busybox
        command: ["/bin/sh", "-c", "sleep 600"]
        volumMounts:
        - name: pod-pvc
          mountPath: /tmp

说明:

在这个例子中PVC和PV的accessmode是ReadWriteMany,Deployment所创建的Pod可以在预期内与PVC进行挂载。但实际上,即便accessmode是ReadWriteOnce,其挂载也会成功。

在Kubernetes中,ReadWriteOnce(RWO)的PersistentVolume(PV)和PersistentVolumeClaim(PVC)确实意味着该卷在同一时间只能被一个节点上的一个Pod挂载为读写模式。但是,这并不意味着你不能在一个Deployment中指定多个副本(replicas),每个副本尝试挂载同一个PVC。

实际上,当你创建一个Deployment并指定多个副本时,Kubernetes会尝试在集群中的不同节点上调度这些Pod。由于每个Pod都在其自己的节点上运行,并且每个Pod都尝试挂载同一个PVC,但Kubernetes的存储系统(如NFS、GlusterFS、AWS EBS等)需要支持多挂载(multi-attach)或者每个Pod在逻辑上获得PVC的一个独立实例(这通常不是真正的PVC机制,而是像StatefulSet这样的控制器使用持久卷模板为每个Pod创建独立的PV和PVC)。

但是,对于大多数RWO存储后端(如本地存储、大多数云提供商提供的块存储等),这种情况实际上是不可能的,因为RWO限制意味着每个时刻只有一个Pod可以访问该卷。但是,Kubernetes调度器并不知道这一点,它会尝试在多个节点上调度Pod,即使它们引用了同一个RWO PVC。

这里可能发生的情况是:

  1. 调度和启动:Pod被调度到不同的节点上,并且都成功启动,因为Kubernetes调度器在调度时不会检查存储的多挂载能力。
  2. 挂载失败:当第一个Pod成功挂载PVC后,其他Pod将尝试挂载同一个PVC,但会失败,因为它们不能在同一个时刻访问RWO卷。这些Pod可能会进入ContainerCreating状态,并显示与存储挂载相关的错误。
  3. 重启和重试:如果集群配置有适当的重试机制(如重启策略),失败的Pod可能会重新启动并尝试重新挂载PVC,但这仍然会失败。