在Kubernetes(K8s)中,PersistentVolumeClaim(PVC)是用于声明对持久化存储资源的需求的一种资源对象。以下是PVC在K8s中的常见使用方式和步骤:
- 定义PVC:
- 创建一个PVC对象,用于声明对存储资源的需求。这包括指定所需的存储大小、访问模式(如ReadWriteOnce、ReadOnlyMany或ReadWriteMany)以及存储类别(如果使用了StorageClass进行动态存储配置)。
- PVC的定义通常包含
apiVersion
、kind
、metadata
和spec
等字段。其中,spec
字段用于描述对存储的具体需求。
- PVC与PV的绑定:
- Kubernetes系统会根据PVC中的声明自动寻找合适的PersistentVolume(PV)进行绑定。PV是集群中由管理员配置或动态创建的存储资源。
- 绑定过程可以基于PV的标签和PVC的选择器进行精确匹配,或者在没有指定选择器时,Kubernetes会基于PVC的存储需求和PV的可用空间进行自动匹配。
- 使用PVC:
- 一旦PVC与PV成功绑定,用户就可以在Pod的定义中引用PVC,将其作为存储卷(Volume)挂载到Pod中。
- Pod通过挂载PVC来使用PV提供的存储资源,从而实现了数据的持久化存储。
- PVC的生命周期:
- PVC的生命周期与Pod类似,可以创建、更新、删除等操作。当PVC不再需要时,可以通过删除PVC对象来释放与其绑定的PV资源。
- 动态存储配置:
- 如果集群中没有现成的PV与PVC的存储需求匹配,Kubernetes可以基于StorageClass(存储类)进行动态存储配置。StorageClass定义了如何为PVC动态创建PV的模板。
- 当PVC需要动态创建PV时,Kubernetes会调用StorageClass中定义的存储后端(如NFS、Ceph、AWS EBS等)来创建满足PVC需求的PV,并将其与PVC进行绑定。
- 注意事项:
- 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
关联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。
使用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。
这里可能发生的情况是:
- 调度和启动:Pod被调度到不同的节点上,并且都成功启动,因为Kubernetes调度器在调度时不会检查存储的多挂载能力。
- 挂载失败:当第一个Pod成功挂载PVC后,其他Pod将尝试挂载同一个PVC,但会失败,因为它们不能在同一个时刻访问RWO卷。这些Pod可能会进入
ContainerCreating
状态,并显示与存储挂载相关的错误。 - 重启和重试:如果集群配置有适当的重试机制(如重启策略),失败的Pod可能会重新启动并尝试重新挂载PVC,但这仍然会失败。