Kubernetes 存储机制概述

Kubernetes 存储机制概述

存储架构全景

Kubernetes 存储系统经过多年演进,形成了完善的存储抽象层次。

存储架构层次

┌─────────────────────────────────────────────────────────┐
│                    应用层 (Pod)                          │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐   │
│  │ Volume  │  │ConfigMap│  │ Secret  │  │EmptyDir │   │
│  └────┬────┘  └────┬────┘  └────┬────┘  └────┬────┘   │
└───────┼───────────┼──────────────┼───────────┼─────────┘
        │           │              │           │
┌───────▼───────────▼──────────────▼───────────▼─────────┐
│              Kubernetes 存储抽象层                       │
│  ┌──────────────────────────────────────────────────┐  │
│  │  PersistentVolumeClaim (PVC) - 用户存储请求      │  │
│  └────────────────────┬─────────────────────────────┘  │
│                       │                                 │
│  ┌────────────────────▼─────────────────────────────┐  │
│  │  PersistentVolume (PV) - 存储资源实例            │  │
│  └────────────────────┬─────────────────────────────┘  │
│                       │                                 │
│  ┌────────────────────▼─────────────────────────────┐  │
│  │  StorageClass - 动态存储配置                     │  │
│  └────────────────────┬─────────────────────────────┘  │
└───────────────────────┼─────────────────────────────────┘
                        │
┌───────────────────────▼─────────────────────────────────┐
│               存储插件层 (Provisioner)                   │
│  ┌──────────────────────────────────────────────────┐  │
│  │  In-Tree Plugins (内置插件,逐步废弃)            │  │
│  │  - AWS EBS, GCE PD, Azure Disk                   │  │
│  └──────────────────────────────────────────────────┘  │
│  ┌──────────────────────────────────────────────────┐  │
│  │  FlexVolume (旧方案,已废弃)                     │  │
│  └──────────────────────────────────────────────────┘  │
│  ┌──────────────────────────────────────────────────┐  │
│  │  CSI (Container Storage Interface) - 推荐        │  │
│  │  - Controller Plugin (Deployment)                │  │
│  │  - Node Plugin (DaemonSet)                       │  │
│  └────────────────────┬─────────────────────────────┘  │
└───────────────────────┼─────────────────────────────────┘
                        │
┌───────────────────────▼─────────────────────────────────┐
│                  存储后端 (Backend)                      │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌────────┐ │
│  │ 块存储   │  │ 文件存储 │  │ 对象存储 │  │本地存储│ │
│  │ AWS EBS  │  │   NFS    │  │   S3     │  │HostPath│ │
│  │ Ceph RBD │  │ CephFS   │  │  MinIO   │  │LocalPV │ │
│  │ iSCSI    │  │  GlusterFS│  │         │  │        │ │
│  └──────────┘  └──────────┘  └──────────┘  └────────┘ │
└─────────────────────────────────────────────────────────┘

核心概念

1. Volume(卷)

Volume 是 Pod 中容器可访问的目录,生命周期与 Pod 绑定。

临时卷类型

  • emptyDir: 空目录,Pod 删除即清空
  • configMap: 配置文件挂载
  • secret: 敏感信息挂载
  • downwardAPI: 暴露 Pod 元数据

持久化卷类型

  • persistentVolumeClaim: 使用 PVC 引用
  • hostPath: 宿主机目录(仅用于测试)
  • local: 本地持久化存储

网络卷类型

  • nfs: NFS 网络文件系统
  • cephfs: Ceph 文件系统
  • iscsi: iSCSI 块存储

2. PersistentVolume (PV)

PV 是集群级别的存储资源,由管理员创建或通过 StorageClass 动态创建。

关键属性

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-example
spec:
  capacity:
    storage: 10Gi              # 容量
  accessModes:                  # 访问模式
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain  # 回收策略
  storageClassName: standard    # 存储类
  mountOptions:                 # 挂载选项
    - hard
    - nfsvers=4.1
  # 存储后端配置
  nfs:
    server: nfs-server.example.com
    path: /exported/path

3. PersistentVolumeClaim (PVC)

PVC 是用户对存储的请求,描述需要的容量和访问模式。

关键属性

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-example
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: standard
  resources:
    requests:
      storage: 5Gi
  # 可选:选择器
  selector:
    matchLabels:
      release: stable

4. StorageClass

StorageClass 定义动态存储的配置模板。

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-storage
provisioner: kubernetes.io/aws-ebs  # 存储提供者
parameters:                          # 参数
  type: gp3
  iops: "3000"
  encrypted: "true"
volumeBindingMode: WaitForFirstConsumer  # 延迟绑定
allowVolumeExpansion: true           # 允许扩容
reclaimPolicy: Delete                # 回收策略
mountOptions:                        # 挂载选项
  - debug

存储访问模式

Kubernetes 定义了三种访问模式:

访问模式 简写 说明 使用场景
ReadWriteOnce RWO 单节点读写 数据库、有状态应用
ReadOnlyMany ROX 多节点只读 共享配置、静态资源
ReadWriteMany RWX 多节点读写 共享存储、集群文件系统
ReadWriteOncePod RWOP 单 Pod 读写(1.22+) 独占访问

存储类型支持矩阵

存储类型 RWO ROX RWX
AWS EBS
GCE PD
Azure Disk
NFS
CephFS
GlusterFS
Local

PV 生命周期

┌─────────────┐
│   Available │  ← 新创建的 PV,可被绑定
└──────┬──────┘
       │ PVC 请求绑定
       ▼
┌─────────────┐
│    Bound    │  ← PV 已绑定到 PVC
└──────┬──────┘
       │ PVC 删除
       ▼
┌─────────────┐
│  Released   │  ← PV 已释放,但未清理
└──────┬──────┘
       │ 根据回收策略处理
       ▼
┌─────────────┐  Retain 策略
│   Available │ ←────────────┐
└─────────────┘               │
                              │
       ┌──────────────────────┤
       │ Delete 策略          │
       ▼                      │
┌─────────────┐               │
│   Deleted   │  删除 PV      │
└─────────────┘               │
                              │
       ┌──────────────────────┘
       │ Recycle 策略(已废弃)
       ▼
┌─────────────┐
│   Available │  清理后重新可用
└─────────────┘

回收策略详解

1. Retain(保留)

  • PVC 删除后,PV 变为 Released 状态
  • 数据仍然存在
  • 需要管理员手动清理和重新创建 PV
  • 适用于重要数据

2. Delete(删除)

  • PVC 删除后,自动删除 PV 和底层存储
  • 数据完全丢失
  • 大多数动态存储的默认策略
  • 适用于临时数据

3. Recycle(回收,已废弃)

  • 执行基本清理(rm -rf)
  • PV 重新变为 Available
  • 不推荐使用,使用动态存储替代

存储绑定流程

静态供给流程

1. 管理员创建 PV
   └─> kubectl apply -f pv.yaml

2. 用户创建 PVC
   └─> kubectl apply -f pvc.yaml

3. Kubernetes 匹配绑定
   ├─> 匹配 StorageClass
   ├─> 匹配 AccessModes
   ├─> 匹配容量(PV >= PVC)
   ├─> 匹配标签选择器
   └─> 绑定成功

4. Pod 使用 PVC
   └─> Pod spec.volumes 引用 PVC

动态供给流程

1. 管理员创建 StorageClass
   └─> kubectl apply -f storageclass.yaml

2. 用户创建 PVC(指定 StorageClass)
   └─> kubectl apply -f pvc.yaml

3. PV Controller 检测到 PVC
   └─> 调用 Provisioner

4. Provisioner 创建存储
   ├─> 调用存储后端 API
   ├─> 创建卷(EBS、Ceph RBD 等)
   └─> 创建 PV 对象

5. PV Controller 绑定 PVC 和 PV
   └─> PVC.status.phase = Bound

6. Pod 使用 PVC
   └─> Kubelet 挂载卷到 Pod

卷挂载流程

Attach 和 Mount 两阶段

┌──────────────────────────────────────────────────────┐
│ Phase 1: Attach (控制器层面,仅块存储)                │
└──────────────────────────────────────────────────────┘
                        │
                        ▼
┌────────────────────────────────────────────────┐
│  AttachDetach Controller (运行在 Master 节点)  │
│  ├─> 检测 Pod 调度到节点                       │
│  ├─> 调用云提供商 API                          │
│  └─> 将卷挂载到节点(如 AWS EBS attach)       │
└────────────────────────────────────────────────┘
                        │
                        ▼
              ┌──────────────────┐
              │ VolumeAttachment │  Kubernetes 对象
              │   (记录挂载状态)  │
              └──────────────────┘

┌──────────────────────────────────────────────────────┐
│ Phase 2: Mount (节点层面)                             │
└──────────────────────────────────────────────────────┘
                        │
                        ▼
┌────────────────────────────────────────────────┐
│  Kubelet Volume Manager (运行在工作节点)       │
│  ├─> 等待 Attach 完成                          │
│  ├─> 格式化设备(如果需要)                    │
│  ├─> 挂载到全局目录 (Stage)                    │
│  │   /var/lib/kubelet/plugins/.../globalmount  │
│  └─> Bind Mount 到 Pod 目录 (Publish)          │
│      /var/lib/kubelet/pods/<pod-id>/volumes/   │
└────────────────────────────────────────────────┘

详细挂载步骤

块存储(如 AWS EBS)

# 1. Attach: 将 EBS 卷挂载到 EC2 实例
aws ec2 attach-volume --volume-id vol-xxx --instance-id i-xxx
# 结果:/dev/xvdf 设备出现

# 2. Format: 格式化(首次)
mkfs.ext4 /dev/xvdf

# 3. Stage: 挂载到全局目录
mount /dev/xvdf /var/lib/kubelet/plugins/kubernetes.io/aws-ebs/mounts/vol-xxx

# 4. Publish: Bind mount 到 Pod 目录
mount --bind /var/lib/kubelet/plugins/.../vol-xxx \
  /var/lib/kubelet/pods/<pod-id>/volumes/kubernetes.io~aws-ebs/pvc-xxx

文件存储(如 NFS)

# 无需 Attach 阶段

# 直接 Mount 到 Pod 目录
mount -t nfs nfs-server:/path \
  /var/lib/kubelet/pods/<pod-id>/volumes/kubernetes.io~nfs/pvc-xxx

存储扩容机制

Kubernetes 支持在线扩容持久卷(需要 CSI 驱动支持)。

扩容流程

1. 用户修改 PVC 容量
   └─> kubectl edit pvc my-pvc
       spec.resources.requests.storage: 10Gi → 20Gi

2. PVC 进入 Resizing 状态
   └─> conditions:
       - type: Resizing
         status: "True"

3. External Resizer 扩容控制器卷
   ├─> 调用 CSI ControllerExpandVolume
   └─> 在存储后端扩容(如调整 EBS 大小)

4. Kubelet 扩容文件系统
   ├─> 调用 CSI NodeExpandVolume
   ├─> 执行 resize2fs(ext4)
   └─> 或 xfs_growfs(xfs)

5. PVC 容量更新
   └─> status.capacity.storage: 20Gi
       conditions:
       - type: FileSystemResizePending
         status: "False"

支持扩容的存储

存储类型 控制器扩容 文件系统扩容 是否需要重启 Pod
AWS EBS
GCE PD
Azure Disk
Ceph RBD
NFS N/A

存储快照

Kubernetes 1.20+ 支持卷快照(VolumeSnapshot)。

快照架构

# 1. VolumeSnapshotClass(快照类)
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
  name: csi-snapclass
driver: ebs.csi.aws.com
deletionPolicy: Delete

---
# 2. VolumeSnapshot(快照对象)
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: my-snapshot
spec:
  volumeSnapshotClassName: csi-snapclass
  source:
    persistentVolumeClaimName: my-pvc

---
# 3. 从快照恢复 PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: restored-pvc
spec:
  dataSource:
    name: my-snapshot
    kind: VolumeSnapshot
    apiGroup: snapshot.storage.k8s.io
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi

存储性能考虑

IOPS 和吞吐量

不同存储类型的性能特征:

存储类型 IOPS 吞吐量 延迟 适用场景
本地 SSD 10K-100K+ 500MB/s+ <1ms 数据库、高性能计算
云块存储 (SSD) 3K-16K 250MB/s 1-5ms 通用持久化
云块存储 (HDD) 100-500 40-90MB/s 5-10ms 冷数据
NFS 1K-10K 100MB/s 5-20ms 共享文件
对象存储 100-1K 50-100MB/s 50-100ms 归档、备份

性能优化建议

1. 选择合适的存储类型

# 高性能数据库
storageClassName: fast-ssd

# 日志归档
storageClassName: slow-hdd

2. 使用本地存储

# LocalPV 提供最佳性能
kind: StorageClass
metadata:
  name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

3. 调整挂载选项

mountOptions:
  - noatime        # 不更新访问时间
  - nodiratime     # 不更新目录访问时间
  - discard        # 支持 TRIM

4. 使用拓扑感知

# 确保 PV 和 Pod 在同一可用区
volumeBindingMode: WaitForFirstConsumer
allowedTopologies:
- matchLabelExpressions:
  - key: topology.kubernetes.io/zone
    values:
    - us-east-1a

存储监控

关键指标

# PV 使用情况
kubectl get pv
kubectl describe pv <pv-name>

# PVC 使用情况
kubectl get pvc --all-namespaces
kubectl describe pvc <pvc-name>

# 存储容量
kubectl get sc
kubectl top pv  # 需要 metrics-server

Prometheus 监控指标

# PV 总数
count(kube_persistentvolume_info)

# PVC 绑定状态
kube_persistentvolumeclaim_status_phase{phase="Bound"}

# 存储容量使用率
(kubelet_volume_stats_used_bytes / 
 kubelet_volume_stats_capacity_bytes) * 100

# 存储 IOPS
rate(kubelet_volume_stats_iops[5m])

故障排查

常见问题

1. PVC 一直 Pending

# 检查 PVC 状态
kubectl describe pvc <pvc-name>

# 常见原因:
# - 没有匹配的 PV
# - StorageClass 不存在
# - 容量不足
# - AccessMode 不匹配

# 查看事件
kubectl get events --field-selector involvedObject.name=<pvc-name>

2. Pod 无法挂载卷

# 检查 Pod 状态
kubectl describe pod <pod-name>

# 常见原因:
# - PVC 未绑定
# - 节点无法访问存储后端
# - 权限问题
# - 卷已被其他 Pod 独占使用

# 查看节点日志
journalctl -u kubelet -f

3. 卷扩容失败

# 检查 PVC 状态
kubectl describe pvc <pvc-name>

# 检查 StorageClass 是否允许扩容
kubectl get sc <sc-name> -o yaml | grep allowVolumeExpansion

# 检查 CSI 驱动是否支持扩容
kubectl get csidrivers

最佳实践

1. 使用动态存储

# ✅ 推荐:使用 StorageClass 动态创建
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: dynamic-pvc
spec:
  storageClassName: standard
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi

# ❌ 不推荐:手动创建 PV(除非必要)

2. 设置资源配额

apiVersion: v1
kind: ResourceQuota
metadata:
  name: storage-quota
  namespace: dev
spec:
  hard:
    requests.storage: "100Gi"
    persistentvolumeclaims: "10"

3. 使用 PVC 保护

# 防止 PVC 被误删
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: protected-pvc
  finalizers:
  - kubernetes.io/pvc-protection
spec:
  # ...

4. 备份重要数据

# 使用 Velero 备份
velero backup create my-backup --include-namespaces=production

# 使用卷快照
kubectl apply -f volumesnapshot.yaml

5. 监控存储使用

# 配置告警规则
- alert: PVCAlmostFull
  expr: |
    (kubelet_volume_stats_used_bytes / 
     kubelet_volume_stats_capacity_bytes) > 0.9
  annotations:
    summary: "PVC {{ $labels.persistentvolumeclaim }} 使用率超过 90%"

总结

Kubernetes 存储系统提供了:

  • 灵活的抽象层:Volume、PV、PVC、StorageClass
  • 多样的存储类型:块存储、文件存储、对象存储
  • 动态供给:自动创建和管理存储
  • 标准接口:CSI 插件系统
  • 高级特性:扩容、快照、克隆

理解存储机制是运维 Kubernetes 的关键技能之一。