持久存储卷声明 (PVC, Persistent Volume Claim) 是用户的一种存储请求。它和 Pod 类似,Pod 消耗 Node 资源,而 PVC 消耗 PV 资源。Pod 能够请求特定的资源(如 CPU 和内存)。PVC 能够请求指定的大小和访问的模式(可以被映射为一次读写或者多次只读)。

PVC 配置文件

nfs-data.yaml

  1. apiVersion: v1
  2. kind: PersistentVolumeClaim
  3. metadata:
  4. name: nfs-data
  5. spec:
  6. accessModes: ["ReadWriteOnce"]
  7. resources: # 指定请求的资源,存储3G
  8. requests:
  9. storage: 3Gi
  10. storageClassName: slow
  11. selector:
  12. matchLabels:
  13. release: "stable"
  14. matchExpressions:
  15. - { key: environment, operator: In, values: [dev] }

accessModes 访问模式

当请求指定访问模式的存储时,PVC 使用的规则和 PV 相同。支持三种访问模式:

  • ReadWriteOnce – PV 以 read-write 挂载到一个节点
  • ReadOnlyMany – PV 以 read-only 方式挂载到多个节点
  • ReadWriteMany – PV 以 read-write 方式挂载到多个节点

resources 资源

PVC,就像 pod 一样,可以请求指定数量的资源。请求资源时,PV 和 PVC 都使用相同的资源样式。

selector 选择器

PVC 可以指定标签选择器进行更深度的过滤 PV,只有匹配了选择器标签的 PV 才能绑定给 PVC。选择器包含两个字段:

  • matchLabels(匹配标签) - PV 必须有一个包含该值得标签
  • matchExpressions(匹配表达式) - 一个请求列表,包含指定的键、值的列表、关联键和值的操作符。合法的操作符包含 In,NotIn,Exists,和 DoesNotExist。

所有来自matchLabelsmatchExpressions的请求,都是逻辑与关系的,它们必须全部满足才能匹配上。

storageClassName 等级

PVC 可以使用属性 storageClassName 来指定 StorageClass 的名称,从而请求指定的等级。只有满足请求等级的 PV,即那些包含了和 PVC 相同storageClassName的 PV,才能与 PVC 绑定。

PVC 并非必须要请求一个等级。设置 storageClassName'' 的 PVC 总是被理解为请求一个无等级的 PV,因此它只能被绑定到无等级的 PV(未设置对应的标注,或者设置为 '')。未设置storageClassName的 PVC 不太相同,DefaultStorageClass 的权限插件打开与否,集群也会区别处理 PVC。

  • 如果权限插件被打开,管理员可能会指定一个默认的StorageClass。所有没有指定StorageClassName的 PVC 只能被绑定到默认等级的 PV。要指定默认的StorageClass,需要在StorageClass对象中将标注storageclass.kubernetes.io/is-default-class设置为“true”。如果管理员没有指定这个默认值,集群对 PVC 创建请求的回应就和权限插件被关闭时一样。如果指定了多个默认等级,那么权限插件禁止 PVC 创建请求。
  • 如果权限插件被关闭,那么就没有默认StorageClass的概念。所有没有设置StorageClassName的 PVC 都只能绑定到没有等级的 PV。因此,没有设置StorageClassName的 PVC 就如同设置StorageClassName'' 的 PVC 一样被对待。

根据安装方法的不同,默认的StorageClass可能会在安装过程中被插件管理默认的部署在 Kubernetes 集群中。

当 PVC 指定selector来请求StorageClass时,所有请求都是与操作的。只有满足了指定等级和标签的 PV 才可能绑定给 PVC。当前,一个非空 selector 的 PVC 不能使用 PV 动态供给。

创建 PVC

kubectl create -f nfs-data.yaml

创建 Pod 以使用 PVC

pv-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: redis
  labels:
    app: redis
spec:
  containers:
    - name: redis
      image: redis
      imagePullPolicy: Never
      volumeMounts:
        - mountPath: "/data"
          name: data
      ports:
        - containerPort: 6379
  volumes:
    - name: data
      persistentVolumeClaim: # 指定使用的PVC
        claimName: nfs-data # 名字一定要正确

当前 Pod 可用空间为 3G,如果超过 3G,则需要再创建存储来满足需求,因为是网络数据卷,如果需要扩展空间,直接删除 Pod 再建立一个即可。

获取 pvc 信息

pvc 可以指定命名空间, 默认为 default

$ kubectl get pvc --all-namespaces
NAMESPACE   NAME       STATUS   VOLUME    CAPACITY   ACCESS MODES   STORAGECLASS   AGE
test        nfs-data   Bound    test-pv   15Gi       RWX                           5m20s

$ kubectl get pvc -n test
NAME       STATUS   VOLUME    CAPACITY   ACCESS MODES   STORAGECLASS   AGE
nfs-data   Bound    test-pv   15Gi       RWX                           44m

查看 pvc 详情

$ kubectl describe pvc nfs-data -n test
Name:          nfs-data
Namespace:     test
StorageClass:
Status:        Bound
Volume:        test-pv
Labels:        <none>
Annotations:   pv.kubernetes.io/bind-completed: yes
               pv.kubernetes.io/bound-by-controller: yes
Finalizers:    [kubernetes.io/pvc-protection]
Capacity:      15Gi
Access Modes:  RWX
VolumeMode:    Filesystem
Events:
  Type       Reason         Age                 From                         Message
  ----       ------         ----                ----                         -------
  Normal     FailedBinding  43m (x12 over 46m)  persistentvolume-controller  no persistent volumes available for this claim and no storage class is set
Mounted By:  <none>

可以看到, nfs-data 使用了持久卷 test-pv