节点排水期间本地存储卷如果处理不当会直接丢数据,核心结论是:必须在 drain 之前明确区分 emptyDir 和 local PV 的归属关系,做好备份或迁移,否则节点下线那一刻,数据就跟着“蒸发”了。
很多运维第一次碰上节点排水都栽在本地卷上,明明在控制台上点了“节点维护”,Pod 也顺利迁移到了其他机器,可服务一启动就报错“文件不存在”,这不是 Kubernetes 出 bug,而是本地存储卷天生就有“地域属性”它长在这台机器的磁盘上,Pod 走了,数据却留不下来。
节点排水期间本地卷丢失的根因分析
先搞清楚 Kubernetes 节点排水机制是怎么工作的,kubectl drain 命令会对节点上的 Pod 执行 eviction,驱逐前会检查 Pod 是否满足 PodDisruptionBudget 规则,空数据目录的 Pod 需要额外加 –delete-emptydir-data 参数才能强制驱逐。
问题恰恰出在这里,本地存储卷分两类,处理方式完全不同:emptyDir 属于临时卷,生命周期跟着 Pod 走,Pod 删了目录就清了,这类卷在排水时直接丢弃没有任何风险,而 local PV(本地持久卷)绑定的是节点上的真实磁盘路径,Pod 调度时会因为 PV 的 nodeAffinity 被钉死在这台机器上。
行业共识认为,大多数排水事故都源于对 local PV 的三大误解:第一,以为 PersistentVolumeClaim 有内置备份,local PV 没有底层副本;第二,以为 drain 会像云磁盘一样自动迁移数据,local PV 的数据迁移本来就需要外部工具配合;第三,完全没看 PV 的 reclaimPolicy 设置,Delete 策略会在 PV 删除时直接清盘。
local PV 是距离数据最近、同时也最脆弱的存储方案,节点排水安全的前提是“主动搬运数据,而不是被动等待迁移”。
处理前必须清单:判断本地卷的类型与状态
动手排水前,先用这几条命令给节点把脉,数据安全永远建立在“先摸清家底”上:
- 检查节点上所有 PV 的存储类型:
kubectl get pv -o wide | grep <node-name>筛选出 Local 类型的条目 - 查看 PVC 与 Pod 的绑定关系:
kubectl get pod -o wide | grep <node-name>找出所有使用本地卷的工作负载 - 核对每个 PV 的回收策略:
kubectl get pv <pv-name> -o yaml | grep persistentVolumeReclaimPolicy - 确认 emptyDir 的实际使用量:进入容器执行
df -h,如果超过内存限制的一半,建议调整 medium 类型
一条极容易被忽略的坑:daemonset 类型的 Pod 即使使用本地卷也无法被 drain 正常驱逐,必须加 –ignore-daemonsets 参数跳过,这不是绕过问题,而是给 DaemonSet 更新留出另外的通道。
节点排水期间本地存储卷怎么安全的实操步骤
如果业务允许短暂停机,直接走最稳妥的三步方案,这套步骤在很多生产集群里跑过,按顺序执行基本不会出问题。
第一步:提前摘流并备份元数据
把服务的流量从待维护节点上摘掉,确认无新写入后,登录节点把本地卷里的数据同步一份到临时中转位置,常用的命令组合是:
tar czvf /backup/local-volume-$(date +%Y%m%d).tar.gz /data/local-storage scp /backup/local-volume-.tar.gz backup-server:/data/volume-backup/
tar 打包适合文件数量不多、总量在百 GB 以内的场景,如果数据量更大,直接用 rsync 做增量同步更划算,这一步的核心价值在于 本地卷快照是最后一道保险,即使后续迁移方案出现了偏差,数据还有一次回滚机会。
第二步:解绑 PVC 并驱逐工作负载
针对 local PV 绑定的 PVC,可以在排水前先删除工作负载,再逐个删除 PVC,让 PV 回到 Released 状态。注意不要直接删 PV,Delete 策略的 PV 会在 PVC 删除后立即触发底层数据清理,等于自己把数据杀了。
Kubernetes 的 local PV 不像云盘那样自带“解绑后数据仍保留”的语义,需要先手工编辑 PV 去掉 claimRef 使其从 Released 变为 Available,才能被新 PVC 绑定,步骤是:
kubectl delete deploy <app-name> -n <namespace> kubectl delete pvc <pvc-name> -n <namespace> kubectl edit pv <pv-name> # 删除 spec.claimRef 字段内容 kubectl delete node <node-name> --force --grace-period=0
删除节点时挂起的 finalizer 也需要顺手清理,否则节点对象残留会影响集群的健康状态,这一套操作做下来,节点上的 local PV 就处于“数据还在、绑定已解除”的中间态。
第三步:数据恢复到新节点
新节点做好本地卷目录并创建 PV 后,把中转备份的数据回传过去,如果是同区域多节点之间迁移,用 rsync 比 tar 更高效:
rsync -avP --delete backup-server:/data/volume-backup/ /data/local-storage/
最后重新创建 PVC,Kubernetes 会自动匹配到 Available 状态的 PV。
务必用 workload 自身的数据校验逻辑检查一下记录数或文件哈希,别等到流量切进来才发现数据是坏的。
用开源方案实现排水期间本地卷的不停机处理
如果业务要求排水全程不能中断服务,就需要引入外部工具完成数据搬运,常见组合是 Velero 做备份恢复,或 OpenEBS 做跨节点副本同步。
训练好判断依据:业务数据能接受秒级延迟复制,就用 OpenEBS 的 cStor 副本机制;能接受分钟级停机,Velero 的 File System Backup 就足够。
| 维度 | Velero 备份 | OpenEBS 同步 | 手工备份 |
|---|---|---|---|
| 数据一致性 | 依赖应用自身的持久化机制 | 实时同步 | 依赖停机排空 |
| 恢复时间 | 分钟级 | 秒级 | 小时级 |
| 适用场景 | 定期容灾、版本回滚 | 高可用业务、核心数据库 | 临时维护、无业务要求的场景 |
| 运维复杂度 | 中 | 高 | 低 |
业内专家指出,这种方式适合数据量中等、对 RPO 要求高的业务,恢复验证建议每月做一次,不要等到节点真正故障了才第一次演练。
批量节点的排水策略与局部故障规避
生产环境很少只排一个节点,通常是整批滚动替换,这时候要先给节点打标签分组,避免一次性驱逐过多副本。
kubectl label node node-01 maintenance=2026-01-group1 kubectl get node -l maintenance=2026-01-group1
每次排水不超过集群节点总数的 20%,等前一批 Pod 在剩余节点上 Running 且 Ready 后再操作下一批。如果发现新调度的 Pod 因为资源不足处于 Pending 超过 5 分钟,立刻停止后续批次的排水,先把集群资源水位调整好,节点排水期间本地存储卷的处理节奏最忌讳急躁。
自动化运维中本地卷的安全兜底设计
大规模集群靠手工操作迟早出事故,得有一套自动化的前置检查逻辑,GitOps 思路下可以写一个排水前巡检的脚本,检测逻辑包含:
- 检查节点上是否存在 ReplicaSet 副本数小于期望值的状态
- 检查所有关联 PVC 是否已经有备份任务的历史记录
- 检查节点上的 local PV 是否全部打上了 backup 标签
- 检查工作负载是否有自定义的 preStop hook 完成数据落盘
把排水权限收口到运维平台,不是限制操作自由,而是给团队加一道刹车闸。 所有排操作要留有审计日志,目标节点、执行时间、涉及存储卷、操作人等字段一个不少,近年来不少团队已经开始用 Kyverno 这类策略引擎来强制要求“没有备份标签的节点禁止 drain”,这比约定俗成的规矩可靠得多。
节点排水时本地卷处理常见问题解答
节点排水后 local PV 处于 Released 状态,还能绑定回来吗?
可以,PV 的 reclaimPolicy 是 Retain,数据就还在磁盘上,把 PV 的 claimRef 清掉后,状态会变回 Available,但需要确保新 PVC 的 StorageClass 与 PV 一致,同时节点亲和性也要匹配。
排水时忘了加 –delete-emptydir-data,会阻塞多久?
这会一直阻塞到默认的超时时间,通常是 5 分钟,emptyDir 卷被大量使用,驱逐会被持续拒绝,不过建议不要用强制参数绕过,而是先确认 emptyDir 里真的没有需要留下的数据再做决定,毕竟有些应用会把日志临时写在 emptyDir,一旦强删可能影响后续排障。
节点排水期间,本地存储卷的数据一致性怎么保证?
源码层面能保证的是文件系统数据在驱动层的一致性,应用层的数据一致性还得靠应用自身,最好在容器里配 preStop hook,在收到 SIGTERM 后先执行 flush 操作,把内存里的数据落盘再退出,这样排水过程中的本地卷数据才是一个完整的状态。
节点排水期间本地存储卷的处理,核心就是:数据挪走了再排水,挪不走就备份了再排水,备份不了就停服了再排水。 把这条原则固化到流程和工具里,本地卷就不再是集群维护的软肋,而是你最可控的存储底座。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/776053.html


