节点排水(kubectl drain)不会直接删除本地存储卷的数据,但会把承载本地卷的 Pod 强制驱逐,导致 PVC 与 PV 陷入“数据还在、应用起不来”的僵局,必须提前规划数据迁移或重建策略。
节点排水对本地存储卷的影响:数据会不会丢
本地存储卷(Local PersistentVolume)与云盘最大的区别在于,它和节点是强绑定的,PVC 一旦绑定了某个节点的 Local PV,这个 PV 的 nodeAffinity 就锁死了调度范围,换句话说,数据不会因为排水而自动消失,但应用会因为节点不可调度而无法在其他机器上恢复运行。
Pod 被驱逐但 PV 还在,新 Pod 却起不来
执行 kubectl drain 时,kubelet 会依据 PodDisruptionBudget 和驱逐宽限期依次终止节点上的 Pod,对于使用 Local PV 的 Pod,驱逐动作本身只是“杀掉容器”,并不会触发 PV 的删除逻辑。
问题出在驱逐之后:
- 原节点被置为不可调度(cordon),Pod 被迫重建。
- 重建时调度器看到 PVC 绑定的 PV 带有 nodeAffinity,目标节点只能是原节点。
- 原节点处于排水状态,Pod 一直 Pending,直到排水完成或节点恢复。
local PV 的回收策略通常是 Retain,这一点和默认的 Delete 策略完全不同,Retain 意味着 PVC 被删掉后,PV 和底层数据目录会保留,但 PV 会进入 Released 状态,无法被直接重新绑定,要恢复使用,必须手动清理 PV 对象,或者重建 PV 并重新指向原数据目录。
什么时候数据会真丢
有三种常见情况会造成本地卷数据实际丢失:
- 节点发生了不可逆的硬件故障,磁盘数据无法读取。
- 排水的后续操作中,有人手动删除了本地数据目录,
/mnt/disks/vol1。 - 节点重新加入集群时,kubelet 的 storage 清理逻辑误删了挂载点下的内容。
行业共识认为,本地存储卷默认不具备跨节点数据冗余能力,单副本本身就是最大的风险点,不管排水操作是否执行,只要数据只存在一块盘上,就谈不上真正的数据安全。
节点排水前本地盘数据迁移的实操检查清单
排水前最忌讳直接敲 kubectl drain node-1,尤其是集群里跑着有状态服务的时候,下面这几步能帮你把风险降到可接受的范围。
第一步:确认 PVC 生命周期与回收策略
kubectl get pv -o custom-columns=NAME:.metadata.name,CAPACITY:.spec.capacity.storage,RECLAIM:.spec.persistentVolumeReclaimPolicy,STATUS:.status.phase,CLAIM:.spec.claimRef.name
看到 RECLAIM 列是 Retain 时,说明 Pod 被驱逐后数据会留在原节点,如果是 Delete,则意味着删除 PVC 会触发放存储清理,不过实际场景中,Local PV 的 provisioner 配置不规范时,PV 的回收策略可能是默认的 Delete,这时候就要格外小心。

kubectl get pvc -n <namespace> 确认 PVC 目前是 Bound 状态,PVC 已经是 Lost 或 Released,排水操作会进一步让恢复变复杂。
第二步:备份优先,快照与远程拷贝二选一
节点排水期间想要保住数据,最稳妥的办法是先把数据拷走,以下两条路径任选:
- 直接拷贝业务数据目录:找到 PV 对应的宿主机路径,执行
rsync -avP /mnt/disks/vol1/ backup-server:/data/vol1/,操作前先停写或降级写入。 - 用业务层复制机制:比如数据库的主从复制、分布式存储的多副本,先在其他节点拉起新实例,再触发排水。
依赖云厂商快照功能来“保护”本地盘意义不大,因为本地盘不等同于云盘,快照功能通常不适用于直通盘或本地 NVMe 盘。
第三步:按业务重要性选排水方式
如果业务可以接受短暂停摆,直接执行:
kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data
排完后节点上的本地盘数据目录仍在,等节点维护完毕,执行:
kubectl uncordon <node-name>
原先被驱逐的 Pod 会因为 nodeAffinity 仍然指向该节点,但调度器会等节点重新可用后把 Pod 调度回去。前提是 Pod 的 PVC 还在,且 PVC 没有被人为删除。
如果业务要求不能中断,则需要手动将工作负载迁移到其他节点,完成后再排水。
节点排水后 Local PV 无法恢复的处置路径
有些场景下,节点排水后发现 PV 虽然还在,但 PVC 已经找不到了,或者 PV 状态变成了 Released,这时候需要手动介入。
PV 进入 Released 状态时的恢复技巧
PVC 被删除后,Local PV 会进入 Released 状态,此时需要手工重建 PV,或者用脚本清理并重新发布,步骤如下:
- 确认数据目录还在原节点上。
- 保存旧的 PV 描述:
kubectl get pv <pv-name> -o yaml > pv-backup.yaml - 删除旧 PV:
kubectl delete pv <pv-name> - 编辑
pv-backup.yaml,移除claimRef中的 UID,保留nodeAffinity。 - 重新创建 PV:
kubectl create -f pv-backup.yaml - 创建或复用原有的 PVC,确认 PVC 的 selector 能匹配到新 PV。
很多人在第四步卡住,因为不清理 claimRef 的话,PV 会一直显示 Released,无法再次绑定。
节点排水本地盘数据迁移到新节点的折腾方案
如果原节点彻底回不来了,且本地数据没有备份,那就陷入了一个现实困局:数据在坏节点或不可用节点的磁盘上,无法迁移,此时只能接受数据丢失,恢复应用时用存储在其他位置的数据源重新初始化。

业内专家指出,这类事故多发生在没有为本地卷建立跨节点冗余的集群中,节点异常是压死骆驼的最后一根稻草。
云服务器节点维护本地盘数据备份的替代思路
本地存储卷适合对性能敏感、对数据可靠性要求没那么严苛的场景,比如大数据分析和临时计算任务,对于核心业务库里核心数据,直接用 Local PV 承担主存储的角色并不合理。
本地盘与分布式存储的选型对比
| 维度 | Local PV | 分布式存储(Ceph/GlusterFS) |
|---|---|---|
| 性能 | 极高,直通本地盘 | 中等,有网络开销 |
| 数据冗余 | 无,依赖上层复制 | 有,多副本 |
| 节点排水影响 | 必须手动处理数据 | 自动 rebalance |
| 运维复杂度 | 低 | 高 |
| 适用场景 | 中间数据、缓存、临时结果集 | 核心业务持久化数据 |
如果你在考虑“Kubernetes节点维护时本地盘数据会不会受影响”这类问题,答案取决于你选择的是哪一种存储方案,Local PV 天然受影响,分布式存储天然免疫。
用拓扑约束或节点亲和绕开维护窗口
如果你不想迁移数据,又必须对某台云服务器做硬件维护,可以尝试把 Pod 调度强绑定到该节点上,利用停机窗口短暂停服后直接重启,这种方式适合开发环境或非核心业务。
对于核心业务,行业通行的做法是:在业务上层做多副本,让 Pod 分布在不同节点上,维护前把某一个副本驱逐走,完成一轮滚动,这个过程也依赖 PodDisruptionBudget 来保证同一个服务的多个副本不会同时被驱逐。
本地存储卷应用高可用如何设计
如果看完前面的内容你意识到本地卷的脆弱性,下一步应该讨论怎么设计高可用架构。
针对本地卷的应用层复制方案
- 数据库类应用:使用主从复制,主库带 Local PV,从库放到另一节点的 Local PV,业务读写走主库,主库节点排水时手动或自动切到从库。
- 消息队列类应用:Kafka、Pulsar 这类系统天然支持多副本跨节点分布,数据副本并不依赖单节点 Local PV 的可靠性。
- 文件存储类应用:用 MinIO 网关或 JuiceFS 等把数据底层放到对象存储,本地盘只做缓存或热数据层。
一些行之有效的运维策略
- 尽量把所有有状态服务的副本数设置成大于 1,且不要把所有副本放到同一节点。
- 给 Pod 设置合理的
terminationGracePeriodSeconds
,保证排水时容器内的进程有足够时间优雅退出并 flush 数据。
- 在节点排水前给关键服务打一个
preStop钩子,执行sync或触发远端备份。 - 定时巡检 PV 的
nodeAffinity与 PVC 的绑定关系,避免出现跨节点绑定的隐性配置错误。
这里再激进地说一点:如果一组数据真的重要到丢失会出大事,那它就不该只待在单块本地盘上,本地存储的定位应该是“高性能缓存”或者“可重建的临时结果”,而不是“唯一真相源”,把这条规则刻进脑子里,节点排水问题对你的冲击会小一大半。
节点排水期间本地存储卷处理的最优顺序
运维操作中,操作顺序直接决定成败,下面给出一套在多数情况下都能跑通的最佳顺序:
- 确认节点角色和节点上运行的工作负载类型:
kubectl get pods -A -o wide | grep <node-name> - 标记节点不可调度:
kubectl cordon <node-name> - 检查哪些 Pod 使用了 Local PV:
kubectl get pvc -A | grep Bound - 备份关键数据或通知业务方进行数据校验。
- 驱逐非本地卷 Pod:
kubectl drain <node-name> --ignore-daemonsets --force - 手动迁移使用 Local PV 的 Pod(删除后新建到其他节点,或先等待节点恢复)。
- 执行节点维护操作。
- 恢复节点:
kubectl uncordon <node-name> - 确认原先的 Pod 是否成功调度回原节点,必要时重建 PVC 以重新绑定到原 PV。
这个流程的核心原则是:先把风险暴露出来,再执行破坏性操作,最后才动节点,反过来操作,大概率会出事。
常见问题解答
kubectl drain 之后本地 PVC 数据会丢吗?
不会直接丢,drain 触发的是 Pod 驱逐,不影响 PV 和底层数据目录,只有 reclaimPolicy 为 Delete 且 PVC 被删除,或者数据目录被手动清理,数据才会真正丢失,节点若发生物理故障,单副本数据同样无法找回。
节点排水和节点维护有什么区别?
节点排水是把节点上的 Pod 清空并标记不可调度,通常用于节点下线、硬件维修或内核升级,节点维护是一个更宽泛的概念,可能不做任何 Pod 驱逐,只对节点进行重启或配置变更,排水是维护的一种前置动作,核心区别在于是否触发工作负载迁移。
本地存储卷的 Pod 为什么在节点排水后一直 Pending?
因为 PV 的 nodeAffinity 只允许调度到原节点,而原节点处于 cordon 状态,调度器找不到任何满足条件的节点,Pod 就自然停在 Pending,等节点 uncordon 后,若 PVC 仍存在且 PV 状态正常,Pod 会自动调度回去,若 PV 状态变为 Released,则需要手动重建 PV 对象来恢复绑定关系。