当前位置: 首页 > news >正文

Kubernetes控制平面组件:Kubelet详解(八):容器存储接口 CSI

云原生学习路线导航页(持续更新中)

  • kubernetes学习系列快捷链接
    • Kubernetes架构原则和对象设计(一)
    • Kubernetes架构原则和对象设计(二)
    • Kubernetes架构原则和对象设计(三)
    • Kubernetes控制平面组件:etcd(一)
    • Kubernetes控制平面组件:etcd(二)
    • Kubernetes控制平面组件:API Server详解(一)
    • Kubernetes控制平面组件:API Server详解(二)
    • Kubernetes控制平面组件:调度器Scheduler(一)
    • Kubernetes控制平面组件:调度器Scheduler(二)
    • Kubernetes控制平面组件:Controller Manager 之 内置Controller详解
    • Kubernetes控制平面组件:Controller Manager 之 NamespaceController 全方位讲解
    • Kubernetes控制平面组件:Kubelet详解(一):架构 及 API接口层介绍
    • Kubernetes控制平面组件:Kubelet详解(二):核心功能层
    • Kubernetes控制平面组件:Kubelet详解(三):CRI 容器运行时接口层
    • Kubernetes控制平面组件:Kubelet详解(四):gRPC 与 CRI gRPC实现
    • Kubernetes控制平面组件:Kubelet详解(五):切换docker运行时为containerd
    • Kubernetes控制平面组件:Kubelet详解(六):pod sandbox(pause)容器
    • Kubernetes控制平面组件:Kubelet详解(七):容器网络接口 CNI
    • Kubernetes控制平面组件:Kubelet 之 Static 静态 Pod

本文是 kubernetes 的控制面组件 kubelet 系列文章第八篇,主要对 容器存储接口CSI 进行讲解,包括:容器运行时存储的局限性,kubernetes存储卷插件的类型,每种插件的原理、优缺点、适用场景等,并详细介绍了kubernetes支持的常用存储卷emptyDir、hostPath、pv、pvc、storageClass等,重点介绍了pv、pvc、storageClass设计和使用上的差异

  • 希望大家多多 点赞 关注 评论 收藏,作者会更有动力继续编写技术文章

1.容器运行时存储

在这里插入图片描述

  • 在学习docker时,我们在 Docker核心技术:Docker原理之Union文件系统 中学习了docker的文件系统,容器文件系统中,overlayFS已经成为事实标准,不二选择,所以基本也不怎么存在容器文件系统的选型问题。
  • 容器运行时存储(容器运行时的文件系统)是存储什么?
    • 存储镜像的层。尽量不要在容器运行时写数据,因为性能很差,一般就是用于把应用拉起来就好。日志也不要写在里面
  • 那么应用运行中产生的数据,怎么存储呢?
    • 使用容器的各种数据卷。下面就一一讲解。

2.kubernetes存储卷插件

在这里插入图片描述

  • kubernetes支持多种多样的存储卷,为了方便管理和扩展,kubernetes以插件方式支持。
  • 随着不断迭代演进,kubernetes存储卷插件可以分成3种类型:
    • in-tree插件
    • out-of-tree FlexVolume插件
    • out-of-tree CSI插件

2.1.In-Tree 存储插件

2.1.1.原理

  • 代码直接集成在Kubernetes核心组件(如kube-controller-manager、kubelet)中,与Kubernetes同进程运行。
  • 存储驱动(如NFS、iSCSI)通过Kubernetes原生API实现卷的生命周期管理。

2.1.2.优点

  • 开箱即用:无需额外部署组件,安装Kubernetes即支持。
  • 兼容性高:早期版本中功能稳定,与Kubernetes核心深度集成。

2.1.3.缺点

  • 强耦合性:存储驱动的更新需跟随Kubernetes版本发布周期,灵活性差。
  • 稳定性风险:插件崩溃可能导致Kubernetes核心组件异常。
  • 社区维护弱化:Kubernetes已停止接受新的in-tree插件,逐步迁移至CSI。

2.1.4.适用场景

  • 旧集群兼容性维护,或无需频繁更新的简单存储需求(如测试环境使用NFS)。

2.2.Out-of-Tree FlexVolume 插件

2.2.1.原理

  • 通过节点上的可执行文件(Shell/Python脚本)与存储驱动交互,由kubelet调用脚本实现卷操作(如挂载/卸载)。
  • 与 Kubernetes控制平面组件:Kubelet详解(七):容器网络接口 CNI 中讲的CNI插件的使用方式一样,在node的某个固定目录下安装了很多可执行文件,供kubelet调用执行这些插件,来实现存储的mount/unmount等功能
  • 需在所有节点预安装驱动文件,并赋予执行权限。

2.2.2.优点

  • 解耦核心代码:独立于Kubernetes发布周期,存储商可自主更新驱动。
  • 兼容多种存储:支持云存储(如阿里云云盘)、分布式存储(如Ceph)。

2.2.3.缺点

  • 部署复杂:需手动在所有节点安装驱动,运维成本高。
  • 功能有限:仅支持基础操作(Attach/Detach、Mount/Unmount),缺乏快照、扩容等高级功能。
  • 权限要求高:需root权限运行脚本,安全风险提升。

2.2.4.适用场景

  • CSI成熟前的过渡方案,或对存储功能要求简单的环境

2.3.Out-of-Tree CSI 插件

为了更好的扩展存储插件,并做到kubernetes与存储的解藕合,设计了CSI标准接口。接口通过gRPC协议定义了存储生命周期的管理操作(如创建卷、快照、扩容)

在这里插入图片描述

2.3.1.CSI 接口类型

2.3.1.1.CSI Controller Service 接口
  • 功能:实现Controller Service 接口,负责集群级别的存储资源管理
  • 核心操作包括
    • 卷的创建(CreateVolume)、删除(DeleteVolume)
    • 卷的附加(ControllerPublishVolume)与分离(ControllerUnpublishVolume)
    • 快照管理(CreateSnapshot/DeleteSnapshot)
    • 卷扩容(ControllerExpandVolume)
  • 部署形式
    • 通常以 ​​Deployment/StatefulSet(单副本)​​ 部署在控制平面节点
    • CSI Controller Pod还会包含 一些CSI Sidecar 组件,以多容器的方式加入:
      • external-provisioner(动态卷供给)
      • external-attacher(卷附加管理)
      • external-resizer(卷扩容)
      • external-snapshotter(快照管理)
    • CSI Sidecar 组件是由kubernetes社区维护的,方便存储厂商接入CSI的一组组件,不需要存储厂商自己开发,只需要部署的时候带上即可
2.3.1.2.CSI Node Service 接口
  • 功能​​:实现 ​​Node Service​​ 接口,负责节点级别的存储操作
  • 核心操作包括:
    • 卷的挂载(NodePublishVolume)与卸载(NodeUnpublishVolume)
    • 节点全局目录准备(NodeStageVolume)与清理(NodeUnstageVolume)
    • 卷状态监控(NodeGetVolumeStats)
  • ​​部署形式​​:
    • 以 ​​DaemonSet(每节点一个 Pod)​​ 部署在工作节点
    • CSI Node Pod 也会包含一些 CSI Sidecar 组件:比如node-driver-registrar,用于向 kubelet 注册驱动,以多容器方式加入Pod。
      • node-driver-registrar 向kubelet注册CSI Driver的方式,其实就是告知 kubelet 本地CSI Driver socket的路径
2.3.1.3.CSI Identity Service 接口
  • ​​功能​​:实现 ​​Identity Service​​ 接口,提供驱动元数据与能力声明
  • 核心操作:
    • 返回驱动名称、版本(GetPluginInfo)
    • 声明支持的 CSI 功能(GetPluginCapabilities)
  • ​​部署形式​​:
    ​​ - 非独立 Pod​​,而是内置于 ​​CSI Controller Pod 和 CSI Node Pod​​ 中
    • 例如:同一 CSI Driver 容器在 Controller 和 Node 模式下均需响应 Identity 接口

2.3.2.CSI 存储插件架构

在这里插入图片描述

CSI 存储插件架构主要包括3个部分:CSI Sidecar、CSI Driver、Kubernetes 原生组件

2.3.2.1.CSI 存储插件架构
Data Plane
CSI Node Pod
Control Plane
CSI Controller Pod
监听 PVC/PV
管理 VolumeAttachment
触发流程
触发流程
gRPC over UDS
注册驱动
调用 Node 接口
挂载/卸载
gRPC over UDS
操作存储
操作存储
创建 PVC/Pod
存储对象同步
读写对象
读写对象
kubelet
VolumeManager
MOUNT
node-driver-registrar
CSI Driver
Storage System
PersistentVolumeController
kube-controller-manager
AttachDetachController
CSI Sidecar Containers
external-provisioner
external-attacher
external-resizer
external-snapshotter
livenessprobe
CSI Driver
用户
API Server
etcd
  • Control Plane
    • kube-controller-manager
      • PersistentVolumeController:监听 PVC,触发动态供给流程(不直接调用 CSI)
      • AttachDetachController:管理 VolumeAttachment 对象(不直接调用 CSI)
    • csi controller pod
      • csi 的控制平面pod,其中容器可以分成:csi sidecar、csi controller service driver
  • Data Plane
    • kubelet
      • VolumeManager:调用 CSI Node 接口(需先通过 node-driver-registrar 注册驱动)
      • 执行两阶段挂载: 挂载到全局目录、绑定挂载到pod文件系统
    • csi node pod
      • csi 的 node pod,其中容器可以分成:node-driver-register、csi node service driver
  • CSI 各团队职责分工:
    • 存储厂商需要提供的代码实体:csi controller service driver、csi node service driver
    • csi sidecar(包括node-driver-register)​是 Kubernetes 社区官方维护的组件,代码托管在 Kubernetes SIG Storage 项目中
2.3.2.2.架构设计核心思想
  1. 解耦与扩展性
    • Kubernetes 核心组件仅管理存储对象(PVC/PV/VolumeAttachment)
    • Sidecar 代理将对象变更转换为 CSI 接口调用
  2. 高可用保障
    • Controller Sidecar 需单副本部署,避免存储操作冲突
    • 可通过 Leader Election 实现多副本选主(如 CubeFS 优化方案)
  3. 安全隔离
    • CSI Driver 以独立进程运行,故障不会影响 kubelet/kube-controller-manager
    • 卷操作权限由 StorageClass 中的 secretRef 动态注入

此架构严格遵循 CSI 规范,已被 AWS EBS、Google Persistent Disk、Ceph RBD 等主流存储系统采用。实际部署时需注意 Sidecar 版本与 Kubernetes 的兼容性(详见 CSI 官方文档)

2.3.2.3.存储卷生命周期流程示例(动态供给 + Pod 挂载)
用户 API Server PersistentVolumeController external-provisioner CSI Driver AttachDetachController external-attacher kubelet node-driver-registrar etcd Storage Scheduler 创建 PVC 存储 PVC 触发 CreateVolume gRPC: CreateVolume() 创建存储卷 返回卷 ID 创建 PV 并绑定 PVC 卷供应完成 创建 Pod(引用 PVC) 调度 Pod 到节点 创建 VolumeAttachment gRPC: ControllerPublishVolume() 附加卷到节点 注册 CSI Driver NodeStageVolume() 挂载到全局目录 NodePublishVolume() 绑定挂载到 Pod 路径 容器启动,使用存储卷 用户 API Server PersistentVolumeController external-provisioner CSI Driver AttachDetachController external-attacher kubelet node-driver-registrar etcd Storage Scheduler

2.3.3.CSI Sidecar

  • CSI Sidecar 是 Kubernetes 中实现容器存储接口(CSI)的核心辅助组件,由 Kubernetes 社区官方维护(SIG Storage),用于桥接 Kubernetes 存储管理逻辑与第三方存储驱动的具体实现。
  • CSI Sidecar 本质是一组独立容器,与存储厂商提供的 CSI Driver 容器协同部署,负责监听 Kubernetes API 对象变更并触发对应的 CSI 接口调用。
  • 根据职责,可将CSI Sidecar分为两类:Controller Sidecar、Node Sidecar
2.3.3.1.Controller Sidecar
  • 部署于 CSI Controller Pod(Deployment/StatefulSet,单副本),处理集群级存储操作:
组件功能监听对象触发的 CSI 接口
external-provisioner动态创建/删除存储卷PVCCreateVolume/DeleteVolume
external-attacher管理存储卷与节点的附加(Attach)/分离(Detach)VolumeAttachmentControllerPublishVolume
external-resizer扩容存储卷容量PVC(容量变更)ControllerExpandVolume
external-snapshotter管理卷快照生命周期VolumeSnapshotCreateSnapshot/DeleteSnapshot
livenessprobe监控 CSI Driver 健康状态,向 kubelet 上报存活状态--
external-health-monitor监控卷健康状态(如文件系统损坏)PersistentVolumeNodeGetVolumeStats(扩展)
2.3.3.2.Node Sidecar
  • 部署于 CSI Node Pod(DaemonSet,每节点),处理节点级卷操作:
组件功能通信对象
node-driver-registrar向 kubelet 注册 CSI Driver,写入驱动信息到 /var/lib/kubelet/plugins_registrykubelet
external-health-monitor-agent节点级卷健康监控(如 I/O 错误)kubelet

2.4.三种存储插件对比

特性In-Tree插件FlexVolume插件CSI插件
耦合性强耦合(K8s核心代码)中等解耦(节点脚本)完全解耦(独立进程)
部署复杂度无需部署高(需节点预安装)中(容器化部署)
功能支持基础卷操作基础卷操作全生命周期管理+高级功能
安全性低(共享进程)低(需root权限)高(独立进程)
社区趋势逐步废弃维护减少主流标准方案
典型用例NFS、iSCSI阿里云早期云盘AWS EBS、Ceph RBD

注:Kubernetes 1.13+ 后CSI进入GA阶段,成为默认推荐方案,FlexVolume仅用于兼容旧驱动

  • 如果要深入学习CSI插件,可以去看CNCF的一个开源项目:Rook

3.kubernetes存储卷类型

3.1.临时存储 emptyDir

3.1.1.emptyDir 介绍

在这里插入图片描述

  • emptydir的真实存储路径:
    • kubelet会在node上为每个pod都创建一个数据目录,用来存储一些运行时文件。该目录不属于容器的overlayFS文件系统,而是记录在主机上的。
    • kubelet的数据目录一般为:/var/lib/kubelet,可以通过 --root-dir 参数配置。该路径下会有个pods的子目录,所有pod的临时数据都记录在这里。
    • pod使用emptydir,默认会为pod创建目录/var/lib/kubelet/pods/<Pod-UID>/volumes/kubernetes.io~empty-dir/<Volume-Name>,作为emptydir的存储目录
    • 也可以通过 docker inspect/crictl inspect 等命令查看容器的挂载信息,会记录数据卷的真实目录
  • emptydir 其实是最常用的存储卷类型,因为用起来最简单,一些临时数据、中间数据都会直接用
  • 注意:pod crash 重启,不会导致emptydir数据清理

3.1.2.emptyDir 参数列表

volumes[0].emptyDir 下面属性

字段可选值默认值核心作用
medium""Memory""选择磁盘或内存存储介质
sizeLimit字符串(如 "1Gi"nil限制卷容量,内存介质必须设置

3.1.2.emptyDir 使用示例

apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-deployment
spec:replicas: 1selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginxvolumeMounts:- mountPath: /cachename: cache-volumevolumes:- name: cache-volumeemptyDir: {}

3.2.半持久化存储 hostPath

3.2.1.hostPath 介绍

在这里插入图片描述

  • hostpath 还有种使用场景:当要拷贝一些文件或可执行程序到主机上的时候,可以使用hostpath,比如 cni 插件,就是通过daemonset往主机cni插件目录拷贝可执行文件的
  • emptyDir 与 hostPath 对比
    • emptyDir 其实也是一种hostPath,但pod删除时kubelet会自动清理emptyDir的数据,emptyDir使用的更广泛

3.2.2.hostPath 使用注意事项

在这里插入图片描述

  • pod漂移到其他node,就无法找到原node的hostpath数据
  • 脏数据问题
    • hostPath的数据,与pod生命周期解耦,pod被干掉后数据依旧保留在node主机上,如果忘记手动清理的话,残留脏数据会占用空间,也可能影响后续pod挂载,如果后续pod挂载该目录就会看到脏数据
  • 权限敏感
    • 使用hostpath时一定要确保目录存在,或使用hostpath.type保证能自动创建目录,
    • 还要确保pod有该主机目录的操作权限
    • 主机目录开放权限是很危险的,要慎用

3.2.3.hostPath 参数列表

volumes[0].hostPath 下面属性

字段名是否必需数据类型默认值描述与行为注意事项
path必需string指定宿主机(节点)上的文件或目录路径。例如:/data/var/logs
(1)若路径是符号链接,则自动解析到真实路径。
(2)路径必须预先存在(除非使用 *OrCreate 类型)
• 路径需有足够权限(通常需 root 或调整目录权限)
• 不同节点路径内容可能不一致,影响 Pod 可移植性
type可选string""定义路径类型及创建行为,可选值如下:
(1)""(空):默认值,不检查路径类型(兼容旧版本)
(2)DirectoryOrCreate:路径不存在时自动创建目录(权限 0755,属主 kubelet
(3)Directory:路径必须是已存在的目录
(4)FileOrCreate:路径不存在时创建空文件(权限 0644,属主 kubelet
(5)File:路径必须是已存在的文件
(6)Socket:路径必须是已存在的 Socket 文件
(7)CharDevice:路径必须是已存在的字符设备
(8)BlockDevice:路径必须是已存在的块设备
FileOrCreate 不创建父目录,需确保父目录存在(可配合 DirectoryOrCreate 使用)
• 非默认类型需显式声明,否则路径校验可能失败

3.2.4.hostPath 使用示例

apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-deployment
spec:replicas: 1selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginxvolumeMounts:- mountPath: /logname: logs-dirvolumes:- name: logs-dirhostPath: path: /var/log

3.3.持久化存储 PV/PVC

3.3.1.为什么需要 PV/PVC

  • 云存储是非常大的一个领域,大部分业务应用同学其实都不太熟悉,让他们部署的时候自行查询集群支持哪些存储,决定要使用什么存储,把控各种存储的使用差异和细节,是不现实的。
  • 那怎么办呢?设计理念:职责分离,专业的事情交给专业的人做。
    • 为了实现存储过程的职责分离,kubernetes中提供了两种类型的资源:PV/PVC
      • PV:供集群管理员声明集群存储
      • PVC:供应用向集群申请存储资源
    • 运维大佬、集群管理员们
      • 事先把集群内支持的所有存储,通过PV的方式声明出来。比如 当前环境有ssd 500Gi,有hssd 100Gi,就会事先创建一些PV。
      • PV代表集群内的存储资源,自然也就和命名空间无关,属于集群级别。
    • 应用程序员
      • 应用程序员们更了解自己的应用,清楚应用运行过程需要多少存储资源(类型、容量、性能等)
      • 他们不需要关心集群有什么资源,只需要编写PVC,向集群申请自己需要的存储类型、容量等信息,集群会自行寻找合适的存储。
      • 应用的 PVC 创建后,kubernetes 会自动为其寻找合适的PV进行绑定,绑定关系是1对1,绑定成功后,代表存储资源满足了需求,应用就可以正常使用了

3.3.2.PV/PVC 介绍

3.3.2.1.PV(PersistentVolume)持久化数据卷

在这里插入图片描述

  • PV 是什么
    • 每一个 PV 都是集群中的一块存储资源。它是由集群管理员预先配置好的,或者通过 StorageClass 动态供应出来的。
    • 你可以把它想象成集群中的一个“物理磁盘”或“网络存储挂载点”(虽然底层可能是云盘、NFS、Ceph 等)。
  • PV 的生命周期
    • PV 是集群级别的资源,独立于任何 Pod 存在。
    • 即使使用它的 Pod 被删除,PV 及其数据通常仍然保留(除非配置为自动删除)。它的生命周期由 Kubernetes 管理。
  • PV 的供应方
    • 静态供应:通常由集群管理员创建
    • 动态供应:由 StorageClass 自动动态创建。后面StorageClass部分会详细讲解
3.3.2.2.PVC(PersistentVolumeClaim)持久化数据卷声明

在这里插入图片描述

  • PVC 是什么
    • PVC是用户(应用开发者)对存储的请求。它表达了应用需要什么样的存储资源(多大容量、什么访问模式)。
    • 你可以把它想象成用户提交的一份“存储需求申请单”。
  • PVC 的生命周期
    • PVC 是命名空间级别的资源。它存在于特定的命名空间中。
    • PVC 首先向集群申请一块存储,然后 Pod 通过引用 同命名空间 下的 PVC 来使用这块存储。
  • PVC 的供应方
    • 由应用开发者在部署应用的 YAML 清单中 直接定义 PVC
    • 或者 在 StatefulSet 等控制器中编写 volumeClaimTemplates,控制器根据模板自行创建PVC

3.3.3.PV/PVC 参数列表

3.3.3.1.PV 参数列表

pv.spec 下面字段

字段名称类型必填描述备注说明
accessModes[]string卷的挂载方式定义卷的访问权限:
- ReadWriteOnce(RWO):单节点读写(如数据库)
- ReadOnlyMany(ROX):多节点只读(如配置文件)
- ReadWriteMany(RWX):多节点读写(如共享文件系统)
capacitymap[string]string存储容量必须包含 storage 键值对(如 storage: 10Gi),决定 PVC 可请求的最大空间
persistentVolumeReclaimPolicystring释放策略PVC 释放后处理方式:
- Retain:保留数据(需手动清理)
- Delete:自动删除存储资源
- Recycle:废弃策略(不安全擦除)
storageClassNamestring所属 StorageClass 名称为空表示静态供给;指定名称则关联 StorageClass 实现动态供给
volumeModestring卷模式Filesystem(默认):创建文件系统
Block:原始块设备(需应用直接操作块设备)
claimRefObject绑定的 PVC 引用包含 namespacename,用于预绑定特定 PVC(防止自动绑定)
mountOptions[]string挂载选项底层存储的挂载参数(如 NFS 的 nfsvers=4.1 或 Ext4 的 noatime
nodeAffinityObject卷的节点亲和性约束限制可使用该卷的节点(常用于 local 卷类型),需定义 required 节点选择器
awsElasticBlockStoreObjectAWS EBS 磁盘配置需指定 volumeIDfsType(如 ext4),仅适用于 AWS 环境
azureDiskObjectAzure 数据磁盘配置需指定 diskNamediskURI,适用于 Azure 托管磁盘
azureFileObjectAzure 文件服务配置需提供 secretName(存储账号密钥)和 shareName(文件共享名)
cephfsObjectCeph FS 存储配置需配置 monitors(Ceph 监控节点)和 path,支持 secretRef 认证
cinderObjectOpenStack Cinder 卷配置需指定 volumeIDfsType,适用于 OpenStack 环境
csiObject外部 CSI 驱动存储配置现代存储扩展方案,需配置 driver 名称和 volumeHandle(存储系统唯一标识)
fcObject光纤通道 (Fibre Channel) 配置需指定 targetWWNs(目标全球端口名)和 lun 号,用于 SAN 存储
flexVolumeObject基于 exec 插件的通用卷配置需指定 driver 路径和自定义参数,支持第三方存储驱动
flockerObjectFlocker 存储配置需配置 datasetNamedatasetUUID(已弃用),用于 Docker 集群存储
gcePersistentDiskObjectGCP 持久化磁盘配置需指定 pdNamefsType,仅适用于 Google Cloud
glusterfsObjectGlusterFS 卷配置需配置 endpoints(Gluster 集群端点)和 path(卷路径)
hostPathObject主机目录配置仅开发测试使用,需指定 pathtype(如 DirectoryOrCreate)。不适用于生产集群
iscsiObjectiSCSI 存储配置需指定 targetPortal(IP:port)、iqn(目标名称)和 lun
localObject本地直接附加存储配置需配合 nodeAffinity 使用,指定 path(节点本地路径),数据与节点生命周期绑定
nfsObjectNFS 共享配置需指定 server(NFS 服务器)和 path(导出路径),支持 readOnly 模式
photonPersistentDiskObjectPhoton Controller 持久化磁盘需指定 pdID,仅适用于 VMware Photon 平台
portworxVolumeObjectPortworx 卷配置需指定 volumeID(Portworx 卷 ID),适用于 Portworx 分布式存储
quobyteObjectQuobyte 存储配置需指定 registry(注册服务地址)和 volume(卷名),支持 readOnly 模式
rbdObjectCeph RBD 块设备配置需配置 monitorspoolimage,支持 secretRef 认证
scaleIOObjectScaleIO 存储配置需指定 gatewaysystemprotectionDomain,适用于 Dell EMC ScaleIO
storageosObjectStorageOS 卷配置需配置 volumeNamesecretRef,适用于 StorageOS 容器存储
vsphereVolumeObjectvSphere 卷配置需指定 volumePath(VMDK 路径)和 fsType,仅适用于 vSphere 环境
  • 关键说明
    1. 必填字段:创建 PV 时必须指定 accessModes, capacity, persistentVolumeReclaimPolicy
    2. 存储后端互斥:25+ 种存储插件配置(如 AWS/GCP/Azure/Ceph/NFS 等),只能启用一种
    3. 动态绑定storageClassName 用于关联 StorageClass 实现动态供给
    4. 安全约束nodeAffinity 确保 Pod 调度到有本地存储的节点
    5. 卷模式volumeMode=Block 时需应用直接操作块设备
    6. 弃用警告Recycle 回收策略已被废弃,建议使用动态供给的 Delete 或静态 Retain
    7. 生产环境:避免使用 hostPath,优先选择云存储或分布式存储(如 Ceph/Portworx)
3.3.3.2.PVC 参数列表

pvc.spec 下面字段

字段名称类型必填描述备注说明
accessModes[]string期望的卷访问模式定义应用需要的访问权限:
- ReadWriteOnce(RWO):单节点读写
- ReadOnlyMany(ROX):多节点只读
- ReadWriteMany(RWX):多节点读写
必须与目标 PV 的访问模式兼容
resourcesObject资源请求必须包含 requests.storage 字段(如 storage: 5Gi),表示最小存储需求。也可设置 limits.storage 限制最大容量
storageClassNamestring所需 StorageClass 名称1.为空时使用默认 StorageClass(集群管理员需要事先注明哪个是default sc);2.设为 "" 显式禁止动态供给;3.指定名称则要求匹配特定存储类
volumeModestring卷模式Filesystem(默认):需要文件系统
Block:需要原始块设备
必须与目标 PV 的 volumeMode 一致
volumeNamestring直接绑定目标 PV 名称强制绑定特定 PV(绕过自动绑定机制),需确保 PV 存在且未被绑定
selectorObjectPV 标签选择器通过标签选择匹配的 PV(如 matchLabels: { tier: ssd }),与 storageClassName 结合使用
dataSourceObject数据源(快照/已有 PVC)支持三种类型:
1. VolumeSnapshot(快照恢复,需启用 VolumeSnapshotDataSource)
2. 已有 PVC(克隆卷)
3. 自定义资源(Alpha 阶段)
需存储后端支持
  • 关键注意事项
    1. 核心必填字段accessModesresources.requests.storage 是创建 PVC 的必要条件
    2. 动态供给流程
      • storageClassName 指定有效存储类时,自动创建符合要求的 PV
      • 若存储类不存在或后端不支持,PVC 将处于 Pending 状态
    3. 数据源克隆
      • 卷快照:从 VolumeSnapshot 恢复数据(需 CSI 驱动支持)
      • PVC 克隆:复制另一个 PVC 的数据(需同一命名空间且 storageClass 相同)
    4. 绑定限制
      • volumeName 优先级最高(显式指定 PV)
      • selector 次之(标签匹配 PV)
      • 最后按 storageClassName + resources + accessModes 自动匹配
    5. 容量验证
      • PVC 请求的容量必须 ≤ PV 的 capacity.storage
      • 动态供给时实际 PV 容量可能略大于请求值(取决于存储系统分配策略)

3.3.4.PV/PVC 的绑定规则

3.3.4.1.绑定流程概览
匹配
不匹配
创建PVC
是否指定volumeName?
直接绑定指定PV
是否配置selector?
筛选匹配标签的PV
按StorageClass筛选
容量/访问模式/卷模式检查
完成绑定
触发动态供给
创建新PV
  • 注意:
    • PV、PVC 的 写权限绑定 是严格1对1的。
    • PV、PVC 的 容量匹配规则:就近向上匹配规则
      • 比如当前有1Gi、5Gi、10Gi三个PV,现在有一个PVC 想要申请2Gi。那么就会匹配到最小能满足容量需求的5Gi PV,与之绑定
    • 只读权限对绑定关系有所放宽,当PV 的 accessModes 包含 ReadOnlyMany 时,Kubernetes 允许该 PV 同时绑定多个 PVC
3.3.4.2.核心匹配规则
3.3.4.2.1. 存储类(StorageClass)匹配
PVC 配置匹配的 PV 要求动态供给行为
未设置 storageClassNamePV 未设置 storageClassName使用默认 StorageClass
storageClassName: “”PV 的 storageClassName 为 “”禁止动态供给
storageClassName: “gold”PV 的 storageClassName 为 “gold”使用 “gold” StorageClass
3.3.4.2.2.访问模式(Access Modes)
  • 严格匹配:PVC 请求的访问模式必须是 PV 支持模式的子集
  • 优先级:ReadWriteOnce < ReadOnlyMany < ReadWriteMany
  • 示例:
    • PVC 请求 [ReadWriteOnce] → 可绑定支持 [ReadWriteOnce, ReadOnlyMany] 的 PV
    • PVC 请求 [ReadWriteMany] → 不可绑定仅支持 [ReadWriteOnce] 的 PV
3.3.4.2.3.存储容量(Capacity)
情况绑定规则
静态 PVPVC 请求 ≤ PV 容量
动态供给PV 容量 ≥ PVC 请求(可能略大)
PVC 设置 limits.storagePV 容量必须在 PVC 请求范围内
3.3.4.2.4.卷模式(VolumeMode)
类型要求使用场景
FilesystemPV/PVC 必须同为 Filesystem常规文件系统(默认)
BlockPV/PVC 必须同为 Block数据库/裸设备访问
3.3.4.3.特殊绑定机制
3.3.4.3.1.直接绑定(volumeName)
# PVC 强制绑定特定 PV
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: myclaim
spec:volumeName: my-pv-001  # 直接指定 PV 名称accessModes:- ReadWriteOnceresources:requests:storage: 5Gi
  • 规则:绕过自动选择器,直接绑定指定 PV
  • 要求:PV 必须存在且未被绑定
  • 风险:PV 不可用时 PVC 将处于 Pending 状态
3.3.4.3.2.标签选择器(Selector)
# PVC 使用标签选择 PV
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: ssd-claim
spec:selector:matchLabels:storage-tier: "ssd"  # 选择含此标签的 PVaccessModes:- ReadWriteOnceresources:requests:storage: 100Gi
  • 匹配逻辑:AND 操作(必须满足所有标签)
  • 优先级:高于 StorageClass 匹配
  • 典型用例:区分不同性能级别的存储(SSD/HDD)
3.3.4.3.3.延迟绑定(VolumeBindingMode)
# StorageClass 配置延迟绑定
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer  # 延迟绑定
  • 工作原理:等待 Pod 调度后,在目标节点创建/绑定 PV
  • 适用场景
    • 本地存储(Local PV)
    • 拓扑受限的存储(如区域化云存储)
  • 优势:避免 PV 与 Pod 节点不匹配的问题
3.3.4.4.回收策略影响
回收策略PVC 删除后 PV 状态数据处置方式重新绑定要求
RetainReleased保留数据(需手动清理)管理员手动重置为 Available
Delete被删除自动删除存储资源需创建新 PV
RecycleAvailable擦除数据(已废弃)自动可用(不再推荐)
3.3.4.5.最佳实践
3.3.4.5.1.生产环境配置
# 推荐的安全配置
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: safe-claim
spec:storageClassName: encrypted-ssdaccessModes:- ReadWriteOnceresources:requests:storage: 50Gilimits:storage: 55Gi  # 防止过大 PV 造成资源浪费volumeMode: Filesystem
3.3.4.5.2.故障排查指南
问题现象可能原因解决方案
PVC 长期 Pending无匹配 PV/StorageClass 错误检查 PV 可用性/SC 配置
绑定后 Pod 无法挂载访问模式不兼容验证 PV/PVC accessModes
数据意外丢失回收策略为 Delete改为 Retain 并设置备份
多节点 Pod 挂载失败PV 仅支持 ReadWriteOnce改用支持 ReadWriteMany 的存储
3.3.4.5.3.高级策略
  • 跨命名空间共享:使用 ReadOnlyMany PV + 多个命名空间的 PVC
  • 容量扩展:v1.24+ 支持在线调整 PVC 容量(需 StorageClass 允许)
  • 克隆卷:通过 dataSource 从现有 PVC 创建新卷
    dataSource:kind: PersistentVolumeClaimname: source-pvc
    

3.4.StorageClass

3.4.1.为什么需要 StorageClass

3.4.1.1.直接使用 PV/PVC 存在什么问题
  • 持久化存储已经有个PV/PVC,把 集群存储管理 和 应用存储请求 做了职责分离,为什么又多出一个StorageClass?
  • 从前面我们知道,PV、PVC 的 容量匹配规则:就近向上匹配规则。这样就可能产生存储碎片。比如:
    • 当下有3个ReadWriteOnce的PV,容量分别是1Gi、5Gi、10Gi
    • 然后当下有4个应用都有自己的PVC,都创建了访问模式为ReadWriteOnce类型的PVC,申请容量为1Gi、2Gi、3Gi、5G
    • 比如此时绑定关系形成这种:1Gi<–>1Gi、2Gi<–>5Gi、3Gi<–>10Gi,那么申请5Gi的PVC就无法找到可用PV,会一直Pending
    • 而申请到5Gi、10Gi的两个应用,压根用不到那么多存储,存储资源就被浪费了
3.4.1.2.StorageClass动态供应PV
  • 怎么解决这种问题?
    • 问题根音:PV是集群管理员手动静态创建的,每个都代表集群的一块真实存储,集群管理员只能把容量设置为一个固定的大小,无法动态调整
    • 那么 如果PV能够根据PVC自动创建就好了。PVC需要1Gi资源,就创建一个1Gi资源大小的PV,给他绑定,这样就 避免一个非常大的PV被一个小需求PVC占用,导致资源浪费的问题
    • 于是就需要有个角色,能够根据用户的PVC,自动创建PV。StorageClass正是这样的角色。
3.4.1.3.StorageClass、PV、PVC之间的关系

在这里插入图片描述

  • 集群管理员 根据集群支持的存储类型,创建对应的StorageClass,并且要把每一种 StorageClass 对应的 CSIDriver 安装好。CSIDriver才是真正用于动态创建PV的程序
  • 用户 根据需求创建PVC,指定StorageClass,或不指定时由默认storageClass负责动态创建PV,并完成PV/PVC绑定
  • 应用 通过引用对应的PVC,来引用存储。对应的PV被attach到相应主机,然后被mount进pod

3.4.2.StorageClass 介绍

在这里插入图片描述

  • StorageClass 是 Kubernetes 中定义存储类型模板的 API 对象,它抽象了底层存储系统的细节,允许管理员提供不同类型的存储(如 SSD/HDD/高速网络存储)供用户按需选择。
  • 每一种 StorageClass 都代表了 一种底层存储,有对应的存储厂商为其编写provisioner。应用编写的PVC指定了对应了StorageClass之后,对应的 StorageClass 控制器就负责为之创建 PV,实现PV的动态供应。
管理员
创建 StorageClass
定义存储类型模板
用户
创建 PVC 指定 StorageClass
自动创建匹配的 PV
User K8s Control Plane CSI Driver Cloud Storage 创建 PVC (指定 StorageClass) 调用 CreateVolume 创建存储卷 返回卷ID 创建 PV 对象 绑定 PVC/PV User K8s Control Plane CSI Driver Cloud Storage

3.4.3.默认StorageClass

  • StorageClass通过annotation:storageclass.kubernetes.io/is-default-class: "true" 标识一个sc是否为默认sc
特性默认 StorageClass非默认 StorageClass
定义方式通过注解标记 is-default-class: "true"无特殊注解
数量限制集群中最多只能有一个生效可创建任意数量
PVC 默认行为未指定 storageClassName 的 PVC 自动使用PVC 必须显式指定名称才能使用
创建必要性强烈推荐为集群设置默认类按需创建
Kubernetes 内置部分发行版预置(如 EKS 的 gp2)无预置
查看命令kubectl get sc 中标注 (default)无特殊标注
优先级当存在默认类时,优先级最高需显式指定才生效
未设置
存在
不存在
显式设置名称
设置为 ''
创建 PVC
是否设置 storageClassName?
检查是否存在默认 StorageClass
使用默认类创建 PV
PVC 保持 Pending
使用指定存储类
禁止动态供给 仅绑定静态PV

3.4.4.StorageClass 参数列表

  • StorageClass没有spec字段,所有属性与apiVersion同级
字段名称类型必填默认值描述实际应用示例
provisionerstring存储供应驱动名称,决定如何创建 PVebs.csi.aws.com (AWS EBS CSI 驱动)
disk.csi.azure.com (Azure Disk)
parametersmap[string]string{}供应驱动的配置参数,特定于每种存储类型AWS EBS:
type: gp3
iops: "4000"
NFS:
server: nfs.example.com
reclaimPolicystringDelete动态 PV 的回收策略Retain (保留存储资源)
Delete (自动删除)
allowVolumeExpansionbooleanfalse是否允许 PVC 创建后扩展容量true (启用在线扩容功能)
volumeBindingModestringImmediatePV 绑定时机策略Immediate立即创建,WaitForFirstConsumer (延迟到 Pod 调度时绑定,适合本地存储)
allowedTopologies[]Object[]限制 PV 创建的拓扑域(需启用 VolumeScheduling 特性)限制在特定区域创建:
matchLabelExpressions:
- key: topology.kubernetes.io/zone
values: [us-east-1a]
mountOptions[]string[]自动创建的 PV 的挂载选项["discard", "noatime"] (SSD 优化)
["nfsvers=4.1"] (NFS 版本指定)
  • 关键字段深度说明:
    1. provisioner

      • 内置驱动:kubernetes.io/ 前缀(如 kubernetes.io/gce-pd
      • CSI 驱动:<driver-name>(如 ebs.csi.aws.com
      • 本地存储:kubernetes.io/no-provisioner
    2. volumeBindingMode

      • Immediate:PVC 创建后立即绑定(适合网络存储)
      • WaitForFirstConsumer:延迟到 Pod 调度时绑定(适合本地存储)
    3. reclaimPolicy

      • Delete:删除 PVC 时自动删除存储资源
      • Retain:删除 PVC 后保留存储资源(需手动清理)

3.4.5.StorageClass 典型配置示例

3.4.5.1.AWS gp3 存储类
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:name: aws-gp3annotations:storageclass.kubernetes.io/is-default-class: "true" # 设为默认
provisioner: ebs.csi.aws.com
parameters:type: gp3iops: "4000"throughput: "250"
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
reclaimPolicy: Delete
3.4.5.2.本地 SSD 存储类
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:name: local-ssd
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
allowedTopologies:
- matchLabelExpressions:- key: topology.kubernetes.io/zonevalues:- us-west1-a
3.4.5.3.NFS 共享存储
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:name: nfs-shared
provisioner: nfs.csi.k8s.io
parameters:server: nfs-server.example.comshare: /exports
mountOptions:- nfsvers=4.1- noresvport

3.4.6.高级特性

3.4.6.1.卷扩展(Volume Expansion)
# 1. StorageClass 启用扩展
allowVolumeExpansion: true# 2. 编辑 PVC 请求更大容量
kubectl patch pvc mypvc -p '{"spec":{"resources":{"requests":{"storage":"20Gi"}}}'

要求

  • 存储后端支持在线扩容
  • 文件系统支持调整(如 ext4/XFS)
3.4.6.2.拓扑感知(Topology)
allowedTopologies:
- matchLabelExpressions:- key: topology.kubernetes.io/zonevalues: [ "us-east-1a", "us-east-1b" ]
  • 确保存储卷与 Pod 在同一故障域
  • 配合 WaitForFirstConsumer 使用
3.4.6.3.快照管理
# 创建 VolumeSnapshotClass
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:name: aws-snapshot-class
driver: ebs.csi.aws.com
deletionPolicy: Delete

3.4.7.常见Volume使用场景

3.4.7.1.独占Local Volume使用过程
  • 对于高 IO p/s的应用,可以通过创建独占本地存储,把主机自带的一些硬盘分配给他,提高读写性能,减少网络io
    在这里插入图片描述
3.4.7.2.动态 Dynamic Local Volume

在这里插入图片描述

在这里插入图片描述

  • Dynamic Local 可以将底层多个硬盘组合成一个逻辑盘,满足一些特别大存储容量的需求。比如需要100T,现在有10块10T的硬盘,单独都满足不了,但是组合在一起就可以
  • 但是Dynamic Local会有下面的一些问题:
    在这里插入图片描述

3.5.8.StorageClass 生产化实践经验

在这里插入图片描述

配置项推荐值原因
默认 StorageClass必须设置一个避免未指定类的 PVC 失败
回收策略关键数据用 Retain防止误删数据
卷绑定模式本地存储用 WaitForFirstConsumer确保 PV 创建在 Pod 调度节点
容量扩展按需启用避免存储后端不支持导致故障

3.4.9.常见存储驱动比较

驱动类型代表实现适用场景特点
云厂商 CSIAWS EBS, GCE PD, Azure Disk公有云环境深度集成云平台功能,支持快照/扩容
网络存储 CSINFS, Ceph RBD, GlusterFS混合云/私有云跨平台兼容,需自建存储集群
本地存储Local PV高性能需求场景低延迟,但数据持久性与节点绑定
容器原生存储Portworx, Longhorn容器化存储方案专为 Kubernetes 设计,支持高级功能(如加密/压缩)

4.问题辨析

4.1.为什么 CRI、CNI、CSI 插件的机制没有统一呢?

Kubernetes 中的 CRI、CNI、CSI 插件机制之所以未采用统一实现方式(如 CRI/CSI 使用 gRPC 远程调用,而 CNI 使用本地可执行文件),核心原因在于它们解决不同领域的扩展问题,且在接口设计时考虑了技术场景的差异历史演进路径以及性能与复杂度平衡

🔧 一、接口定位与技术场景的差异

  1. CRI(容器运行时接口)与 CSI(容器存储接口)

    • 跨节点协调需求
      CRI 管理容器生命周期(如创建/销毁容器),CSI 管理存储卷的创建/挂载等操作,这些操作通常需要跨节点协作(例如存储卷需在多个节点间挂载/卸载)。gRPC 的跨进程通信能力天然适合此类分布式场景
    • 复杂操作与状态管理
      容器运行时需支持镜像拉取、资源隔离等复杂操作;存储卷需支持快照、扩容等高级功能。gRPC 的结构化数据封装(Protocol Buffers)和双向流式通信能更好地处理此类复杂交互
  2. CNI(容器网络接口)

    • 单节点本地操作
      CNI 的核心操作(如为 Pod 添加/删除网卡、配置 IP 地址)仅在当前节点完成,无需跨节点协调。本地可执行文件(如 bridgeflannel 插件)通过标准输入/输出(STDIO)传递 JSON 配置,执行效率更高,延迟更低
    • 轻量化与快速响应
      网络配置需在 Pod 启动/销毁时实时生效,本地命令调用(如 shell 脚本)的低开销更适合这种高频、短时操作

⏳ 二、历史演进与生态兼容性

  1. CNI 的早期设计背景

    • CNI 最初由 CoreOS 为 rkt 容器引擎设计,后由 Kubernetes 采纳。其基于命令行的设计源于 Unix 哲学“小而专的工具”,便于与现有网络工具(如 iproute2iptables)集成
    • 简单性优先
      早期 Kubernetes 网络需求聚焦基础连通性(如 Pod 间通信),命令式插件已足够满足,无需引入 gRPC 的复杂度
  2. CRI/CSI 的后期标准化

    • CRI 和 CSI 诞生于 Kubernetes 解耦核心组件的阶段:
      • CRI(Kubernetes 1.5+)解决 Docker 运行时与 kubelet 的强耦合问题,gRPC 实现运行时热插拔(如从 Docker 切换为 containerd)
      • CSI(Kubernetes 1.9+)替代 in-tree 存储插件,通过 gRPC 支持厂商自定义驱动(如 AWS EBS、Ceph),避免修改 Kubernetes 核心代码

⚖️ 三、性能与复杂度的权衡

维度CNI(本地命令)CRI/CSI(gRPC)
延迟微秒级(直接调用系统工具)毫秒级(跨进程通信)
部署复杂度低(只需二进制文件)高(需部署 gRPC Server 和 Sidecar)
功能扩展性弱(仅支持基础网络配置)强(支持异步调用、双向流、高级特性)
跨节点通信不适用原生支持

🔮 四、未来可能的演进方向

尽管机制不同,但社区正尝试部分统一:

  • CNI 的 gRPC 化尝试
    部分项目(如 Cilium)通过 CNI gRPC 库(如 cni-service)将插件封装为 gRPC 服务,兼顾性能与跨节点能力,但尚未成为主流
  • Sidecar 模式的补充
    CSI 已通过 Node Plugin(DaemonSet 形式)解决部分本地操作问题,平衡了 gRPC 的分布式优势与节点级操作需求

💎 总结:差异存在的必然性

  • CNI 的本地命令机制性能敏感型单节点操作的最优解。
  • CRI/CSI 的 gRPC 机制复杂状态管理与跨节点协调的必要选择。
    三者设计差异本质上是 Kubernetes 在不同领域权衡性能、复杂度与扩展性的结果,而非技术缺陷。未来若出现统一框架,需同时解决网络配置的实时性、运行时/存储的分布式一致性难题。

相关文章:

  • AI评测-(1)基础介绍
  • 【Docker 08】Compose - 容器编排
  • 【单调栈】-----【Largest Rectangle in a Histogram】
  • DPO直接偏好函数的学习解读
  • 【Kubernetes】从零搭建K8s集群:虚拟机环境配置全指南(DNS/网络/防火墙/SELinux全解析一站式配置图文教程)
  • Spring中IoC的理解
  • python模块常用语法sys、traceback、QApplication
  • [muduo] Buffer缓冲区 | TcpServer | Reactor模式
  • 在 `setup` 函数中实现路由跳转:Vue3与Vue Router 4的集成
  • Python 数据分析与可视化 Day 3 - Pandas 数据筛选与排序操作
  • vivado工具配置(二)
  • Python 的内置函数 hasattr
  • 网络编程及原理(六):三次握手、四次挥手
  • 【软考高级系统架构论文】论软件设计方法及其应用
  • modelscope设置默认模型路径
  • app Router VS pages Router(Next.js学习笔记)
  • 车载CAN总线数据采集与故障诊断装置设计与实现
  • Spring Boot邮件发送终极指南:从基础到高级应用
  • 纯跟踪算法本质解密:航向角偏差=预瞄角?数学证明与工程实践
  • vscode搭建spring boot项目
  • 赣州网站优化制作/百度网站推广关键词怎么查
  • soho网站建设教程/免费网站建设平台
  • 动态网站开发过程ppt/企业推广方式
  • 政府网站域名要求/关键词搜索工具有哪些
  • 企业信息公开网查询系统/张掖seo
  • 政府机关网站建设的依据/通过百度指数不能判断出