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 是反向操作。流程涉及控制面与节点侧协作:

  1. kubelet 触发: Pod 调度到节点后,kubelet 的 VolumeManager 检查卷是否已 Attach。
  2. VolumeAttachment 对象创建: kubelet 或 AttachDetachController 创建 VolumeAttachment CRD 对象,标记节点与卷关系。
  3. external-attacher 响应: 监听 VolumeAttachment,调用 CSI 驱动的 ControllerPublishVolume RPC。
  4. CSI 驱动执行: 调用存储后端 API 将卷挂载到节点(如 EC2 AttachVolume)。
  5. 状态确认: 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 驱动与存储后端之间的交互关系:

K8s 存储组件全景拓扑 控制面 (Control Plane) kube-controller-manager external-provisioner external-attacher PV/PVC Controller 节点 (Node) kubelet node-driver-registrar CSI 驱动 VolumeManager 存储后端 AWS EBS / GCE PD / Ceph RBD NFS / vSphere / Azure Disk 图例: 控制面组件 节点组件 CSI 驱动 存储后端 gRPC / API 调用 控制面直连后端

3.6 Attach / Detach 与 Mount / Unmount 流程时序

下图展示从 Pod 创建到卷就绪的完整时序,突出 Attach 与 Mount 两个阶段的衔接:

Attach / Detach 与 Mount / Unmount 流程时序 时间 ① Pod 创建 → kubelet 检测到需要挂载卷 ② Attach 阶段:VolumeAttachment 创建 → external-attacher → ControllerPublishVolume ③ Stage 阶段:NodeStageVolume → 格式化 → 全局挂载 ④ Publish 阶段:NodePublishVolume → bind mount → Pod 容器路径就绪 ⑤ Pod 运行中 → 卷可读写 → Unmount/Detach 在 Pod 删除时逆向执行
面板化切入点: 在 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 做交叉验证。