news 2026/10/13 3:05:02

Harvester 增强维护模式:用 maintain-mode-strategy 标签精细控制 VM 在节点维护时的行为

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Harvester 增强维护模式:用 maintain-mode-strategy 标签精细控制 VM 在节点维护时的行为
  • 云原生
  • 虚拟化
  • 存储
  • 后端
  • 高可用

【免费下载链接】harvester

Open source hyperconverged infrastructure (HCI) software

项目地址:https://gitcode.com/gh_mirrors/ha/harvester
点击查看免费下载

本文基于 Harvester 仓库中的增强提案 20240605-enhanced-maintenance-mode.md 展开,完整介绍该功能的设计目标、四种维护模式策略、标注方式与验证方法,并结合当前仓库源码(维护模式控制器、drain 控制器、VM 标签同步与 Webhook 校验)剖析每条策略在维护流程中的真实执行路径,帮助读者在 HCI 集群中实现“按需迁移、按需停机、按需重启”的节点维护操作。

背景:传统维护模式的行为过于“一刀切”

Harvester 节点进入维护模式时,系统会尝试把该节点上的所有 VM 迁移(live-migration)到集群内的其他节点,或者在无法迁移时将所有 VM 强制关机。这一行为在部分场景下并不理想,因此引入了本增强:让用户能够逐 VM 显式定义其在节点维护事件中的行为。

该增强不改变 API 结构,核心是通过为VirtualMachine资源添加一个标签来声明策略:

metadata: labels: harvesterhci.io/maintain-mode-strategy: ShutdownAndRestartAfterDisable

标签常量及其合法取值定义在 pkg/util/constants.go:

LabelMaintainModeStrategy = prefix + "/maintain-mode-strategy" // 即 harvesterhci.io/maintain-mode-strategy AnnotationMaintainModeStrategyNodeName = prefix + "/maintain-mode-strategy-node-name" MaintainModeStrategyMigrate = "Migrate" MaintainModeStrategyShutdownAndRestartAfterEnable = "ShutdownAndRestartAfterEnable" MaintainModeStrategyShutdownAndRestartAfterDisable = "ShutdownAndRestartAfterDisable" MaintainModeStrategyShutdown = "Shutdown" MaintainModeStrategyDefault = MaintainModeStrategyMigrate

四种维护模式策略

提案定义了四种策略,语义与源码常量一一对应:

策略值行为典型场景
Migrate(默认)VM 被实时迁移到集群内其他节点。这是增强前维护模式的既有行为,也是默认行为大多数无状态或支持热迁移的负载
ShutdownAndRestartAfterEnable维护模式启用时关机,等节点成功进入维护模式后在另一节点上重启VM 换节点后需要执行停机/开机脚本做初始化动作
ShutdownAndRestartAfterDisable维护模式启用时关机,禁用维护模式后在原节点上重启VM 必须绑定在原节点上运行
Shutdown维护模式启用时关机,不再重启,保持关闭状态维护期间明确不需要运行的 VM

其中Migrate与三个关机类策略的区分逻辑集中在源码中:MaintenanceModeStrategyShutdownValues列表(见 pkg/util/constants.go)收录了三个关机类取值,drain 阶段用这个列表筛选出“必须先关机”的 VM;而Shutdown与另外两个的区别在于是否会被后续流程自动重启——drain 控制器只对ShutdownAndRestartAfterEnable和ShutdownAndRestartAfterDisable两种打“待重启”注解,Shutdown策略的 VM 关机后不会被打注解,也永远不会被自动拉起(对应测试用例 3 中“注解不应存在”的断言)。

典型用户场景(来自提案)

  1. 只关特定 VM 且不重启:将节点放入维护模式时只希望某些 VM 关机,且维护结束后仍保持关闭 —— 使用Shutdown;
  2. 关机后在新节点重启:某些 VM 换节点后必须执行停机/启动脚本(通过关机脚本和开机自启保证)—— 使用ShutdownAndRestartAfterEnable;
  3. 关机后回原节点重启:某些 VM 维护结束后必须回到原节点 —— 使用ShutdownAndRestartAfterDisable。

Force(强制)复选框的覆盖语义

如果在维护模式对话框中勾选了Force,则所有 VM 已配置的maintain-mode-strategy策略都被覆盖:VM 一律被强制关机且保持关闭状态,无论其策略为何值。对于没有该标签的其他 VM,则沿用原有的强制维护行为。

从源码看,这一语义由 nodedrain 控制器 中的forced分支实现:当请求携带强制标记时,FindNonMigratableVMS找出的所有不可迁移 VM 会并入关机清单,与策略类 VM 一起被findAndStopVM统一关机;而RestartMaintenanceModeVMsOnNode的“待重启”注解只有在非强制流程下才会写入,因此强制关机后的 VM 不会被自动恢复。

标注方式:UI 与 kubectl

用户可以通过 Harvester UI 为任意 VM 添加harvesterhci.io/maintain-mode-strategy标签(Edit YAML后在metadata.labels下添加),也可以使用kubectl通过标签过滤器一次性为多个 VM 打标签:

# 将某命名空间中匹配标签选择器的所有 VM 标记为维护时关机且维护结束后重启 kubectl label -n default virtualmachines kubevirt \ harvesterhci.io/maintain-mode-strategy=ShutdownAndRestartAfterDisable --overwrite # 批量查看已配置策略的 VM kubectl get vms -l harvesterhci.io/maintain-mode-strategy --show-labels

注意标签取值大小写必须与常量完全一致。Webhook 会对取值做校验:pkg/webhook/resources/virtualmachine/validator.go 中的checkMaintenanceModeStrategyIsValid会拒绝不在MaintenanceModeStrategyValidValues白名单内的值(返回invalid maintenance mode strategy错误);对未打标签或沿用既有非法值的 VM 则仅记录告警日志,行为按默认Migrate处理,以兼容 Rancher 等集成方可能省略该标签的情况。

实现原理:标签如何驱动维护流程

提案的“Implementation Overview”部分列出了四点设计,以下逐条对应到仓库源码,说明其实际执行链路。维护模式整体由节点上的MaintenanceMode条件驱动一个状态机:Validating → Draining → Evacuating → Completed(失败时进入Error),定义见 pkg/util/maintain.go。

1. 策略标签从 VM 同步到 VMI

标签打在VirtualMachine上,但 drain 过滤器工作于 Pod/VMI 层面。为此,VM 控制器维护了一个“额外标签同步列表”,把harvesterhci.io/maintain-mode-strategy从VirtualMachine同步到VirtualMachineInstance:

// A list of labels that are always automatically synchronized with the // VMI in addition to the instance labels. var syncLabelsToVmi = []string{util.LabelMaintainModeStrategy}

见 pkg/controller/master/virtualmachine/vm_controller.go。提案中说明,这个列表是特意设计成可扩展的,未来其他特性可以往里追加需要同步的标签。

2. drain 阶段:筛选、关机与跳过迁移

当用户通过 UI 或 API 请求启用维护模式时,动作处理器(pkg/api/node/formatter.go)会先校验该节点没有进行中的维护请求,然后写入 drain 请求(含Force标记)。随后 nodedrain 控制器接管,流程为:

  1. 校验(Validating):validate()调用DrainPossible做前置检查,并调用FindNonMigratableVMS找出不可迁移的 VM(包括 Longhorn 卷仅剩一个健康副本且副本恰在本节点、VMI 带VirtualMachineInstanceIsMigratable=False条件、以及 nodeAffinity/nodeSelector 无法满足的 VM,见 pkg/controller/master/nodedrain/nodedrain_controller.go)。非强制模式下若存在不可迁移 VM,维护会以前置检查失败告终,提示使用 force drain。

  2. 关机(Draining):drain() 通过listVMILabelMaintainModeStrategy(L634-L641)按节点列出所有策略取值为三个关机类之一的 VMI,对每一台:

    • 归入关机清单shutdownVMs[MaintainModeStrategyKey],随后统一调用findAndStopVM将对应 VM 的Spec.RunStrategy改为RunStrategyHalted完成优雅关机;
    • 对ShutdownAndRestartAfterEnable/ShutdownAndRestartAfterDisable两种策略,额外在VM(不是 VMI)上写入注解harvesterhci.io/maintain-mode-strategy-node-name: <节点名>,作为“该 VM 需要在维护流程后续阶段被重启、且重启位置由该节点决定”的跟踪标记。这正是提案中“Introduce the annotation … automatically added and removed by the maintenance mode code”的落点(nodedrain_controller.go L229-L240)。
  3. 跳过迁移:随后执行的kubectl drain使用自定义 Pod 过滤器 maintainModeStrategyFilter:如果 Pod 带有kubevirt.io/vmName标签,且其harvesterhci.io/maintain-mode-strategy取值属于关机类,则跳过对该 Pod 的驱逐/迁移,并打印提案中所示的日志:

    time="2024-03-19T12:45:24Z" level=info msg="migration of pod owned by VM test01 is skipped because of the label harvesterhci.io/maintain-mode-strategy" namespace=default pod_name=virt-launcher-test01-gfgjp

    没有标签的其他 VM 的 virt-launcher Pod 则照常被 drain 触发实时迁移,对应 UI 中显示的Migrating状态。

3. 两个“重启时机”的执行位置

提案的两种重启语义由两处不同代码触发,都以“策略标签 + 节点跟踪注解”作为双重筛选条件:

  • 维护模式启用后重启(ShutdownAndRestartAfterEnable):maintain-node-controller 的OnNodeChanged在节点处于Evacuating阶段时轮询(每 10 秒)确认该节点上已无任何 VMI,然后调用RestartMaintenanceModeVMsOnNode(..., ShutdownAndRestartAfterEnable)重启这些 VM,最后把条件推进到Completed(即 UI 上的Maintenance状态)。此时节点已被 cordon,KubeVirt 重新调度 VM 自然会落在其他节点——这解释了测试用例 2 中“VM 重启在了别的节点,且明确不是被迁移的”。
  • 维护模式禁用后重启(ShutdownAndRestartAfterDisable):用户在 Hosts 页面禁用维护模式时,API 动作处理器在解除 cordon、清理 drain 请求之后,调用 disableMaintenanceMode 中的RestartMaintenanceModeVMsOnNode(..., ShutdownAndRestartAfterDisable),再移除维护条件。VM 被重新调度回记录在注解中的原节点。

两个路径共用的 RestartMaintenanceModeVMsOnNode 函数行为值得注意:它只重启当前处于Halted运行策略的 VM;重启时优先恢复关机前保存在注解中的原运行策略(AnnotationRunStrategy),否则回退为RunStrategyRerunOnFailure;处理完成后删除maintain-mode-strategy-node-name注解,避免重复触发。

4. 节点删除时的注解清理

提案测试用例 5 覆盖了一个边界场景:VM 关机后节点被直接删除。maintain-node-controller 的OnNodeRemoved会遍历所有 VM,删除那些注解maintain-mode-strategy-node-name仍指向已删除节点的资源,防止“悬空”注解在将来同名节点上引发误重启。

验证方法(Test Plan)

提案给出了 5 个完整的手工测试用例,以下完整保留其操作要点,可作为功能验收与自测清单。前提:两台(或更多)VM 运行在同一节点,一台打了策略标签,另一台不打标签(作为对照组,预期走实时迁移)。

用例 1:ShutdownAndRestartAfterDisable

  1. 为选定 VM 打标签harvesterhci.io/maintain-mode-strategy: ShutdownAndRestartAfterDisable(UI 的Edit YAML或 kubectl)。
  2. 确保同节点上还有一台无标签的 VM 在运行,必要时把它迁移过来。
  3. 记录两台 VM 所在的节点。
  4. 在Hosts页对目标节点选择Enable Maintenance Mode动作。
  5. 一段时间后该节点应显示Cordon状态。
  6. 在Virtual Machines页,带标签的 VM 应显示Stopping状态徽标,另一台 VM 应显示Migrate徽标。
  7. 关机后,通过Edit YAML确认该 VM 的注解中存在harvesterhci.io/maintain-mode-strategy-node-name: <NODENAME>。
  8. 回到Hosts页,节点应(过一段时间后)显示Maintenance状态徽标。
  9. 通过节点动作菜单禁用维护模式,一段时间后Maintenance Mode徽标消失。
  10. 在Virtual Machines页,之前被关机的 VM 应已再次启动。

harvester-xxx-xxxPod 的日志中应能看到类似:

time="2024-03-19T12:45:24Z" level=info msg="attempting to place node in maintenance mode" node_name=harvester-node-2 time="2024-03-19T12:45:24Z" level=info msg="force stopping VM" namespace=default virtualmachine_name=test01 time="2024-03-19T12:45:24Z" level=info msg="migration of pod owned by VM test01 is skipped because of the label harvesterhci.io/maintain-mode-strategy" namespace=default pod_name=virt-launcher-test01-gfgjp time="2024-03-19T12:55:37Z" level=info msg="restarting the VM that was shut down in maintenance mode" namespace=default virtualmachine_name=test01

用例 2:ShutdownAndRestartAfterEnable

步骤 1–8 同用例 1,仅标签值改为ShutdownAndRestartAfterEnable;关键差异在第 9–11 步:

  1. 在Virtual Machines页,被关机的 VM 应在维护模式启用完成(Maintenance徽标出现)后自动重启,并且运行在与之前不同的节点上——注意它是“关机+重启”而非迁移。
  2. 在Hosts页禁用维护模式。
  3. 两台 VM 应继续运行,且所在节点不再发生变化(重启时机已过,禁用维护模式不应再触发调度)。

日志中应出现restarting the VM that was temporary shut down for maintenance mode一类信息(本仓库当前实现中对应 pkg/util/maintain.go 打印的Restarting VM that was shut down for maintenance mode,字段为namespace/name/runStrategy)。

用例 3:Shutdown

  1. 打标签harvesterhci.io/maintain-mode-strategy: Shutdown,其余设置同用例 1。
  2. 启用维护模式后,带标签 VM 显示Stopping,对照 VM 显示Migrate。
  3. 关机后通过Edit YAML确认注解中不存在harvesterhci.io/maintain-mode-strategy-node-name(因为该策略无需重启跟踪)。
  4. 节点进入Maintenance状态后,带标签 VM 保持Off,对照 VM 已被迁移到另一节点。
  5. 禁用维护模式后,带标签 VM仍然保持关闭。
  6. harvester-xxx-xxxPod 日志中不应出现任何restarting the VM that was ... shut down in maintenance mode记录。

用例 4:Force 覆盖策略

  1. 打标签ShutdownAndRestartAfterDisable,并保证同节点有一台无标签 VM。
  2. 在内置 Longhorn UI 的Volume页将该 VM 的卷副本数降为 1,并删除所有不在待维护节点上的副本——构造“不可迁移”场景。
  3. 启用维护模式时勾选Force复选框(注意它会覆盖所有 VM 的维护策略,这正是本用例要验证的)。
  4. 节点进入Cordon后,两台 VM 都应显示Stopping,随后都处于Off。
  5. 禁用维护模式后两台 VM 都应保持关闭。
  6. 检查被打过ShutdownAndRestartAfterDisable标签的 VM,注解中不应存在maintain-mode-strategy-node-name。
  7. 注意由于 Longhorn 副本被删除导致部分 Pod 无法 drain,该节点实际上无法切换到Maintenance Mode完成态——这正是强制模式的预期表现。
  8. 日志中不应出现任何自动重启记录。

用例 5:节点删除后注解清理

  1. 打标签ShutdownAndRestartAfterDisable,记录 VM 所在节点。
  2. 启用维护模式,确认 VM 关机且注解中存在maintain-mode-strategy-node-name: <NODENAME>,节点进入Maintenance状态。
  3. 删除该节点(可能需要一些时间)。
  4. 节点删除完成后检查该关机 VM:注解maintain-mode-strategy-node-name应已被 OnNodeRemoved 逻辑清除。

小结

Harvester 的增强维护模式用“一个标签 + 一个注解”的轻量设计,把节点维护时 VM 的处置方式从二选一(迁移或强制关机)细化为四种可编排的策略:

  • 默认Migrate保持向后兼容;
  • 三个关机类策略在 drain 前通过RunStrategyHalted优雅关机,并由 drain 过滤器跳过其 Pod 的迁移;
  • 两个“RestartAfter…”策略借助系统自动维护的节点跟踪注解,分别在维护模式启用完成时(maintain-node-controller)与维护模式禁用时(node 动作处理器)精准重启,重启后恢复原运行策略;
  • Force复选框始终拥有最高优先级,可无条件强制关机;
  • Webhook 校验保证标签取值合法,节点删除时的注解清理避免悬空状态。

相关源码入口汇总:常量定义 pkg/util/constants.go、drain 主流程 pkg/controller/master/nodedrain/nodedrain_controller.go、Pod 迁移过滤 pkg/util/drainhelper/helper.go、标签同步 pkg/controller/master/virtualmachine/vm_controller.go、重启逻辑 pkg/util/maintain.go、策略校验 pkg/webhook/resources/virtualmachine/validator.go。

  • 云原生
  • 虚拟化
  • 存储
  • 后端
  • 高可用

【免费下载链接】harvester

Open source hyperconverged infrastructure (HCI) software

项目地址:https://gitcode.com/gh_mirrors/ha/harvester
点击查看免费下载

相关推荐

上一篇:RCA Capture
下一篇:Valibot 迁移指南:用 @valibot/zod-to-valibot Codemod 将 Zod 模式自动转换为 Valibot

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/13 3:03:31

MySQL行转列实战:从CASE WHEN到动态SQL的完整攻略

做过报表开发的人几乎都撞上过同一个场景&#xff1a;业务表里明明是一行接一行的明细数据&#xff0c;领导却偏偏要一张横着铺开的宽表&#xff0c;季度在旁边排开、门店在头顶列队、指标一个个填进单元格。我第一次被这个问题卡住的时候&#xff0c;是在一个模拟订单系统里跑…

作者头像 李华
网站建设 2026/10/13 3:03:04

市场观察|信创国产化排队叫号系统采购参考:如何甄别靠谱供应商?

一、验收标准变了政务信创改造推进到现在&#xff0c;排队叫号系统的验收标准已经从“终端能跑”升级为全链路国产化适配。服务器、操作系统、数据库、终端硬件&#xff0c;每一层都要有据可查&#xff0c;合规审计时需提供对应的适配证明。市面上不少产品宣称“支持信创”&…

作者头像 李华
网站建设 2026/10/13 3:02:47

具身智能创新原理(8):赋予具身“原生大脑”深度思考的能力

前沿技术探索&#xff1a;TVA智能体&#xff08;简称TVA&#xff09;TVA智能体&#xff08;亦称“AI智能体视觉”&#xff09;是依托Transformer架构与“因式智能体”理论构建的新型工业视觉系统&#xff0c;也是当前最具代表性的具身视觉技术之一。它有机融合深度强化学习&…

作者头像 李华
网站建设 2026/10/13 3:02:47

深度学习-极验叠字点选-yolo-模型调优-高阶数学-opencv

一、引言&#xff1a;叠字点选验证码的对抗本质极验叠字点选与传统点选验证码的差异&#xff1a;字形重叠、语义干扰、动态渲染深度学习破解的总体技术路线&#xff1a;目标检测 语义匹配 色彩处理文章目标&#xff1a;聚焦YOLO系列模型在叠字场景下的检测精度提升与数学优化方…

作者头像 李华
网站建设 2026/10/13 3:02:13

短剧硬字幕如何批量 OCR:从字幕区到整剧校对

短剧硬字幕如何批量 OCR&#xff1a;从字幕区到整剧校对 先说结论 先抽取开场、普通对白、运动背景和多人场景&#xff0c;分别标出对白字幕、片名、花字与弹幕区域。固定字幕区可批量识别&#xff0c;移动或重叠文字要分组处理。输出后按集序校对时间轴、人名、断句和重复帧&a…

作者头像 李华
网站建设 2026/10/13 3:01:56

Topview Motion Studio 技术深度剖析:面向产品叙事的 AI 动态视频生成系统

摘要传统产品发布视频、动态宣传片生产链路高度依赖 After Effects、专业动态设计团队、三维动画管线&#xff0c;完整交付周期长、人力成本高、迭代修改成本巨大。Topview Motion Studio 并非简单的文本生成视频工具&#xff0c;而是一套面向动态图形&#xff08;Motion Graph…

作者头像 李华