Chapter 07

持久化存储:PV / PVC / StorageClass

掌握 K8s 存储三层抽象,理解静态与动态 Provisioning、CSI 驱动、以及有状态应用的存储配置。

存储架构:三层抽象

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。