lolspider / notes
Clipping · 2 分钟

一、整体架构

这次问题的核心现象是:

plaintext
PVC 显示已经从 100Gi 扩到 200Gi
但 Pod 内 df -h 仍只有 99G

最终定位:

OpenEBS 后端已经扩容成功,但 Linux device-mapper(multipath)层没有刷新容量,导致文件系统仍看到旧大小。


一、整体架构

你这个链路实际上是:

plaintext
业务 Pod
↓
NFS Server Pod(openebs nfs-kernel)
↓
PVC(cStor CSI)
↓
OpenEBS cStor Volume
↓
iSCSI Target
↓
Node 上 iSCSI Device
↓
dm-multipath/device-mapper
↓
ext4 filesystem

这里:

plaintext
真正扩容的是 backend cStor volume

不是 NFS 本身。


二、问题现象

PVC describe

看到:

plaintext
Capacity: 200Gi

但 events 中持续出现:

plaintext
ResizeInProgress

以及:

plaintext
VolumeResizeFailed

同时又有:

plaintext
FileSystemResizeSuccessful

这是一个非常“矛盾”的状态。


三、第一次误判

最开始以为:

plaintext
OpenEBS Controller Resize 卡死

因为:

  • external-resizer 持续 retry
  • PVC event 反复报 ResizeInProgress

这是 cStor 很常见的问题。


四、关键证据

查看 CVC

bash
kubectl describe cvc pvc-xxx

出现:

plaintext
VolumeResizeSuccessful

说明:

OpenEBS 自己已经认为 resize 成功。


五、真正突破点

在 Pod 内查看 df

bash
df -h

看到:

plaintext
/dev/mapper/1OpenEBS_iscsi_xxx   99G

这说明:

plaintext
文件系统实际仍只有 100G

于是问题方向改变:

不是 metadata 卡住,而是真实 block device 没变大。


六、继续深入定位

查看 CStorVolume

bash
kubectl get cv -o yaml

发现:

yaml
spec.capacity: 200Gi
status.capacity: 200Gi
phase: Healthy

说明:

plaintext
OpenEBS backend volume 实际已经扩容成功

因此:

问题一定在 Node 侧。


七、关键发现

查看 lsblk

bash
lsblk

看到:

plaintext
sdf       200G
└─dm-9    100G

这是整个问题的关键。

说明:

SCSI device 已经扩容成功

但:

dm-multipath/device-mapper 仍缓存旧大小


八、问题根因

本次问题本质是:

device-mapper 没 reload table

即:

plaintext
底层 iSCSI device
已经从 100G 变为 200G

但:

plaintext
上层 dm device
仍然维持旧 mapping

因此:

plaintext
filesystem 只能看到 100G

九、为什么 Kubernetes 误判成功?

CSI 扩容流程:

plaintext
1. ControllerExpandVolume
2. NodeExpandVolume
3. Filesystem Resize

实际情况:

plaintext
OpenEBS backend resize 成功
↓
Node SCSI rescan 成功
↓
但 dm table 未 reload
↓
resize2fs 实际没扩
↓
Kubelet 仍认为成功

因此:

plaintext
FileSystemResizeSuccessful

是“假成功”。


十、最终解决方案

有两种。


方案1(推荐)

重建使用 PVC 的 Pod

例如:

bash
kubectl delete pod -n openebs nfs-pvc-xxx

原理:

plaintext
Pod 重建
↓
重新 attach volume
↓
重新建立 iSCSI session
↓
重新创建 dm mapping
↓
自动识别 200G

这是:

Kubernetes 最推荐、最稳定的方法


方案2(在线修复)

手工刷新 multipath:

bash
multipathd resize map <map-name>

然后:

ext4

bash
resize2fs /dev/mapper/xxx

或:

xfs

bash
xfs_growfs

十一、为什么不会影响数据?

因为:

扩容本质是:

plaintext
在已有 filesystem 后面增加可用空间

不是:

  • 重建 filesystem
  • 格式化
  • 覆盖数据

ext4/xfs 都支持在线扩容。


十二、为什么会发生这个问题?

这是:

OpenEBS cStor + iSCSI + multipath 的经典问题

尤其:

  • device-mapper
  • multipath
  • kubelet rescan race
  • 老内核
  • 老 iscsiadm

组合时很常见。

核心原因:

plaintext
Kubelet 不负责 reload dm table

它通常只:

plaintext
rescan SCSI device

不会:

plaintext
multipath resize

十三、本次问题最终结论

OpenEBS 实际没有问题

真正问题是:

Linux dm-multipath 没刷新容量

导致:

plaintext
PVC=200Gi
backend=200Gi
filesystem=100Gi

形成状态不一致。


十四、后续建议

1. 扩容后重点检查

不要只看:

bash
kubectl get pvc

必须同时检查:

bash
df -h
lsblk

2. 如果使用 multipath

扩容后建议:

bash
multipathd resize map

或者:

plaintext
重建 Pod

3. Kubernetes 的“ResizeSuccessful”不一定可靠

CSI success 不代表:

plaintext
filesystem 真正变大

最终一定要:

bash
df -h

验证。