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 的关键技能之一。