“PVC 扩容”到底是谁在做?kubectl patch 一下 20Mi 就算扩好了吗?这篇用没有扩容能力的 local-path 存储把 API Server 管的那一半(让不让改、能改什么)和存储驱动管的那一半(真正把卷变大)拆开,看清中间停在哪一步。
存储类 k53-noexp(allowVolumeExpansion: false)的 PVC a:spec.requests=10Mi;status.capacity=10Mi;conditions=['Unused'] 把 a 改成 20Mi:退出码 1;Error from server (Forbidden): persistentvolumeclaims "a" is forbidden: only dynamically provisioned pvc can be resized and the storageclass that provisions the pvc must support resize 被拒绝之后 a:spec.requests=10Mi;status.capacity=10Mi;conditions=['Unused'] 把存储类的 allowVolumeExpansion 改成 true 之后再改 a 为 20Mi:退出码 0;persistentvolumeclaim/a patched(字段是随时可改的,而且对已有 PVC 立即生效)
存储类 allowVolumeExpansion: false 时,把已绑定 PVC 的 requests.storage 从 10Mi 改成 20Mi 直接返回 Forbidden: only dynamically provisioned pvc can be resized and the storageclass that provisions the pvc must support resize。这是 API Server 的准入检查,与存储驱动无关。
allowVolumeExpansion 是存储类上可以事后修改的字段,改成 true 后同一条 patch 立刻被受理——它对已经存在的 PVC 同样生效。
扩容前 b:spec.requests=10Mi;status.capacity=10Mi;conditions=['Unused'];PV capacity=10Mi;Pod 里 df /d 总大小 474095688 KiB(local-path 的卷是节点磁盘上的目录,df 看到的是整块节点磁盘)
把 b 改成 20Mi:退出码 0;persistentvolumeclaim/b patched
40 秒之后 b:spec.requests=20Mi;status.capacity=10Mi;conditions=['Unused'];PV capacity=10Mi;df 总大小 474095688 KiB
b 上多出来的事件:['ExternalExpanding: waiting for an external controller to expand this PVC']允许扩容的类 k53-exp 上,PVC b 改成 20Mi 后 patch 成功,但 40 秒之后 status.capacity 还是 10Mi,PV 的 capacity 还是 10Mi,Pod 里 df 的总大小也没变(local-path 的卷本来就是节点磁盘上的目录,df 看到的是整块盘)。PVC 上多出一条事件 ExternalExpanding: waiting for an external controller to expand this PVC。
spec 写的是意图,status.capacity 是结果;从前者到后者要靠 CSI 的 external-resizer 这类控制器完成,local-path-provisioner 没有实现扩容,所以请求一直停在这里。真正的在线扩容(文件系统在容器运行时被撑大)需要支持它的 CSI 驱动,本文的集群验证不了。
b 现在 spec 是 20Mi、容量 10Mi;改成 5Mi:退出码 1;The PersistentVolumeClaim "b" is invalid: spec.resources.requests.storage: Forbidden: field can not be less than status.capacity 改成 15Mi(比 spec 的 20Mi 小,但比容量 10Mi 大):退出码 0;persistentvolumeclaim/b patched;现在 spec.requests=15Mi;status.capacity=10Mi;conditions=['Unused'] 改回 10Mi(等于容量):退出码 1;The PersistentVolumeClaim "b" is invalid: spec.resources.requests.storage: Forbidden: field can not be less than status.capacity;现在 spec.requests=15Mi;status.capacity=10Mi;conditions=['Unused']
b 的 spec 现在是 20Mi、容量 10Mi:改成 5Mi 被拒,field can not be less than status.capacity;改成 15Mi(比 spec 小但比容量大)被受理;改成 10Mi(正好等于容量)却仍然被拒,报错相同,spec 停在 15Mi。最后这一条是实测结果,但我没弄清为什么等于容量也算“小于”,所以不拿它下结论。
PVC c(类 k53-exp 允许扩容,没有 Pod 使用,phase=Pending):spec.requests=10Mi;status.capacity=(无);conditions=(无) 把还是 Pending 的 c 改大到 30Mi:退出码 1;The PersistentVolumeClaim "c" is invalid: spec: Forbidden: spec is immutable after creation except resources.requests and volumeAttributesClassName for bound claims 创建 Pod 使 c 绑定之后:spec.requests=10Mi;status.capacity=10Mi;conditions=['Unused'];PV capacity=10Mi 绑定之后改 accessModes:退出码 1;The PersistentVolumeClaim "c" is invalid: spec: Forbidden: spec is immutable after creation except resources.requests and volumeAttributesClassName for bound claims 绑定之后改 requests.storage 为 30Mi:退出码 0;persistentvolumeclaim/c patched
还是 Pending 的 PVC c 想把大小改成 30Mi 被拒:spec is immutable after creation except resources.requests and volumeAttributesClassName for bound claims——没绑定时 spec 整个不可变,想换大小只能删了重建。绑定之后,改 accessModes 依然被拒,只改 requests.storage 才被受理。
另外,v1.37 里 PVC 的 status.conditions 会有一条 Unused,有 Pod 引用时它是 False(reason PodUsingPVC)。