持久卷(PV/PVC)存储管理
约 1361 字大约 5 分钟
kubernetesstorage
2025-06-13
Kubernetes 通过 PersistentVolume(PV)、PersistentVolumeClaim(PVC)和 StorageClass 三层抽象实现存储管理,将存储的供给与消费解耦。本文将全面讲解存储体系的核心概念和实践用法。
存储架构
PersistentVolume(PV)
PV 是集群级别的存储资源,由管理员预先创建或通过 StorageClass 动态供给:
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv-01
labels:
type: nfs
environment: production
spec:
capacity:
storage: 100Gi
volumeMode: Filesystem # Filesystem 或 Block
accessModes:
- ReadWriteMany # 多节点读写
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs-storage
mountOptions:
- hard
- nfsvers=4.1
nfs:
server: 192.168.1.100
path: /exports/dataAccess Modes(访问模式)
| 模式 | 缩写 | 描述 |
|---|---|---|
| ReadWriteOnce | RWO | 单节点读写 |
| ReadOnlyMany | ROX | 多节点只读 |
| ReadWriteMany | RWX | 多节点读写 |
| ReadWriteOncePod | RWOP | 单 Pod 读写(K8s 1.27+) |
不同存储后端支持的访问模式不同:
| 存储类型 | RWO | ROX | RWX |
|---|---|---|---|
| AWS EBS | 支持 | - | - |
| GCE PD | 支持 | 支持 | - |
| NFS | 支持 | 支持 | 支持 |
| Ceph RBD | 支持 | 支持 | - |
| CephFS | 支持 | 支持 | 支持 |
Reclaim Policy(回收策略)
- Retain:PVC 删除后 PV 变为 Released 状态,数据保留,需手动清理后重新绑定
- Delete:PVC 删除后自动删除 PV 和底层存储资源(云盘等)
- Recycle(已废弃):执行
rm -rf /thevolume/*
PersistentVolumeClaim(PVC)
PVC 是用户对存储的请求声明:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-data-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 50Gi
storageClassName: fast-ssd # 指定 StorageClass
selector: # 可选:选择特定 PV
matchLabels:
type: nfs
environment: production在 Pod 中使用 PVC:
apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
containers:
- name: app
image: myapp:1.0
volumeMounts:
- name: data
mountPath: /app/data
- name: cache
mountPath: /app/cache
volumes:
- name: data
persistentVolumeClaim:
claimName: app-data-pvc
- name: cache
emptyDir:
sizeLimit: 1Gi # 临时存储限制StorageClass(存储类)
StorageClass 定义动态供给存储的方式,避免手动创建 PV:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: ebs.csi.aws.com # CSI 驱动
parameters:
type: gp3
iops: "5000"
throughput: "250"
encrypted: "true"
fsType: ext4
reclaimPolicy: Delete
allowVolumeExpansion: true # 允许在线扩容
volumeBindingMode: WaitForFirstConsumer # 延迟绑定
mountOptions:
- noatime
- nodiratimeVolume Binding Mode
- Immediate(默认):PVC 创建后立即供给和绑定 PV
- WaitForFirstConsumer:等到 Pod 调度到节点后再供给 PV(适用于拓扑限制的存储)
Volume Expansion(卷扩容)
StorageClass 设置 allowVolumeExpansion: true 后,可以在线扩容 PVC:
# 修改 PVC 的 storage 请求
kubectl patch pvc app-data-pvc -p '{"spec":{"resources":{"requests":{"storage":"100Gi"}}}}'# 扩容后 PVC 状态
status:
capacity:
storage: 100Gi
conditions:
- type: FileSystemResizePending
status: "True"
message: "Waiting for user to (re-)start a pod to finish file system resize"注意:
- 只能扩容,不能缩小
- 某些 CSI 驱动支持在线扩容(不需要重启 Pod)
- 文件系统类型的卷需要文件系统扩展支持(ext4、xfs 支持,某些旧版本不支持)
CSI 驱动
Container Storage Interface(CSI)是 Kubernetes 的标准存储插件接口:
# CSI Driver 对象
apiVersion: storage.k8s.io/v1
kind: CSIDriver
metadata:
name: ebs.csi.aws.com
spec:
attachRequired: true
podInfoOnMount: false
volumeLifecycleModes:
- Persistent
fsGroupPolicy: File常用 CSI 驱动:
| 驱动 | 存储后端 | 访问模式 |
|---|---|---|
| ebs.csi.aws.com | AWS EBS | RWO |
| pd.csi.storage.gke.io | GCE PD | RWO, ROX |
| disk.csi.azure.com | Azure Disk | RWO |
| file.csi.azure.com | Azure Files | RWX |
| nfs.csi.k8s.io | NFS | RWX |
| rook-ceph.rbd.csi.ceph.com | Ceph RBD | RWO |
StatefulSet 与 PVC
StatefulSet 通过 volumeClaimTemplates 为每个 Pod 自动创建独立的 PVC:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysql-headless
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
ports:
- containerPort: 3306
volumeMounts:
- name: data
mountPath: /var/lib/mysql
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: root-password
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: fast-ssd
resources:
requests:
storage: 50Gi自动创建的 PVC 命名规则:<volumeClaimTemplate-name>-<statefulset-name>-<ordinal>
kubectl get pvc
# NAME STATUS VOLUME CAPACITY ACCESS MODES
# data-mysql-0 Bound pvc-xxx1 50Gi RWO
# data-mysql-1 Bound pvc-xxx2 50Gi RWO
# data-mysql-2 Bound pvc-xxx3 50Gi RWO注意:缩容 StatefulSet 不会自动删除 PVC,需手动清理。
Local Persistent Volume
Local PV 使用节点本地磁盘,提供更高的 I/O 性能,但牺牲了高可用(Pod 绑定到特定节点):
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-storage
provisioner: kubernetes.io/no-provisioner # 不支持动态供给
volumeBindingMode: WaitForFirstConsumer # 必须延迟绑定
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: local-pv-node1
spec:
capacity:
storage: 200Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: local-storage
local:
path: /mnt/data # 节点本地路径
nodeAffinity: # 必须指定节点亲和性
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- worker-node-01Volume Snapshots
Volume Snapshot 允许对 PV 创建快照,用于备份和恢复:
# VolumeSnapshotClass
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
name: csi-ebs-snapclass
driver: ebs.csi.aws.com
deletionPolicy: Delete
---
# 创建快照
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: mysql-data-snapshot
spec:
volumeSnapshotClassName: csi-ebs-snapclass
source:
persistentVolumeClaimName: data-mysql-0
---
# 从快照恢复
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-data-restored
spec:
accessModes:
- ReadWriteOnce
storageClassName: fast-ssd
resources:
requests:
storage: 50Gi
dataSource:
name: mysql-data-snapshot
kind: VolumeSnapshot
apiGroup: snapshot.storage.k8s.io总结
Kubernetes 存储管理的关键实践:
- 使用 StorageClass 动态供给,避免手动管理 PV
- 设置
WaitForFirstConsumer绑定模式,确保 PV 在正确的可用区创建 - 启用卷扩容(
allowVolumeExpansion: true),便于后续调整容量 - StatefulSet 的 PVC 需手动清理,缩容不会自动删除
- Local PV 适用于高 I/O 场景,但需接受节点绑定的限制
- 定期创建 Volume Snapshot 备份关键数据
贡献者
更新日志
2026/3/14 13:09
查看所有更新日志
9f6c2-feat: organize wiki content and refresh site setup于