【Kubernetes从入门到精通】第38篇:StorageClass——存储的“自助餐“

发布时间:2026/8/14 21:08:08
【Kubernetes从入门到精通】第38篇:StorageClass——存储的“自助餐“ 上一篇【第37篇】PV和PVC——存储的供需匹配平台下一篇【第39篇】本地持久化存储——Local PV和hostPath的正确使用姿势摘要你走进一家自助餐厅。传统模式静态PV供应是你告诉服务员我要吃菜服务员跑到后厨手动做你等着。StorageClass模式是你走到菜品区自己拿——想拿多少拿多少想拿什么拿什么系统自动补货。StorageClass就是K8s存储的自助餐系统。你只需要在PVC里写一行storageClassName: fast-ssdK8s就自动去找对应的StorageClass调用Provisioner在云平台上创建一个真实的存储卷比如AWS EBS然后自动创建PV、自动绑定PVC——全程零人工介入。本文把StorageClass从里到外讲透(1)Provisioner这个大厨怎么工作(2)parameters参数怎么把要几分熟的要求传递到存储后端(3)volumeBindingMode的两种模式Immediate立即绑定和WaitForFirstConsumer等有人来了再绑各自的利弊场景(4)云厂商的StorageClass最佳实践。一、没有StorageClass的世界有多痛苦先回顾一下上一篇静态供应的痛# 静态供应——运维的日常噩梦# 第1天开发说我要部署10个微服务kubectl apply-fpv-service1.yaml# 手动建PV-1kubectl apply-fpv-service2.yaml# 手动建PV-2# ...手动建10个PV...# 第3天开发说新需求再加5个服务# 运维操又要建PV心态崩了# 第7天开发说3个服务下线了PV可以回收了# 运维操又要清理PV心态二次崩了StorageClass一句话解决问题你写一个PVC剩下的全自动。# 有了StorageClass——开发只需要这样写apiVersion:v1kind:PersistentVolumeClaimmetadata:name:my-app-dataspec:storageClassName:fast-ssd# ← 就这一行剩下的全自动accessModes:-ReadWriteOnceresources:requests:storage:10Gi# 几秒后# 1. K8s找到 fast-ssd 这个StorageClass# 2. 调用对应的Provisioner比如AWS EBS CSI Driver# 3. Provisioner调用AWS API创建10G的EBS卷# 4. Provisioner自动创建PV对象# 5. PV自动绑定到PVC# 6. 你的Pod直接mount上去用# 全程不用运维不用等审批不用写NFS地址二、StorageClass的解剖——自助餐菜单怎么写2.1 StorageClass最简示例# StorageClass——最简配置apiVersion:storage.k8s.io/v1kind:StorageClassmetadata:name:fast-ssd# SC的名字PVC里用这个名字引用annotations:storageclass.kubernetes.io/is-default-class:true# 标记为默认SCprovisioner:ebs.csi.aws.com# ← 最关键的字段用哪个大厨parameters:# 传给Provisioner的菜谱参数type:gp3# EBS卷类型fsType:ext4# 文件系统格式encrypted:true# 是否加密iops:3000# IOPSgp3支持独立配置IOPSthroughput:125# 吞吐量gp3新特性reclaimPolicy:Delete# PVC删除后自动删除EBS卷allowVolumeExpansion:true# 允许扩容PVCvolumeBindingMode:WaitForFirstConsumer# 等有人要用再创建详后mountOptions:# 挂载选项-debug-noatime要点StorageClass本质就是一个配方表——定义好用什么厨师provisioner、怎么做parameters、吃完怎么处理reclaimPolicy。你点菜PVC的时候说按这个配方的来一份厨房Provisioner就照方抓药。不同的配方可以做不同风格的菜——SSD快速存储、HDD廉价存储、加密存储、共享文件存储全是换个配方的事。2.2 Provisioner——StorageClass的灵魂Provisioner就是那个大厨。不同的Provisioner会做不同的菜【Provisioner——各种大厨和他们的拿手菜】 ┌─────────────────────────────────────────────────────────┐ │ StorageClass (菜单) │ │ │ │ provisioner: 请指定哪个大厨来做这道菜 │ └────────────────────────┬────────────────────────────────┘ │ ┌───────────────┼───────────────┐ │ │ │ ▼ ▼ ▼ ┌─────────────────┐ ┌─────────────┐ ┌─────────────────┐ │ AWS EBS Chef │ │ GCE PD Chef │ │ NFS Chef │ │ (ebs.csi.aws │ │(pd.csi.gcp │ │(nfs.csi.k8s │ │ .com) │ │ .com) │ │ .io) │ │ │ │ │ │ │ │ 拿手菜: │ │ 拿手菜: │ │ 拿手菜: │ │ • gp3 SSD │ │ • pd-ssd │ │ • NFS共享目录 │ │ • io2 高性能 │ │ • pd-hdd │ │ • 多Pod读写 │ │ • st1 大容量 │ │ │ │ │ └─────────────────┘ └─────────────┘ └─────────────────┘ 常见Provisioner一览 ┌────────────────────────────────┬──────────────────────────┐ │ Provisioner │ 对应存储 │ ├────────────────────────────────┼──────────────────────────┤ │ kubernetes.io/aws-ebs │ AWS EBS (in-tree, 弃用) │ │ ebs.csi.aws.com │ AWS EBS (CSI, 推荐) │ │ pd.csi.storage.gke.io │ GCE Persistent Disk │ │ disk.csi.azure.com │ Azure Disk │ │ file.csi.azure.com │ Azure Files │ │ nfs.csi.k8s.io │ NFS (CSI) │ │ cephfs.csi.ceph.com │ CephFS │ │ rbd.csi.ceph.com │ Ceph RBD │ │ rook-ceph.rbd.csi.ceph.com │ Rook Ceph RBD │ │ nfs-subdir-external-provisioner│ NFS子目录Provisioner │ └────────────────────────────────┴──────────────────────────┘要点区分in-tree和out-of-tree的provisioner很重要。kubernetes.io/aws-ebs是K8s内置的老版本in-tree已经不推荐使用了。新项目一律用CSI版本的provisioner如ebs.csi.aws.com独立发布、独立迭代、不依赖K8s版本。2.3 parameters——“少盐、微辣、七分熟”parameters是传给Provisioner的烹饪参数——你想让存储卷有什么特性就在这里配置# 不同存储后端的parameters差异很大——类比不同菜系的配方# AWS EBS 的参数apiVersion:storage.k8s.io/v1kind:StorageClassmetadata:name:premium-ssdprovisioner:ebs.csi.aws.comparameters:type:gp3# 卷类型fsType:ext4# 文件系统encrypted:true# 加密kmsKeyId:arn:aws:kms:...# 加密密钥iops:16000# IOPSthroughput:1000# 吞吐量 MB/s---# Azure Disk 的参数apiVersion:storage.k8s.io/v1kind:StorageClassmetadata:name:azure-premiumprovisioner:disk.csi.azure.comparameters:skuName:Premium_LRS# Premium SSDkind:Managed# 托管磁盘cachingMode:ReadOnly# 缓存模式---# GCE PD 的参数apiVersion:storage.k8s.io/v1kind:StorageClassmetadata:name:gce-ssdprovisioner:pd.csi.storage.gke.ioparameters:type:pd-ssd# SSD持久盘replication-type:regional-pd# 跨区域复制fsType:xfs# XFS文件系统# 查看集群中的所有StorageClass及其参数kubectl get storageclass# NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE# fast-ssd ebs.csi.aws.com Delete WaitForFirstConsumer# standard ebs.csi.aws.com Delete Immediate# premium-rwx efs.csi.aws.com Retain Immediate# 查看特定SC的详细配置kubectl describe storageclass fast-ssd# Parameters:# encrypted: true# fsType: ext4# iops: 3000# type: gp3三、volumeBindingMode——“先上菜还是等人来再上菜”这是StorageClass里最容易理解错但最重要的一项配置。它决定了PV什么时候被创建、什么时候绑定给PVC。3.1 两种模式的核心区别【volumeBindingMode——提前做 vs 等人来再做】 Immediate立即绑定 WaitForFirstConsumer等人来再绑 ──────────────────── ────────────────────────────── PVC一创建 → 立即创建PV PVC创建 → 先不创建PV → 立即绑定PV → 等着 → Pod还没影呢 → Pod被调度器安置到Node → 然后才创建PV、绑定 时间线 时间线 ──────── ──────── t0: 创建PVC t0: 创建PVC t1: 立即创建PV(在某个可用区) t1: 啥也不干Pending t2: 立即绑定 t2: 啥也不干Pending t3: 创建Pod t3: 创建Pod t4: 调度Pod t4: 调度器决定Pod放哪个Node t5: Pod启动 ✅ t5: 创建PV在Pod所在可用区 t6: 绑定PV t7: Pod启动 ✅ 问题PV可能在Zone-APod被调度 好处PV一定在Pod所在可用区 到Zone-B → 挂载失败 绝对不会挂错区3.2 场景选择——什么时候用哪种场景推荐模式原因多可用区集群 块存储EBS/PDWaitForFirstConsumerEBS只能在同AZ挂载等确认Pod位置再建卷单可用区集群Immediate没有跨AZ问题立即创建更简单网络存储NFS/CephFS/EFSImmediate网络存储跨AZ不需要等开销敏感的测试环境WaitForFirstConsumerPVC不消费Pod就不创建省资源需要预热的存储Immediate有些存储创建需要时间提前准备好要点volumeBindingMode的选择本质上是一个先有鸡还是先有蛋的问题——你是先创建PV再等PodImmediate还是先等Pod调度再创建PVWaitForFirstConsumer。对于块存储EBS/PD/本地盘永远选WaitForFirstConsumer。这个决策只有一个例外你的集群只有一个可用区——那选哪个都行。多AZ环境下选Immediate就是找死——你会看到一半的Pod因为跨AZ挂载失败而CrashLoopBackOff。# WaitForFirstConsumer 标准配置多AZ集群推荐apiVersion:storage.k8s.io/v1kind:StorageClassmetadata:name:fast-ssd-waitprovisioner:ebs.csi.aws.comvolumeBindingMode:WaitForFirstConsumer# ← 关键配置parameters:type:gp3allowVolumeExpansion:true---# Immediate 标准配置单AZ或网络存储apiVersion:storage.k8s.io/v1kind:StorageClassmetadata:name:nfs-sharedprovisioner:nfs.csi.k8s.iovolumeBindingMode:Immediate# ← NFS跨AZ可以立即绑parameters:server:nfs-server.default.svc.cluster.localshare:/exports3.3 WaitForFirstConsumer的完整工作流【WaitForFirstConsumer——完整时间线】 时间 事件 PVC状态 PV状态 ──── ──── ────── ───── t0 开发者创建PVC Pending 不存在 我要10Gi, fast-ssd t1 K8s看到WaitForFirstConsumer Pending 不存在 先等等别急着做 t2 开发者创建Pod引用这个PVC Pending 不存在 t3 调度器为Pod选Node Pending 不存在 Pod放Node-3在AZ-a t4 Kubelet发现Pod的PVC未绑定 Pending 不存在 触发volume provisioning t5 Provisioner在AZ-a创建EBS卷 Pending Creating 在AZ-a建了个10G的gp3卷 t6 EBS卷创建完成 Pending Available 创建PV对象 t7 K8s将PV绑定到PVC Bound Bound t8 Kubelet挂载EBS卷到Node-3 Bound Bound Pod启动✅要点WaitForFirstConsumer本质上是一种延迟绑定策略——它把PV的创建时机推迟到Pod调度决策完成后。这对于多可用区集群使用块存储是必须的——因为EBS/PD等块存储有AZ亲和性卷必须在Pod所在AZ才能挂载。如果你用Immediate模式在多AZ集群里跑有50%的概率Pod启动失败——因为它被调度到了另一个AZ。四、默认StorageClass——“不用点名自动找你”# 如果集群设置了默认StorageClass# PVC不需要写storageClassName自动使用默认的# 查看默认StorageClasskubectl get storageclass# NAME PROVISIONER RECLAIMPOLICY# gp2 (default) ebs.csi.aws.com Delete# ↑ 有 (default) 标记的就是默认SC# 设置某个SC为默认kubectl patch storageclass gp2-p{metadata:{annotations:{storageclass.kubernetes.io/is-default-class:true}}}# 取消默认SCkubectl patch storageclass gp2-p{metadata:{annotations:{storageclass.kubernetes.io/is-default-class:null}}}# 创建不指定SC的PVC——自动用默认SCapiVersion: v1 kind: PersistentVolumeClaim metadata: name: auto-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi# 不写 storageClassName → 自动使用默认SC要点默认StorageClass很方便但要小心隐式行为。如果你同时在用多种存储SSD和HDD不要设默认SC——让开发者显式指定用哪个。否则有人写了个PVC忘了声明storageClassName结果系统给了一个HDD慢速存储等到性能问题暴露已经晚了。原则生产环境宁可多写一行storageClassName也别依赖默认值。五、扩容——“吃完了还能续杯”# StorageClass 需要开启 allowVolumeExpansionapiVersion:storage.k8s.io/v1kind:StorageClassmetadata:name:expandable-ssdprovisioner:ebs.csi.aws.comallowVolumeExpansion:true# ← 允许扩容必须显式开启parameters:type:gp3# 扩容PVC在线扩容不需要停Podkubectl patch pvc my-app-data-p{spec:{resources:{requests:{storage:20Gi}}}}# 前提# 1. StorageClass 设置了 allowVolumeExpansion: true# 2. 底层存储支持扩容gp3支持gp2也支持# 3. 新的容量 旧容量只能扩不能缩# 查看扩容进度kubectl describe pvc my-app-data# Conditions:# Type Status LastProbeTime# FileSystemResizePending True 正在扩容文件系统...# 几秒后变成 ResizeSucceeded# ⚠️ 重要限制# - 只能扩容不能缩容只增不减# - 扩容过程中Pod可以继续使用# - 扩容完成后Pod内文件系统自动扩展# - 有些存储类型需要重启Pod才能看到新容量六、云厂商StorageClass最佳实践6.1 AWS EKS 推荐配置# 分层存储策略——按性能和成本分为三个等级# 1. 高性能SSD数据库apiVersion:storage.k8s.io/v1kind:StorageClassmetadata:name:premium-ssdprovisioner:ebs.csi.aws.comvolumeBindingMode:WaitForFirstConsumer# 多AZ必须等allowVolumeExpansion:truereclaimPolicy:Deleteparameters:type:gp3fsType:ext4encrypted:trueiops:16000throughput:1000---# 2. 标准SSD一般应用apiVersion:storage.k8s.io/v1kind:StorageClassmetadata:name:standard-ssdprovisioner:ebs.csi.aws.comvolumeBindingMode:WaitForFirstConsumerallowVolumeExpansion:truereclaimPolicy:Deleteparameters:type:gp3fsType:ext4iops:3000throughput:125---# 3. HDD大容量备份/日志apiVersion:storage.k8s.io/v1kind:StorageClassmetadata:name:bulk-hddprovisioner:ebs.csi.aws.comvolumeBindingMode:WaitForFirstConsumerallowVolumeExpansion:truereclaimPolicy:Deleteparameters:type:st1fsType:ext46.2 阿里云 ACK 推荐配置# 阿里云极速SSDapiVersion:storage.k8s.io/v1kind:StorageClassmetadata:name:alicloud-essdprovisioner:diskplugin.csi.alibabacloud.comvolumeBindingMode:WaitForFirstConsumerallowVolumeExpansion:trueparameters:type:cloud_essd# ESSD云盘performanceLevel:PL2# PL0/PL1/PL2/PL3encrypted:true---# 阿里云NAS共享文件存储支持RWXapiVersion:storage.k8s.io/v1kind:StorageClassmetadata:name:alicloud-nasprovisioner:nasplugin.csi.alibabacloud.comvolumeBindingMode:Immediate# NAS是网络存储可以立即绑parameters:volumeAs:subpathserver:xxxxx.cn-hangzhou.nas.aliyuncs.com:/path:/k8svers:3options:nolock,prototcp,rsize1048576,wsize1048576七、StorageClass的日常操作# 创建StorageClasskubectl apply-fstorageclass.yaml# 查看所有StorageClasskubectl get sc# kubectl get storageclass 也一样# 查看详细信息kubectl describe sc fast-ssd# 修改StorageClass注意immutable字段改不了kubectl edit sc fast-ssd# 可修改的字段allowVolumeExpansion, mountOptions, reclaimPolicy, metadata# 不可修改的字段改了也不生效provisioner, parameters, volumeBindingMode# 删除StorageClasskubectl delete sc old-sc# 注意删除SC不会影响已经用这个SC创建的PV和PVC# 查看PVC使用的是哪个SCkubectl get pvc-owide# 或者kubectl describe pvc my-pvc|grepStorageClass# 查看PVC对应的底层存储卷IDkubectl describepv$(kubectl get pvc my-pvc-ojsonpath{.spec.volumeName})|grepVolumeID本篇小结StorageClass让K8s存储从半自动进化到全自动——你再也不用手动管理PV的创建和删除。核心掌握三点Provisioner是灵魂不同的provisioner对应不同的存储后端选对了直接决定了你能用什么参数和特性volumeBindingMode是开关多AZ集群用块存储必须配WaitForFirstConsumer否则Pod可能因跨AZ挂载失败parameters是可选的配方每个Provisioner有自己的一套参数按需配置——不用背查文档即可实战中一个集群至少配两个StorageClass一个高性能SSD给数据库、一个大容量HDD给日志和备份。再加一个NAS的SC支持RWX给需要多Pod共享的应用。下一篇聊Local PV——当你对性能有极致追求不想加任何网络存储的延迟直接用Node本地盘做持久化存储。上一篇【第37篇】PV和PVC——存储的供需匹配平台下一篇【第39篇】本地持久化存储——Local PV和hostPath的正确使用姿势

相关新闻