背景与问题界定

某在线教育平台的实时录制系统需要在 Kubernetes 上运行——录制器 Pod 必须将音视频切片直接写入持久化存储,同时后端的转码 Worker 要读取这些文件进行 HLS 格式转换。起初团队采用了 StatefulSet 配 emptyDir 的方案,结果 Pod 因节点故障重建后所有录制数据丢失,用户端出现大面积的"回放缺失"投诉。更麻烦的是,跨 AZ 部署时,一个 AZ 中写入的 PV 无法被另一个 AZ 的 Pod 挂载,导致转码系统只能在本地读取而无法负载均衡。Kubernetes 的存储体系从 ephemeral 到持久化、从静态绑定到动态供给、从本地磁盘到分布式存储,是一套分层和扩展性极强的设计,但每个阶梯都有不同的故障模型和性能特征。

目标拆解与工程约束

  1. 存储生命周期与 Pod 生命周期解耦:Pod 重建后必须能自动挂载到之前写入数据的存储卷,保证有状态服务的"状态"不随 Pod 死亡而消失,同时支持 StatefulSet 的 volumeClaimTemplate 自动创建和绑定 PVC。
  2. 跨可用区访问与快照:存储后端必须支持跨 AZ 的 ReadWriteMany(RWX)访问模式——视频文件在一个 AZ 写入后需要被其他 AZ 的 Worker 立即读取,同时支持 CSI Snapshot 机制进行小时级定期快照防止数据损坏。
  3. 性能 Predictability:不同业务对存储 IOPS 和 Throughput 的要求差异极大——MySQL 需要低延迟(< 1ms)的块存储,日志系统需要高吞吐的顺序写,AI 训练则需要大带宽的并行文件系统。存储类(StorageClass)必须提供明确的性能分层。
  4. 存储成本可视化管理:无限制的 PVC 动态供给可能导致存储成本失控,需要利用 ResourceQuotaLimitRange 限制 namespace 级别的存储请求上限,同时通过标签追踪每块 PV 的归属项目。

方案设计

我们设计了四层存储性能分层模型,通过 StorageClass 的参数差异实现不同性能级别的选择:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-ssd
provisioner: ebs.csi.aws.com
parameters:
  type: gp3
  iops: "16000"
  throughput: "1000"
  fsType: ext4
reclaimPolicy: Retain
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer

性能分层:fast-ssd(16000 IOPS,用于数据库)、standard-hdd(通用型,用于日志和附件存储)、archive-cold(成本优先,用于备份归档)。关键设计是 volumeBindingMode: WaitForFirstConsumer——延迟绑定策略保证 Pod 被调度到某节点后,存储卷才在 Pod 所在的可用区创建,避免跨 AZ 绑定导致的性能问题。

对于 CSI 快照,我们配置了周期性的 VolumeSnapshotClass,配合 Velero 实现应用的备份恢复。实时录制系统采用 Local PV + 远端对象存储的双写策略:视频切片首先写入本地 NVMe SSD(local.csi.hostpath)保证低延迟录制,同时通过 Sidecar 容器异步上传到 S3 兼容对象存储,实现"本地快速写入、远端可靠持久化"。

RWX 场景使用 NFS CSI Driver 或 Amazon EFS CSI Driver,但需要注意性能限制——EFS 单文件系统的 IOPS 上限取决于文件大小,小文件场景性能远低于 EBS。我们利用 ReadWriteOncePod(K8s 1.22+ alpha)作为新特性来替代某些场景下的 RWX,让 PV 只能被单个 Pod 挂载但可以在 Pod 重建时保留数据。权限管理方面,通过 Pod Security Context 的 fsGroupsupplementalGroups 确保容器进程对挂载卷的读写权限正确。

实施路径与关键决策

  • 第一步:建立存储类标准化清单——统一命名规则(ssd-premiumhdd-standardarchive-cold),清理历史遗留的未通过 StorageClass 创建的 PV,要求新服务必须显式指定 StorageClass 名称。
  • 第二步:部署 CSI Driver——根据底层基础设施选择对应的 CSI 提供者(公有云用云厂商 CSI,自建用 Rook/Ceph CSI 或 Longhorn),配置 Driver 的 Controller 和 Node 组件,验证 VolumeAttachment 的生命周期管理。
  • 第三步:配置 Velero 备份策略——每个 namespace 自动创建 VolumeSnapshotClass,关键数据库每天全量快照 + 每 6 小时增量快照,快照保留 30 天,备份数据写入 S3 并提供跨 Region 复制。
  • 第四步:存储成本优化——配置 kube-costkubecost 的成本分摊数据,将 PV 的 Provisioned IOPS 和存储容量以项目标签分摊到业务团队,每月生成存储成本报表。

验证指标与可持续迭代

存储体系建设的关键指标:PVC 状态为 Pending 的时间占比 < 0.1%(排除不正常的 StorageClass);PV 回收后残留 EBS 卷的比例 < 1%;数据库快照恢复时间 < 30 分钟;存储利用率(已分配 vs. 实际使用)不低于 60%。每季度的存储审计检查未绑定的 PVC 和 orphan PV,通过 Label selector 查找未被任何 Pod 引用的 PV 并回收 Released 状态的资源。

工程落地思考

Kubernetes 存储体系最容易被低估的是"性能一致性"问题。同一个 StorageClass(比如 gp3),在不同的可用区、不同时间点创建的卷性能波动可能达到 30%。有状态服务必须通过 volumeAttributesClassName 或 CSI 的参数模板明确声明性能需求。另外,Local PV 虽然性能优异但管理困难——节点故障数据丢失问题可以用 OpenEBS 的 Mayastor 或 Longhorn 的 replica 机制缓解。存储选择本质上是在"性能、可用性和成本"之间做三角权衡,Kubernetes 的 StorageClass 和 CSI 提供了这个三角权衡的标准化框架,但具体的填值需要基于业务特征做 benchmark 测试。