多可用区 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 按下面顺序取可用区,参数名大小写不敏感:
diskZone 或 zone。有值就用,不再看拓扑。topology.com.tencent.cloud.csi.cbs/zone。这是驱动常量:topology. 接驱动名 com.tencent.cloud.csi.cbs 再接 /zone。节点插件在 NodeGetInfo 里用本节点的 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。
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。
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_PREMIUMap-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。公有云多可用区不要照搬成写死一个区。
Immediate 下已经 Bound 的 PVC,盘在哪个可用区就停在哪个可用区。新建 StorageClass 不会回头改它,PVC 的 storageClassName 也不可变。Pod 被驱逐后只能回到该盘的可用区。该区没有容量,或节点已到挂载上限,Pod 就停在 Pending。TKE 文档写单台默认最多 20 块,调度时会滤掉超过最大可挂载数的节点。这是实例限制,不是 StorageClass 里能调大的参数。
删 PVC 再重建不是修复。默认回收策略是 Delete,删 claim 会删盘。要留数据,先看 PV 的 persistentVolumeReclaimPolicy 是不是 Retain,再迁数据。云硬盘不能换可用区,换区就是新盘。
下面命令里的名字是示例。diskZone= 后面应为空。注解那条等 Pod 被调度后再执行。
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,以实际错误为准。
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 的前提,不要假设这条路径可用。nodeAffinity。参考文档:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。