3. K8s 存储组件全景:CSI 驱动、PV/PVC/StorageClass、Attach/Detach、Mount/Unmount 流程
Kubernetes 存储体系是集群有状态工作负载的基石。理解 CSI 驱动、PV/PVC/StorageClass 抽象层以及 Attach/Detach、Mount/Unmount 的完整生命周期,是构建存储 SLO 与错误预算面板的前提。本章从组件拓扑与核心流程两个维度展开全景分析。
3.1 存储组件拓扑与职责划分
K8s 存储体系由控制面组件、节点代理、外部存储插件三层构成。下表列出核心组件及其职责:
| 层级 | 组件 | 核心职责 | 关键指标 |
|---|---|---|---|
| 控制面 | kube-controller-manager (AttachDetachController / PVController) | PV/PVC 绑定、回收策略执行、Attach/Detach 调度 | volume_operation_total_seconds / pv_claim_binding_duration |
| 控制面 | external-provisioner (CSI sidecar) | 监听 PVC 创建,调用 CSI CreateVolume | csi_sidecar_operations_duration_seconds |
| 控制面 | external-attacher (CSI sidecar) | 监听 VolumeAttachment,调用 CSI ControllerPublishVolume | csi_sidecar_operations_duration_seconds |
| 节点 | kubelet (VolumeManager / PluginManager) | Pod 启动时执行 Mount/Unmount,管理节点级卷状态 | kubelet_volume_stats_available_bytes / kubelet_volume_stats_used_bytes |
| 节点 | node-driver-registrar (CSI sidecar) | 向 kubelet 注册 CSI 驱动 socket | csi_sidecar_operations_duration_seconds |
| 节点 | CSI 驱动 (DaemonSet) | 实际执行 NodeStageVolume / NodePublishVolume | csi_operations_seconds / csi_errors_total |
| 外部 | 存储后端 (AWS EBS / GCE PD / Ceph RBD 等) | 提供块存储或文件存储能力 | 后端延迟 / 吞吐 / 错误率 |
SRE 观察点: CSI sidecar 与 kubelet 之间的 gRPC 通信超时、CSI 驱动 Pod 重启次数、VolumeAttachment 对象 stuck 状态,是存储故障的三大前兆信号。
3.2 PV / PVC / StorageClass 抽象关系
StorageClass 定义了动态制备的模板(provisioner、参数、回收策略);PVC 是用户对存储的请求;PV 是集群中的存储资源。三者通过以下规则绑定:
- 动态制备: PVC 引用 StorageClass → external-provisioner 调用 CSI CreateVolume → 创建 PV 并绑定。
- 静态绑定: 管理员预先创建 PV,PVC 通过 label selector 或容量匹配绑定。
- 回收策略: Delete(删除 PV 与后端卷)、Retain(保留卷需手动清理)、Recycle(已弃用)。
# 典型 StorageClass 定义(CSI 驱动示例)
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
provisioner: ebs.csi.aws.com
parameters:
type: gp3
iops: "3000"
throughput: "125"
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
面板化建议: 在 Grafana 中建立
pv_claim_status 面板,按 StorageClass 分组展示 Pending / Bound / Lost 状态的 PVC 数量,快速发现制备瓶颈。
3.3 Attach / Detach 流程详解
Attach 是将存储卷挂载到节点使其成为块设备的过程,Detach 是反向操作。流程涉及控制面与节点侧协作:
- kubelet 触发: Pod 调度到节点后,kubelet 的 VolumeManager 检查卷是否已 Attach。
- VolumeAttachment 对象创建: kubelet 或 AttachDetachController 创建
VolumeAttachmentCRD 对象,标记节点与卷关系。 - external-attacher 响应: 监听 VolumeAttachment,调用 CSI 驱动的
ControllerPublishVolumeRPC。 - CSI 驱动执行: 调用存储后端 API 将卷挂载到节点(如 EC2 AttachVolume)。
- 状态确认: external-attacher 更新 VolumeAttachment 状态为 Attached。
Detach 流程逆向执行:Pod 终止 → VolumeAttachment 标记删除 → external-attacher 调用 ControllerUnpublishVolume → 后端解挂。
常见故障: VolumeAttachment 卡在 Attached 状态但后端已解挂(残留对象);CSI 驱动版本与后端 API 不兼容导致 Attach 超时;节点故障导致 Detach 无法完成,影响卷迁移。
3.4 Mount / Unmount 流程详解
Mount 阶段将块设备格式化为文件系统并挂载到 Pod 可访问的路径。分为两个子阶段:
| 阶段 | CSI RPC | 执行者 | 操作 |
|---|---|---|---|
| Stage (全局挂载) | NodeStageVolume | CSI 驱动 (节点) | 格式化(如 mkfs.ext4)、挂载到全局路径(如 /var/lib/kubelet/plugins/kubernetes.io/csi/pv/<pv-name>/globalmount) |
| Publish (Pod 级挂载) | NodePublishVolume | CSI 驱动 (节点) | bind mount 全局路径到 Pod 容器路径(如 /var/lib/kubelet/pods/<pod-uid>/volumes/kubernetes.io~csi/<pv-name>/mount) |
Unmount 逆向执行:NodeUnpublishVolume(解除 bind mount)→ NodeUnstageVolume(卸载全局挂载)。
# kubelet 日志中 Mount 阶段的关键事件
I0115 10:23:45.123456 12345 operation_generator.go:123] MountVolume.SetUp succeeded for volume "pvc-abc123" (pod "nginx-0")
I0115 10:23:45.234567 12345 csi_mounter.go:456] "CSINodePublishVolume" called for volume "pvc-abc123"
I0115 10:23:45.345678 12345 csi_client.go:789] "GRPC call: NodePublishVolume" driver="ebs.csi.aws.com"
SRE 关键指标:
csi_operations_seconds{operation_type="NodePublishVolume"} 的 P99 延迟、kubelet_volume_stats_available_bytes 的磁盘使用率趋势、Mount 失败导致的 Pod 启动延迟。
3.5 存储组件全景拓扑图
下图展示控制面、节点、CSI 驱动与存储后端之间的交互关系:
3.6 Attach / Detach 与 Mount / Unmount 流程时序
下图展示从 Pod 创建到卷就绪的完整时序,突出 Attach 与 Mount 两个阶段的衔接:
面板化切入点: 在 Prometheus 中采集
csi_operations_seconds 按 operation_type 分桶,建立 Attach / Stage / Publish 各阶段的 P99 延迟面板;配合 volume_operation_total_seconds 监控控制面操作耗时,快速定位瓶颈在 Attach 还是 Mount 阶段。
3.7 关键 SLO 指标与错误预算关联
基于上述流程,定义以下存储 SLO 指标:
| SLO 指标 | 测量方式 | 典型目标 | 错误预算消耗条件 |
|---|---|---|---|
| 卷制备延迟 (Provisioning Latency) | PVC 创建到 PV Bound 的 P99 耗时 | < 30s | 单次 > 60s 或连续 3 次 > 45s |
| Attach 成功率 | VolumeAttachment 成功数 / 总数 (5m 窗口) | ≥ 99.9% | 任何 Attach 失败立即消耗 0.1% 预算 |
| Mount 成功率 | NodePublishVolume 成功数 / 总数 (5m 窗口) | ≥ 99.95% | 连续 2 次 Mount 失败消耗 0.05% 预算 |
| 卷可用性 (Volume Availability) | Pod 中卷就绪状态 / 期望状态 (1h 窗口) | ≥ 99.99% | 任何卷不可用事件消耗 0.01% 预算 |
避坑提示: 不要仅依赖 CSI 驱动自身指标。存储后端 API 限流、网络分区、kubelet 与 CSI 驱动之间的 Unix Socket 超时,都可能绕过 CSI 错误计数。建议在面板中叠加
kubelet_volume_stats_* 与 volume_operation_total_seconds 做交叉验证。