存储架构:三层抽象
K8s 存储抽象层次 ┌──────────────────────────────────────────────┐ │ Pod / Container │ │ 声明存储需求,不关心底层实现 │ └──────────────────────┬───────────────────────┘ │ 引用 ┌──────────────────────▼───────────────────────┐ │ PVC (PersistentVolumeClaim) │ │ 用户声明:需要 10Gi,ReadWriteOnce │ └──────────────────────┬───────────────────────┘ │ 绑定 (Binding) ┌──────────────────────▼───────────────────────┐ │ PV (PersistentVolume) │ │ 集群管理员提供:AWS EBS / NFS / Ceph │ └──────────────────────┬───────────────────────┘ │ ┌──────────────────────▼───────────────────────┐ │ 实际存储后端 │ │ 云磁盘 / NFS / Ceph / 本地磁盘 │ └──────────────────────────────────────────────┘
PV (PersistentVolume)
集群级别的存储资源,由管理员预先创建或 StorageClass 动态创建。代表实际的存储后端(一块云磁盘、一个 NFS 目录等),生命周期独立于 Pod。
PVC (PersistentVolumeClaim)
命名空间级别的存储申领,由用户(开发者)创建。声明所需的存储大小和访问模式,K8s 自动将其与满足条件的 PV 绑定。
StorageClass
存储类,定义"如何动态创建 PV"的模板。包含 Provisioner(如 aws-ebs-csi-driver)和参数(磁盘类型、IOPS)。PVC 引用 StorageClass 触发动态 Provisioning。
访问模式(AccessModes)
| 模式 | 简写 | 含义 | 支持的存储 |
|---|---|---|---|
| ReadWriteOnce | RWO | 单节点读写(最常用) | 云磁盘(EBS/PD)、本地磁盘 |
| ReadOnlyMany | ROX | 多节点只读 | NFS、CephFS |
| ReadWriteMany | RWX | 多节点读写(最灵活,但支持后端少) | NFS、CephFS、Azure Files |
| ReadWriteOncePod | RWOP | 单 Pod 读写(K8s 1.22+) | 支持 CSI 的存储后端 |
静态 Provisioning
管理员手动创建 PV,用户创建 PVC 申领。适合已有存储基础设施的场景。
# 第一步:管理员创建 PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv-01
spec:
capacity:
storage: 20Gi # PV 总容量
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain # Retain/Recycle/Delete
storageClassName: manual # 与 PVC 的 storageClassName 匹配
nfs: # NFS 后端配置
server: 192.168.1.200
path: /data/k8s/pv01
---
# 第二步:用户创建 PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
namespace: default
spec:
accessModes:
- ReadWriteMany
storageClassName: manual # 匹配 PV 的 storageClassName
resources:
requests:
storage: 5Gi # 申请 5Gi,会绑定到 20Gi 的 PV
动态 Provisioning 与 StorageClass
无需提前创建 PV,用户创建 PVC 时 StorageClass 自动创建 PV。这是云原生环境的标准方式。
# StorageClass:定义动态创建 PV 的规则
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
annotations:
storageclass.kubernetes.io/is-default-class: "true" # 设为默认 SC
provisioner: ebs.csi.aws.com # AWS EBS CSI 驱动
parameters: # 传给 Provisioner 的参数
type: gp3 # EBS 卷类型(gp3/io2/sc1...)
iops: "3000"
throughput: "125" # MB/s 吞吐量
encrypted: "true" # 启用加密
reclaimPolicy: Delete # PVC 删除时自动删除 PV 和云磁盘
allowVolumeExpansion: true # 允许扩容 PVC
volumeBindingMode: WaitForFirstConsumer # 等 Pod 调度后再创建 PV(感知可用区)
---
# 用户只需创建 PVC,PV 自动创建
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-data
spec:
accessModes:
- ReadWriteOnce
storageClassName: fast-ssd # 引用上面的 StorageClass
resources:
requests:
storage: 50Gi
Retain(回收策略)
PVC 删除后,PV 和数据保留(变为 Released 状态)。需管理员手动清理后才能再次使用。适合重要数据,防止误删。
Delete(回收策略)
PVC 删除时自动删除 PV 及底层存储资源(如删除 EBS 卷)。动态 Provisioning 的默认策略,适合临时数据。
WaitForFirstConsumer
延迟绑定模式。等到第一个使用该 PVC 的 Pod 被调度后,才在 Pod 所在可用区创建 PV。避免跨可用区挂载(网络存储除外)。
CSI
Container Storage Interface。K8s 存储插件标准接口,使存储厂商(AWS/GCP/Ceph/NetApp)能独立开发存储驱动,无需修改 K8s 核心代码。
在 Pod 中使用 PVC
apiVersion: v1
kind: Pod
metadata:
name: mysql-pod
spec:
containers:
- name: mysql
image: mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: root-password
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql # MySQL 数据目录
volumes:
- name: mysql-data
persistentVolumeClaim:
claimName: app-data # 引用之前创建的 PVC
PVC 扩容
# 编辑 PVC,增加 storage 大小(StorageClass 需开启 allowVolumeExpansion: true)
kubectl patch pvc app-data -p '{"spec":{"resources":{"requests":{"storage":"100Gi"}}}}'
# 查看扩容状态
kubectl describe pvc app-data
# 观察 Conditions 字段,FileSystemResizePending 表示等待 Pod 重启完成文件系统扩容
PVC 只能扩容,不能缩容
Kubernetes 不支持缩小 PVC(降低 storage 大小)。如果需要缩容,必须创建新 PVC,迁移数据,再删除旧 PVC。
常见 Volume 类型速查
| Volume 类型 | 适用场景 | 数据持久性 |
|---|---|---|
emptyDir | 容器间共享临时数据、缓存 | Pod 删除即丢失 |
hostPath | 访问节点文件(日志、设备) | 节点本地持久 |
configMap | 挂载配置文件 | 非持久,来自 API |
secret | 挂载敏感信息 | 非持久,来自 API |
persistentVolumeClaim | 生产数据库、文件存储 | 持久(独立于 Pod) |
nfs | 多 Pod 共享文件(ReadWriteMany) | 持久 |
projected | 合并多个 Volume 到同一目录 | 取决于来源 |
不要在生产中使用 hostPath
hostPath 将容器与特定节点耦合,Pod 迁移到其他节点后数据丢失。且 hostPath 会让容器有潜在的逃逸到宿主机的风险。生产环境请始终使用 PVC。