Kubernetes 存储
PV、PVC、StorageClass、动态供给、挂载异常和存储容量治理。
Kubernetes 存储
Kubernetes 使用 Volume、PersistentVolume、PersistentVolumeClaim 和 StorageClass 抽象存储能力。Pod 只关心 PVC,集群管理员或 CSI 插件负责提供实际存储。
核心对象
| 对象 | 说明 |
|---|---|
| Volume | Pod 级别的卷,生命周期通常随 Pod |
| PersistentVolume | 集群级存储资源,简称 PV |
| PersistentVolumeClaim | 用户对存储资源的申请,简称 PVC |
| StorageClass | 动态供给存储的模板 |
| CSI Driver | 存储插件,连接 Kubernetes 和具体存储系统 |
PV / PVC 生命周期
典型流程:
StorageClass
-> PVC
-> dynamic provisioner creates PV
-> Pod mounts PVC
-> application reads and writes data
查看状态:
kubectl get storageclass
kubectl get pvc -A
kubectl get pv
StorageClass
StorageClass 定义动态创建 PV 的方式。
# API 版本。StorageClass 使用 storage.k8s.io/v1。
apiVersion: storage.k8s.io/v1
# 资源类型。这里表示创建 StorageClass。
kind: StorageClass
metadata:
# StorageClass 名称,PVC 通过 storageClassName 引用。
name: fast-ssd
# CSI provisioner 名称,由具体存储插件提供。
provisioner: csi.example.com
# PVC 删除后底层存储的回收策略。
reclaimPolicy: Delete
# 卷绑定模式。WaitForFirstConsumer 会等 Pod 调度时再创建或绑定 PV。
volumeBindingMode: WaitForFirstConsumer
# 是否允许 PVC 扩容。
allowVolumeExpansion: true
# 传递给 CSI 插件的参数,不同插件支持的参数不同。
parameters:
# 存储类型示例。
type: ssd
字段说明:
| 字段 | 说明 |
|---|---|
provisioner | CSI provisioner 名称 |
reclaimPolicy | PVC 删除后 PV 的回收策略 |
volumeBindingMode | 绑定时机 |
allowVolumeExpansion | 是否允许扩容 PVC |
parameters | 传递给存储插件的参数 |
volumeBindingMode 建议:
| 取值 | 说明 |
|---|---|
Immediate | PVC 创建后立即绑定或创建 PV |
WaitForFirstConsumer | 等待 Pod 调度时再绑定,更适合有拓扑限制的存储 |
PVC
申请 20Gi 存储:
# API 版本。PVC 是核心资源,使用 v1。
apiVersion: v1
# 资源类型。这里表示创建 PersistentVolumeClaim。
kind: PersistentVolumeClaim
metadata:
# PVC 名称。
name: data-redis-0
# PVC 所属命名空间。
namespace: default
spec:
# 访问模式,表示卷如何被节点或 Pod 挂载。
accessModes:
# 单节点读写挂载。
- ReadWriteOnce
# 使用的 StorageClass 名称。
storageClassName: fast-ssd
# 申请的资源。
resources:
requests:
# 申请 20Gi 存储容量。
storage: 20Gi
访问模式:
| 模式 | 说明 |
|---|---|
ReadWriteOnce | 单节点读写挂载,最常见 |
ReadOnlyMany | 多节点只读挂载 |
ReadWriteMany | 多节点读写挂载,需要存储支持 |
ReadWriteOncePod | 单个 Pod 读写挂载 |
Pod 挂载 PVC
# API 版本。Pod 是核心资源,使用 v1。
apiVersion: v1
# 资源类型。这里表示创建 Pod。
kind: Pod
metadata:
# Pod 名称。
name: redis
spec:
# 容器列表。
containers:
# 容器名称。
- name: redis
# 容器镜像。
image: redis:7.2
# 容器内挂载点。
volumeMounts:
# 引用 volumes 中名为 data 的卷。
- name: data
# 挂载到容器内的路径。
mountPath: /data
# Pod 卷列表。
volumes:
# 卷名称。
- name: data
# 卷来源是 PVC。
persistentVolumeClaim:
# PVC 名称。
claimName: data-redis-0
StatefulSet 卷模板
StatefulSet 常用 volumeClaimTemplates 为每个副本创建独立 PVC。
# API 版本。StatefulSet 属于 apps 资源组。
apiVersion: apps/v1
# 资源类型。这里表示创建 StatefulSet。
kind: StatefulSet
metadata:
# StatefulSet 名称。
name: redis
spec:
# 关联 Headless Service,提供稳定网络标识。
serviceName: redis-headless
# 副本数,会创建 redis-0、redis-1、redis-2。
replicas: 3
# 选择 StatefulSet 管理的 Pod。
selector:
matchLabels:
app: redis
# Pod 模板。
template:
metadata:
# Pod 标签,必须匹配 selector。
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7.2
volumeMounts:
# 挂载 volumeClaimTemplates 创建的 PVC。
- name: data
mountPath: /data
# PVC 模板,每个 Pod 副本都会生成一个独立 PVC。
volumeClaimTemplates:
# PVC 模板元数据。
- metadata:
# PVC 模板名称,会作为 PVC 名称前缀。
name: data
spec:
# 访问模式。
accessModes:
- ReadWriteOnce
# 使用的 StorageClass 名称。
storageClassName: fast-ssd
# 申请的存储资源。
resources:
requests:
# 每个副本申请 20Gi 存储。
storage: 20Gi
生成的 PVC 名称类似:
data-redis-0
data-redis-1
data-redis-2
PVC 扩容
前提是 StorageClass 开启:
# 是否允许 PVC 扩容。
allowVolumeExpansion: true
修改 PVC:
kubectl patch pvc data-redis-0 -n default \
-p '{"spec":{"resources":{"requests":{"storage":"50Gi"}}}}'
查看状态:
kubectl describe pvc data-redis-0 -n default
kubectl get pvc data-redis-0 -n default
是否需要重启 Pod 取决于 CSI 插件和文件系统扩容能力。
回收策略
| 策略 | 说明 |
|---|---|
Delete | PVC 删除后,底层存储也删除 |
Retain | PVC 删除后,PV 和底层数据保留 |
生产数据库类存储建议谨慎使用 Delete,避免误删 PVC 导致数据丢失。
常见排查
PVC Pending:
kubectl describe pvc <pvc-name> -n <namespace>
kubectl get storageclass
kubectl get events -n <namespace> --sort-by='.lastTimestamp'
Pod 挂载失败:
kubectl describe pod <pod-name> -n <namespace>
kubectl get pvc,pv -n <namespace>
kubectl get pods -n kube-system | grep -i csi
节点侧检查:
journalctl -u kubelet -n 100
mount | grep kubelet
df -h
常见问题
| 现象 | 排查方向 |
|---|---|
| PVC 一直 Pending | StorageClass、不存在的 provisioner、配额不足、拓扑限制 |
| Pod 卡在 ContainerCreating | 卷挂载失败、CSI Node 插件异常、权限问题 |
| PVC 无法扩容 | StorageClass 未开启扩容、CSI 不支持、文件系统限制 |
| 删除 PVC 后数据丢失 | 检查 reclaimPolicy 是否为 Delete |
| 多节点挂载失败 | 检查 accessModes 是否支持 RWX |