系列导航
本系列从 K8s 存储模型入手,逐步展开到 CSI 插件实现与云原生存储全景。
① 概念 → ② Volume 生命周期 → ③ CSI 架构 → ④ FlexVolume 演进 → ⑤ 对比 → ⑥ 排障 ‖ ⑦ 开发 → ⑧ 高级特性 → ⑨ 演进展望
重要
CSI 的高级特性(快照、克隆、扩容、拓扑感知)都建立在 CSI Spec v1.1+ 基础上,通过额外的 CRD 和 Sidecar 实现。这些特性使 K8s 存储具备生产级数据管理能力。
1. Volume Snapshot(卷快照)
1.1 概念
快照是 Volume 在某一时间点的只读副本,用于备份和恢复。
| CRD | 说明 |
|---|
VolumeSnapshotClass | 定义快照的参数(类似 StorageClass) |
VolumeSnapshot | 用户创建的快照请求 |
VolumeSnapshotContent | 实际快照资源(类似 PV) |
1.2 流程
创建 VolumeSnapshot(引用 VolumeSnapshotClass + PVC)
↓
external-snapshotter 监听 → 调 CSI CreateSnapshot
↓
CSI 插件在存储后端创建快照 → 返回 Snapshot ID
↓
external-snapshotter 创建 VolumeSnapshotContent
↓
快照 Ready,可用于恢复
1.3 使用示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| # 1. 创建快照
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: data-snapshot
spec:
volumeSnapshotClassName: csi-snapshot
source:
persistentVolumeClaimName: data-pvc
---
# 2. 从快照恢复
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: restored-pvc
spec:
storageClassName: fast
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 100Gi
dataSource:
name: data-snapshot
kind: VolumeSnapshot
apiGroup: snapshot.storage.k8s.io
|
2. Volume Clone(卷克隆)
2.1 概念
克隆是从现有 PVC 创建一个相同大小和内容的新 Volume。
| 维度 | 快照 | 克隆 |
|---|
| 依赖 | 需要 VolumeSnapshot CRD | 直接引用 PVC |
| 用途 | 定期备份 | 复制数据用于测试/分析 |
| 中间产物 | VolumeSnapshotContent | 无(直接创建新 PV) |
2.2 使用示例
1
2
3
4
5
6
7
8
9
10
11
12
13
| apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: cloned-pvc
spec:
storageClassName: fast
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 100Gi # 必须 ≥ 源 PVC
dataSource:
name: source-pvc # 源 PVC 名
kind: PersistentVolumeClaim
|
3. Volume Expansion(卷扩容)
3.1 两阶段扩容
| 阶段 | 执行者 | CSI 接口 | 说明 |
|---|
| ControllerExpand | external-resizer → CSI 插件 | ControllerExpandVolume | 扩容底层存储容量 |
| NodeExpand | kubelet → CSI 插件 | NodeExpandVolume | 扩容文件系统 |
3.2 使用方式
1
2
3
4
5
6
7
8
9
10
11
| # 修改 PVC 的 storage 请求即可触发扩容
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-pvc
spec:
storageClassName: fast # StorageClass 必须设置 allowVolumeExpansion: true
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 200Gi # 从 100Gi 扩到 200Gi
|
1
2
3
4
5
6
7
| # StorageClass 需要允许扩容
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast
provisioner: csi.example.com/volume
allowVolumeExpansion: true # 关键
|
扩容是"在线操作"——Pod 不需要重启。但只能扩容不能缩容。文件系统类型不同,NodeExpand 的行为不同:ext4/xfs 在线扩容,raw block 不需要文件系统扩容。
4. Topology(拓扑感知)
4.1 问题
某些存储系统(如云盘、Local PV)的 Volume 只能被特定节点访问。如果 Pod 被调度到没有对应 Volume 的节点,Attach 会失败。
4.2 解决方案
CSI 插件通过 GetPluginCapabilities 声明支持拓扑,然后:
- CSI 插件在
CreateVolume 时指定 AccessibilityRequirements(可访问拓扑) - K8s 调度器根据 CSI 插件声明的拓扑信息过滤节点
- 确保 Pod 调度到能访问该 Volume 的节点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
| // CSI 插件声明支持拓扑
func (d *Driver) GetPluginCapabilities(ctx context.Context, req *csi.GetPluginCapabilitiesRequest) (*csi.GetPluginCapabilitiesResponse, error) {
return &csi.GetPluginCapabilitiesResponse{
Capabilities: []*csi.PluginCapability{
{
Type: &csi.PluginCapability_Service_{
Service: &csi.PluginCapability_Service{
Type: csi.PluginCapability_Service_CONTROLLER_SERVICE,
},
},
},
{
Type: &csi.PluginCapability_VolumeExpansion_{
VolumeExpansion: &csi.PluginCapability_VolumeExpansion{
Type: csi.PluginCapability_VolumeExpansion_ONLINE,
},
},
},
},
}, nil
}
// NodeGetInfo 返回节点拓扑标签
func (d *Driver) NodeGetInfo(ctx context.Context, req *csi.NodeGetInfoRequest) (*csi.NodeGetInfoResponse, error) {
return &csi.NodeGetInfoResponse{
NodeId: d.nodeID,
AccessibleTopology: &csi.Topology{
Segments: map[string]string{
"topology.example.com/zone": "zone-1",
},
},
}, nil
}
|
4.3 常见拓扑维度
| 拓扑键 | 说明 | 典型场景 |
|---|
topology.kubernetes.io/zone | 可用区 | 云盘只能在本区 Attach |
topology.kubernetes.io/region | 地域 | 跨区存储延迟过高 |
topology.example.com/rack | 机架 | Ceph 集群按机架划分 |
5. 特性支持矩阵
| 特性 | CSI Spec | K8s 版本 | 依赖 CRD |
|---|
| 动态供应 | v0.3+ | 1.13+ | 无 |
| 拓扑感知 | v1.0+ | 1.14+ | 无 |
| 卷扩容 | v1.0+ | 1.16+ | 无 |
| 卷快照 | v1.0+ | 1.17+(GA) | VolumeSnapshot |
| 卷克隆 | v1.0+ | 1.18+(GA) | 无 |
参考链接