跳转至

存储与 CSI

容器根文件系统随 Pod 重建而变化。日志缓存等临时数据可以跟随 Pod 消失,数据库文件、上传附件和队列数据则需要持久存储。Kubernetes 把“应用需要多大的卷”与“底层由 NFS、Ceph、云盘还是本地盘提供”分离开。

使用 RBD CSI 或 CephFS CSI 前,应先理解底层 Pool、PG、CRUSH 和故障域,参见 Ceph

Ceph CSI 的部署方式、Controller/Node Plugin 架构以及 PVC 完整挂载流程参见 Rook、Ceph 与 Kubernetes CSI

对象关系

Pod / StatefulSet
  → PVC:应用提出容量、访问模式等要求
  → StorageClass:选择存储类型和动态制备参数
  → CSI Driver:调用实际存储系统创建、挂载、扩容卷
  → PV:集群中已制备的持久卷
对象 作用 运维关注点
Volume Pod 内可挂载的卷定义 生命周期由卷类型决定
PV 集群级持久卷资源 容量、访问模式、回收策略、后端标识
PVC Namespace 内的存储申请 是否 Bound、使用哪个 StorageClass
StorageClass 动态制备模板 CSI provisioner、参数、绑定和回收策略
CSI Kubernetes 与存储系统的标准接口 控制器、节点插件及其日志

emptyDir 适合临时文件和容器间共享,Pod 被删除后数据消失。configMapsecretprojected 卷用于配置,不是业务数据盘。hostPath 绑定节点目录,Pod 漂移后无法保证数据仍可用,生产业务应谨慎使用。

动态申请持久卷

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: app-data
  namespace: app
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: fast-block
  resources:
    requests:
      storage: 20Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
  namespace: app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: app
  template:
    metadata:
      labels:
        app: app
    spec:
      containers:
        - name: app
          image: registry.example.com/app:1.0.0
          volumeMounts:
            - name: data
              mountPath: /data
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: app-data

PVC 只有处于 Bound 后,Pod 才能正常挂载。ReadWriteOnce 表示卷可被一个节点读写,不等于只能被一个 Pod 使用;底层存储是否支持跨节点、多写,必须看 CSI 驱动和存储产品能力。

StorageClass 的关键策略

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-block
provisioner: csi.example.com
reclaimPolicy: Retain
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer
  • reclaimPolicy: Delete:PVC 删除后通常连同后端卷删除,适合可重建数据,但风险高。
  • reclaimPolicy: Retain:保留 PV 和后端数据,需人工清理或重新绑定。
  • WaitForFirstConsumer:等 Pod 调度时再按可用区/节点拓扑制备卷,避免卷建在错误故障域。
  • allowVolumeExpansion:允许扩 PVC;文件系统是否在线扩容仍取决于驱动和卷类型。

StatefulSet 与独立数据卷

有状态副本通常需要稳定名称和每副本独立 PVC:

volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: ["ReadWriteOnce"]
      storageClassName: fast-block
      resources:
        requests:
          storage: 50Gi

生成的 PVC 类似 data-mysql-0data-mysql-1。缩容或删除 StatefulSet 通常不会自动删除这些 PVC,这是为了保护数据,也意味着扩缩容和清理前必须核对卷归属。

扩容、快照与备份

扩容先修改 PVC 请求容量,再观察 PVC、PV 和文件系统状态:

kubectl patch pvc app-data -n app \
  -p '{"spec":{"resources":{"requests":{"storage":"40Gi"}}}}'
kubectl get pvc,pv -n app
kubectl describe pvc app-data -n app

VolumeSnapshot 依赖 CSI 快照能力和快照控制器。快照不天然等于应用一致性备份:数据库仍需配合停写、日志归档或数据库原生备份。生产恢复方案至少要明确备份对象、异地保存、保留周期、RPO/RTO 和定期恢复演练。

排障顺序

kubectl get storageclass
kubectl get pvc -A
kubectl describe pvc app-data -n app
kubectl get pv
kubectl describe pod <pod> -n app
kubectl get events -n app --sort-by=.lastTimestamp
kubectl get pods -A | grep -i csi
现象 重点检查
PVC 一直 Pending StorageClass 名称、provisioner、容量/访问模式、CSI 控制器事件、拓扑限制
Pod Pending PVC 未 Bound,或 WaitForFirstConsumer 与调度条件互相限制
FailedMount/Attach CSI 节点插件、卷是否仍挂在旧节点、节点网络和权限
挂载成功但无法写 容器用户、fsGroup、目录权限、只读挂载、存储端 ACL
扩容无变化 StorageClass 是否允许扩容、驱动能力、PVC condition、文件系统扩容状态
节点故障后卷无法迁移 后端存储可达性、VolumeAttachment、故障域和强制解绑风险

不要为了解决挂载失败直接删除 PVC/PV。先记录 PV 的后端卷标识、回收策略和备份状态,再决定解绑或重建。

官方参考:Persistent VolumesCSI