Kubernetes 存储三剑客:PV、PVC 和 StorageClass 深度解析
在 Kubernetes 的容器编排世界里,Pod 是短暂的。它们可以随时被创建、删除或迁移到集群中的其他节点。这对于无状态应用(如一个只提供静态内容的 Web 服务器)来说不是问题,但对于有状态应用(如数据库、消息队列或需要存储用户上传文件的应用),数据持久化是核心需求。数据绝不能随着 Pod 的消失而丢失。
为了解决这一挑战,Kubernetes 引入了三个关键概念:Persistent Volume (PV)、Persistent Volume Claim (PVC) 和 StorageClass (SC)。它们共同构建了一套强大的存储管理系统,将存储的生命周期与 Pod 的生命周期解耦,确保您的应用数据能够安全地、长期地保存下来。
1. PV (Persistent Volume):集群的“共享硬盘”
想象一下,PV 是 Kubernetes 集群中真实存在的、可供使用的存储资源。它就像是集群管理员在数据中心里准备好的一个个“共享硬盘”或“存储单元”。这些存储可能来自各种底层技术:网络文件系统 (NFS)、iSCSI、云提供商的块存储服务(如 AWS EBS、Google Persistent Disk、Azure Disk)、或本地存储。
关键特性:
- 集群级别资源: PV 属于整个 Kubernetes 集群,不依附于任何特定的 Pod 或命名空间。
- 存储细节抽象: PV 封装了底层存储的所有复杂细节,比如存储类型、容量、访问模式(如只读、单节点读写、多节点读写)以及回收策略。
- 独立生命周期: 即使使用它的 Pod 被删除或重新调度,PV 中的数据仍然安全地保留。
- 两种供应方式:
- 静态供应: 管理员手动创建 PV 对象,使其指向一个预先存在的存储卷。
- 动态供应: (更常用和推荐)当用户请求存储时,Kubernetes 会根据规则自动创建 PV。
PV YAML 示例(静态供应,指向一个 NFS 共享):
apiVersion: v1
kind: PersistentVolume
metadata:
name: my-nfs-pv # PV 的唯一名称
spec:
capacity:
storage: 10Gi # 这个 PV 提供的存储容量
accessModes:
- ReadWriteMany # 访问模式:可以被多个节点同时以读写方式挂载
persistentVolumeReclaimPolicy: Retain # 回收策略:当 PVC 被删除时,保留底层数据
nfs: # 存储类型为 NFS
path: /srv/nfs/volumes/data # NFS 服务器上的共享路径
server: 192.168.1.100 # NFS 服务器的 IP 地址
2. PVC (Persistent Volume Claim):应用的“存储申请单”
如果 PV 是“共享硬盘”,那么 PVC 就是你的应用程序(Pod)向 Kubernetes 提交的一份“存储申请单”。作为应用开发者,你不需要关心 PV 的具体物理位置或类型,你只在申请单上写明自己需要的存储特性。
关键特性:
- 命名空间资源: PVC 属于特定的命名空间,方便团队管理。
- 需求声明: PVC 声明了所需存储的容量(例如 5GB)、访问模式(例如单节点读写)以及要使用的存储类别(通过 StorageClass)。
- 绑定机制: Kubernetes 收到 PVC 申请后,会尝试找到一个符合要求的 PV 与之绑定。一旦绑定,这个 PV 就被该 PVC 独占了。
- Pod 中引用: Pod 通过引用 PVC 来使用持久化存储,而不是直接引用 PV。
PVC YAML 示例:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-app-data-pvc # PVC 的名称
namespace: default # PVC 所属的命名空间
spec:
accessModes:
- ReadWriteOnce # 请求单节点读写访问
resources:
requests:
storage: 5Gi # 请求 5GB 的存储空间
storageClassName: fast-ssd-storage # 指定要使用的 StorageClass
3. StorageClass (SC):硬盘的“自动化生产线”与“服务标准”
StorageClass 是实现存储动态供应的关键。它由集群管理员定义,用于描述不同**“类别”**的存储服务,以及 Kubernetes 如何自动创建这些存储卷。你可以把它看作是“硬盘生产线标准”或“存储服务模板”。
关键特性:
- 管理员定义: 由集群管理员创建和配置,通常一次配置,多处复用。
- 动态供应核心: 当 PVC 引用某个 StorageClass 时,SC 中定义的
provisioner(存储插件)会被调用,自动在底层存储系统上创建实际的存储卷,并生成对应的 PV 对象。 - 定义存储特性: SC 中可以定义:
provisioner: 指定哪个存储插件负责供应存储(例如,GCP 的pd.csi.storage.gke.io,AWS 的ebs.csi.aws.com,或本地路径的rancher.io/local-path)。parameters: 传递给provisioner的具体参数,用于细化存储特性,如硬盘类型(SSD/HDD)、IOPS、复制策略等。reclaimPolicy: 当 PV 被释放(PVC 被删除)时,底层存储资源如何处理(Retain保留数据,Delete自动删除数据)。volumeBindingMode: 定义 PV 和 PVC 绑定的时机(Immediate立即绑定,WaitForFirstConsumer等 Pod 真正需要时再绑定,有助于调度优化)。
StorageClass YAML 示例(使用 GCP 的 SSD 持久盘):
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd-storage # StorageClass 的名称
provisioner: pd.csi.storage.gke.io # GCP CSI 驱动,用于动态创建持久盘
parameters:
type: pd-ssd # 参数:创建 SSD 类型的持久盘
reclaimPolicy: Delete # 当 PVC 删除时,自动删除对应的 GCP 持久盘
volumeBindingMode: WaitForFirstConsumer # 等待第一个 Pod 调度到节点时才创建实际存储
PV、PVC、SC 协同工作:一个 Nginx 网站的例子
让我们用一个具体的例子来理解这三者是如何协同工作的:为 Nginx 网站提供持久化存储。
目标: 部署一个 Nginx Pod,并将它的网页文件存储在一个 1GB 的高速 SSD 盘上,确保数据不丢失。
步骤 1:集群管理员定义 StorageClass (SC)
管理员首先定义一个名为 my-fast-ssd 的 StorageClass,告诉 Kubernetes 如何提供高速 SSD 存储。
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: my-fast-ssd # 定义一个名为 'my-fast-ssd' 的存储类别
provisioner: pd.csi.storage.gke.io # 使用 GCP 的 CSI 驱动来创建存储
parameters:
type: pd-ssd # 指定创建 SSD 类型的磁盘
reclaimPolicy: Delete # 当 PVC 被删除时,对应的 SSD 磁盘也会被删除
volumeBindingMode: Immediate # 立即绑定 PVC 和 PV
管理员执行:kubectl apply -f 1-storageclass.yaml 此时,没有实际的存储卷被创建,只是定义了一个规则。
步骤 2:开发者(你)在 StatefulSet 中声明 PVC 模板
你编写一个 Nginx 的 StatefulSet,并在其 volumeClaimTemplates 中声明你需要的存储。
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: nginx-web # StatefulSet 的名称
spec:
serviceName: "nginx-service" # 关联的 Headless Service
replicas: 1
selector:
matchLabels:
app: nginx-web
template:
metadata:
labels:
app: nginx-web
spec:
containers:
- name: nginx-container
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: website-content # 引用下方 PVC 模板中定义的卷
mountPath: /usr/share/nginx/html # Nginx 存放网页文件的目录
# ... 其他可能的卷和配置 ...
volumeClaimTemplates: # <<--- 关键:在这里定义 PVC 模板
- metadata:
name: website-content # 这个名称会成为实际 PVC 名称的一部分,并与 volumeMounts 对应
spec:
accessModes: [ "ReadWriteOnce" ] # 请求单节点读写
storageClassName: "my-fast-ssd" # <<--- 明确指出使用我们定义的 StorageClass
resources:
requests:
storage: 1Gi # <<--- 请求 1GB 的存储空间
执行:kubectl apply -f 2-nginx-statefulset.yaml
魔法发生:
- 当
nginx-webStatefulSet 启动时,它会根据replicas: 1创建一个 Pod (例如nginx-web-0)。 - 为了给
nginx-web-0提供存储,StatefulSet 会自动创建一个 PVC,例如名称可能为website-content-nginx-web-0。 - 这个自动创建的 PVC 会请求 1GB 存储,并指定
storageClassName: "my-fast-ssd"。 - Kubernetes 调度器接收到这个 PVC 请求,并找到匹配的
my-fast-ssdStorageClass。 my-fast-ssdStorageClass 定义的pd.csi.storage.gke.ioprovisioner被调用。- 这个
provisioner会在 GCP 云平台上动态创建一个实际的 1GB SSD 持久盘。 - 同时,Kubernetes 会为这个新创建的 GCP 持久盘生成一个对应的 PersistentVolume (PV) 对象(例如
pvc-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)。 - 最后,这个新的 PV 会自动与
website-content-nginx-web-0这个 PVC 绑定。 - Nginx Pod (
nginx-web-0) 启动后,这个 PV(代表的 GCP SSD 盘)就会被挂载到其/usr/share/nginx/html路径下。
验证一下:
kubectl get pvc
# 应该会看到一个类似 'website-content-nginx-web-0' 的 PVC,状态为 'Bound'
kubectl get pv
# 应该会看到一个自动创建的 PV,状态也是 'Bound',且容量为 1Gi
现在,即使 Nginx Pod 重启、被删除或被调度到其他节点,只要 website-content-nginx-web-0 这个 PVC 不被删除,底层的数据就始终存储在那个 1GB 的 SSD 持久盘上,不会丢失。
通过 PV、PVC 和 StorageClass,Kubernetes 实现了存储的解耦和自动化:
- StorageClass (SC): 定义了存储服务的“类型”和“自动化创建规则”。
- PersistentVolumeClaim (PVC): 应用对存储的“需求声明”,包括容量和所需类型。
- PersistentVolume (PV): Kubernetes 中实际可用的、持久化的存储资源。
更多推荐


所有评论(0)