节点排水期间,本地存储卷绑定的Pod不会自动迁移到其他节点,正确做法是先识别Local PV并做好备份或容忍策略,否则业务会直接陷入Pending状态。
节点排水期间本地存储卷会丢数据吗?
先给一个明确结论:多数情况下,节点排水不会删除本地存储卷里的数据,但会让使用这些卷的Pod无法在新节点上重新运行。
本地存储卷在Kubernetes里主要有两类:hostPath和Local Persistent Volume,它们共同的特点是数据实际存放在某个节点的本地磁盘上,而不是像云盘那样独立于节点存在,当执行kubectl drain时,Kubernetes会尝试驱逐节点上的所有Pod,对于使用云盘的Pod,新节点挂载同一个云盘即可恢复;但对于使用Local PV的Pod,PV对象里记录了节点亲和性,只能调度回原来那个节点,原节点已经被封锁,新节点又不满足亲和性规则,Pod自然就卡在Pending。
数据本身并没有消失,只要节点没有重装系统、没有删除磁盘分区、没有执行wipefs之类的操作,本地数据仍然躺在原路径下,但这不代表业务安全,数据活着,服务用不了,在生产环境里和丢数据一样致命。
行业共识认为,本地存储卷适合对IO吞吐极高、且能接受单节点故障影响的场景,比如消息队列、日志采集、临时计算缓存,真正有状态强一致性要求的业务,多数情况下不会把Local PV当作第一选择。
生产环境节点排水本地存储卷和云盘对比怎么选?
这个对比直接影响节点维护时的操作复杂度,把两者放一起看,差异非常直观。
| 维度 | 本地存储卷 | 云盘 |
|---|---|---|
| 数据物理位置 | 绑定节点本地磁盘 | 独立于节点的块存储 |
| 节点排水后Pod调度 | 无法跨节点调度,必现Pending | 自动挂载到新节点,正常恢复 |
| 数据丢失风险 | 节点重装或磁盘故障即丢失 | 云盘通常有多副本机制 |
| 迁移成本 | 需手动备份和恢复 | 几乎零迁移 |
| 单机IO性能 | 极高,接近裸盘 | 受网络和云盘性能限制 |
| 单位成本 | 服务器本地盘已包含在硬件成本中 | 按容量和IOPS计费 |
从表格能看出:节点排水期间,本地存储卷最大的麻烦不是数据丢失,而是调度死锁。 云盘之所以省心,是因为它把存储从计算节点上拆了出来,在Kubernetes官方文档关于Local Persistent Volumes的说明里也明确提到,Local PV适用于需要低延迟、高吞吐的应用,但会牺牲跨节点的可移植性。
如果你运行的集群在华北机房或华东裸金属服务器上,本地NVMe盘性能确实诱人,但每次节点维护都要为这份性能付出额外操作成本,反过来,云盘集群做排水时,通常一条kubectl drain命令加上等待时间就够了。
Kubernetes节点排水本地存储卷处理步骤
下面给出生产环境里可验证的具体操作流程,按顺序执行即可。
找出使用本地存储卷的Pod
先确认哪些工作负载依赖本地盘,避免盲目排水。
kubectl get pv -o wide | grep -E 'local|hostPath' kubectl get pods -A -o wide | grep <节点名>
进一步查看Pod的Volume配置:
kubectl get pod <pod名> -n <命名空间> -o yaml | grep -A 5 volumes
如果Volume类型是hostPath或persistentVolumeClaim且对应StorageClass为local-storage,这个Pod就属于重点保护对象。
配置PodDisruptionBudget
在排水前给关键业务加一道保险,PodDisruptionBudget可以限制同时不可用的副本数,防止全部Pod被一次性驱逐。
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: local-app-pdb
spec:
minAvailable: 1
selector:
matchLabels:
app: local-app
这个配置能保证至少有一个副本始终运行,但要注意,PDB只对自愿中断生效,手动执行kubectl drain属于自愿中断,所以会遵守规则。
执行cordon与drain
先封锁节点,禁止新Pod调度上去:
kubectl cordon <节点名>
再执行排水,对于本地存储卷Pod,需要加上--ignore-daemonsets和--delete-emptydir-data参数:
kubectl drain <节点名> --ignore-daemonsets --delete-emptydir-data --grace-period=60
如果Pod无法被正常驱逐,可以加--force,但这会跳过优雅终止过程,有状态应用可能因此写坏数据。生产环境不建议对数据库类Pod使用--force。
排水命令完成后,再次查看Pod状态:
kubectl get pods -A -o wide | grep -E 'Pending|Terminating'
本地卷Pod大概率会出现在Pending列表里,这不是故障,而是预期行为。
数据备份与迁移
如果节点必须下线维护,需要把本地数据迁走,常见做法有两种:
- 使用
rsync把数据目录同步到另一台节点的相同路径,然后手动创建新的Local PV指向新节点。 - 临时把应用的数据目录挂载到云盘,用云盘作为过渡存储,等原节点恢复后再切回。
同步命令示例:
rsync -avz /data/local-pv/ root@<目标节点IP>:/data/local-pv/
迁移完成后,需要修改PV定义里的nodeAffinity,让它匹配新节点的hostname或标签,否则Pod仍然无法调度。
本地存储卷迁移成本高吗?华东机房实操参考
迁移成本按场景拆开看,大头在人力操作和停机时间,而不是软件授权费用,Local PV本身不涉及额外软件采购,但每一次迁移都需要人工介入,步骤多,出错概率也不低。
在华东机房的裸金属集群中,相当一部分团队会采用“本地盘+对象存储备份”的混合方案,平时数据定期异步备份到对象存储,节点排水时只接受短暂不可用,不做实时迁移,这样操作的硬件成本几乎为零,但RTO以小时计,如果业务不能接受小时级中断,那就需要引入云盘或分布式存储,成本自然上升。
从价格维度看,云盘按容量和IOPS计费,本地盘一次性投入包含在服务器采购里,但把维护人力算进去,本地存储卷的长期运维成本并不一定便宜,多数情况下,只有对延迟极度敏感、且副本机制已经做得很完善的应用,才会继续选择本地盘。
Q&A:节点排水期间本地存储卷常见问题
节点排水时local pv pod一直Pending怎么处理?
先确认原节点是否已经cordon,如果原节点还处于Ready状态,可以执行kubectl uncordon <节点名>解除封锁,让Pod调度回原节点,如果原节点已经下线,则必须修改Local PV的nodeAffinity字段,指向一台新的可用节点,并确保数据已经通过rsync等方式同步到新节点对应路径,修改后删除Pending Pod,让其重新创建。
节点排水期间本地存储卷和云盘对比哪个更稳定?
稳定性不能一概而论,本地存储卷在单节点内性能稳定,但节点故障或维护时可用性会明显下降,云盘的稳定性依赖云厂商的存储集群,通常具备多副本容错能力,跨节点迁移时表现更稳定,如果业务本身有完善的副本和故障转移机制,本地盘也能提供足够的整体稳定性。
kubectl drain卡住不结束是什么原因?
多数情况下是因为有Pod无法被正常驱逐,比如缺少PodDisruptionBudget放行、存在静态Pod、或者本地卷Pod的终止钩子迟迟不返回,可以通过kubectl describe pod <pod名>查看事件,如果确认业务可以中断,使用--force --grace-period=0强制结束,但需要自行承担数据不落盘的风险。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/640843.html





