首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >云硬盘挂到另一可用区:延迟绑定与 diskZone 覆盖

云硬盘挂到另一可用区:延迟绑定与 diskZone 覆盖

原创
作者头像
一只特立独行的兔先生
发布于 2026-11-13 18:15:09
发布于 2026-11-13 18:15:09
380
举报

多可用区 TKE 上,Pod Pending 不一定是容量不够。云硬盘和待挂载的云服务器必须在同一可用区,单台云服务器最多挂 20 块弹性云硬盘。StorageClass 若在调度之前就把盘建出来,盘会落在控制器自己的可用区,Pod 被分到另一边就挂不上。

先建盘时,可用区还不知道

volumeBindingMode 不写时,Kubernetes 使用 Immediate:PVC 一创建就绑定并动态供给。这时还没有 Pod,节点选择、亲和、污点和资源请求都还没参与。盘的可用区已经定死,后面的调度只能迁就它。

TKE 文档里的延迟绑定是反过来的。PV controller 看到 WaitForFirstConsumer 就不立刻供给;调度器选定节点后,把节点名写进 PVC 注解 volume.kubernetes.io/selected-node;provisioner 再按该节点的可用区创建 PV。Immediate 没有选节点这一步,供给发生在调度之前。TKE 文档示例把这个注解写成 volume.kubernetes.io/selected-node: 10.0.0.72。值是节点名,不是盘的地址。

驱动按什么顺序选区

TKE 的 CBS-CSI 简介写明,组件管理里安装的驱动与开源仓库 kubernetes-csi-tencentcloud 同源。当前仓库的 CreateVolume 按下面顺序取可用区,参数名大小写不敏感:

  1. StorageClass 参数 diskZone 或 zone。有值就用,不再看拓扑。
  2. 否则从供给请求的拓扑里取 topology.com.tencent.cloud.csi.cbs/zone。这是驱动常量:topology. 接驱动名 com.tencent.cloud.csi.cbs 再接 /zone。节点插件在 NodeGetInfo 里用本节点的 zone 上报这个键。
  3. 前两步都空,退回控制器进程自己的 zone。

第三步就是跨区的来源。没有延迟绑定、拓扑也没传进来时,盘建在控制器所在可用区,不是 Pod 将要落地的可用区。diskZone 更硬,它覆盖拓扑。多可用区集群写死 diskZone: ap-shanghai-1,新盘全进这一区。

TKE 的跨可用区文档仍写 external-provisioner 从节点标签 failure-domain.beta.kubernetes.io/zone 取区。这和驱动认的拓扑键不是同一个字段。验收以 CSINode 的 topologyKeys 和 PV 的 nodeAffinity 为准,不要只改 beta 标签。

类型也跟区绑在一起。未指定时默认 CLOUD_PREMIUM。type 或 diskType 写成 cbs 时,驱动不把它当成一种盘型,而是按该区配额选默认类型:该区有 CLOUD_BASIC 就用它,否则用 CLOUD_PREMIUM。跨可用区文档的示例写了 type: cbs,会走进这条路径。要固定高性能云硬盘,写 diskType: CLOUD_PREMIUM。指定类型在该区没有配额时创建失败,错误是 no available storage in zone: <zone>。延迟绑定只保证盘和节点同区,不保证这个区售卖这种盘。增强型 SSD、极速型 SSD 的机型和可用区限制以云硬盘使用限制为准。

访问模式只接受 SINGLE_NODE_WRITER。PVC 写成 ReadWriteMany 会在供给时被拒绝,返回原文是 cbs access mode only support singer node writer。日志按这个拼写搜。盘已经挂在别的实例上时,错误是 disk <id> is attach to another instance(<id>) already。

新类怎么写

volumeBindingMode、parameters、provisioner、reclaimPolicy 在 API 里都标了不可变。已有 StorageClass 改不成延迟绑定,要新建。reclaimPolicy 不写则默认 Delete。

代码语言:yaml
复制
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: cbs-topo
provisioner: com.tencent.cloud.csi.cbs
reclaimPolicy: Delete
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer
parameters:
  diskType: CLOUD_PREMIUM

不要在这里写 diskZone。只允许少数可用区时,键必须是驱动上报的那个。写成 topology.kubernetes.io/zone,和 CSINode 上的拓扑键对不上,Pod 会停在 Pending,不会按节点所在区建盘。退回控制器自己的 zone,发生在供给请求里没有这个拓扑键、又没写 diskZone 的时候,典型就是 Immediate。

代码语言:yaml
复制
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: cbs-topo-limited
provisioner: com.tencent.cloud.csi.cbs
volumeBindingMode: WaitForFirstConsumer
allowedTopologies:
- matchLabelExpressions:
  - key: topology.com.tencent.cloud.csi.cbs/zone
    values:
    - ap-shanghai-1
    - ap-shanghai-2
parameters:
  diskType: CLOUD_PREMIUM

ap-shanghai-1 是驱动示例里的可用区名,换成集群真实值。值不是 ap- 前缀时,驱动会再调 DescribeZones,按 ZoneId 转成可用区名。不要依赖这个旁路。

Pod 不要写 spec.nodeName。Kubernetes 文档写明:延迟绑定遇到 nodeName 会绕过调度器,PVC 一直 Pending。要钉节点,用 nodeSelector 的 kubernetes.io/hostname。

已有 StatefulSet 的 volumeClaimTemplates 不可变,改不了里面的 storageClassName。新工作负载用新类,旧卷单独迁。

CDC 上的 TKE 是例外。文档要求把 topology.com.tencent.cloud.csi.cbs/zone 指定为 CDC 所在可用区,同时仍建议 WaitForFirstConsumer。公有云多可用区不要照搬成写死一个区。

已经 Bound 的盘不能换区

Immediate 下已经 Bound 的 PVC,盘在哪个可用区就停在哪个可用区。新建 StorageClass 不会回头改它,PVC 的 storageClassName 也不可变。Pod 被驱逐后只能回到该盘的可用区。该区没有容量,或节点已到挂载上限,Pod 就停在 Pending。TKE 文档写单台默认最多 20 块,调度时会滤掉超过最大可挂载数的节点。这是实例限制,不是 StorageClass 里能调大的参数。

删 PVC 再重建不是修复。默认回收策略是 Delete,删 claim 会删盘。要留数据,先看 PV 的 persistentVolumeReclaimPolicy 是不是 Retain,再迁数据。云硬盘不能换可用区,换区就是新盘。

三处输出对得上才算通

下面命令里的名字是示例。diskZone= 后面应为空。注解那条等 Pod 被调度后再执行。

代码语言:bash
复制
kubectl get sc cbs-topo -o jsonpath='mode={.volumeBindingMode} diskZone={.parameters.diskZone}'
kubectl describe pvc data-0 -n example
kubectl get pvc data-0 -n example -o go-template='{{index .metadata.annotations "volume.kubernetes.io/selected-node"}}'
PV=$(kubectl get pvc data-0 -n example -o jsonpath='{.spec.volumeName}')
kubectl get pv "$PV" -o jsonpath='{.spec.nodeAffinity.required.nodeSelectorTerms[*].matchExpressions[*].key}={.spec.nodeAffinity.required.nodeSelectorTerms[*].matchExpressions[*].values[*]}'
kubectl get csinode -o custom-columns=NODE:.metadata.name,KEYS:.spec.drivers[*].topologyKeys

还没有 Pod 时,PVC 保持 Pending。事件原因是 WaitForFirstConsumer,消息是 waiting for first consumer to be created before binding。这条消息会骗人:Pod 已经在,只是没有节点能满足卷,PVC 上仍可能是这句话。调度失败事件里会有 didn't find available persistent volumes to bind,前面的节点计数随集群变化。

Pod 跑起来后,注解应是节点名。PV 亲和键应是 topology.com.tencent.cloud.csi.cbs/zone,值与该节点上报的 zone 一致。jsonpath 为空就看完整的 PV yaml,不要换一条命令就认为没写上。

建盘接口返回后,当前开源驱动最多再等 100 秒,看盘是否进入 UNATTACHED 或 ATTACHED;挂载最多等 120 秒。轮询间隔都是 5 秒。超时原文分别是 cbs disk <id> is not ready before deadline exceeded 和 cbs disk <id> is not attached before deadline exceeded。集群里的组件版本可能落后于仓库 master,以实际错误为准。

上线前对一下

  • 多可用区的 CBS 类显式写 WaitForFirstConsumer。没写就是 Immediate。
  • 不写 diskZone 或 zone,除非工作负载也钉在同一可用区。
  • 不照抄 type: cbs。要的类型写 diskType。
  • allowedTopologies 的键用 topology.com.tencent.cloud.csi.cbs/zone,值用 ap- 开头的可用区名。
  • 目标可用区要售卖这个 diskType。失败时先看是不是 no available storage in zone。
  • 不用 spec.nodeName 配合延迟绑定。集群版本低于 1.14 时,先满足 CBS-CSI 的前提,不要假设这条路径可用。
  • 旧 PVC 不删。先看回收策略和 nodeAffinity。
  • 单节点按最多 20 块盘规划。副本铺开时,把盘数和该区节点数一起算。

参考文档:

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 先建盘时,可用区还不知道
  • 驱动按什么顺序选区
  • 新类怎么写
  • 已经 Bound 的盘不能换区
  • 三处输出对得上才算通
  • 上线前对一下
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档