虚拟机节点正常关机下的 Pod 迁移及异常宕机恢复问题

问题描述

无论节点是 正常关机 还是 异常宕机,运行在该节点上的虚拟机 Pods 都不会自动迁移至其他健康节点。

原因分析

平台基于开源组件 KubeVirt 实现了虚拟机解决方案。然而,从 KubeVirt 的角度来看,无法区分虚拟机是实际宕机还是由于网络或其他原因导致的连接失败。若不加区分地将虚拟机迁移至其他节点,可能导致同一虚拟机的多个实例同时存在。

解决方法

在维护虚拟机节点时,需要根据此文档进行手动操作。针对 正常关机异常宕机 两种情况,需手动驱逐或强制删除虚拟机 Pods。

注意:下述命令均需在对应集群的 Master 节点上执行。

正常关机下的虚拟机 Pods 迁移

  1. 在 CLI 工具中,执行下述命令获取节点信息。其中,回显信息中的 NAME 字段即为 Node-Name

    kubectl get nodes

    回显信息:

    NAME             STATUS   ROLES                  AGE   VERSION
    1.1.1.211   Ready    control-plane,master   99d   v1.28.8
  2. (可选)执行下述命令查看节点下的虚拟机实例。

    kubectl get vmis --all-namespaces -o wide | grep <Node-Name>  # 使用步骤 1 中获取的 Node-Name 替换命令中的 <Node-Name> 部分

    回显信息:

    test-test         vm-t-export-clone   13d     Running      1.1.1.1   1.1.1.211   True    False   
  3. 正常关机前,执行下述命令驱逐需关机节点上的所有虚拟机 Pods,若出现如下回显信息,则表示已成功驱逐。

    kubectl drain <Node-Name> --delete-local-data --ignore-daemonsets=true --force --pod-selector=kubevirt.io=virt-launcher   # 使用需关机节点的 Node-Name 替换命令中的 <Node-Name> 部分

    回显信息:

    Flag --delete-local-data has been deprecated, This option is deprecated and will be deleted. Use --delete-emptydir-data.
    node/1.1.1.211 cordoned
    evicting pod test-test/virt-launcher-vm-t-export-clone-hmnkk
    pod/virt-launcher-vm-t-export-clone-hmnkk evicted
    node/1.1.1.211 drained
  4. 等所有虚拟机在其他节点上启动后,将节点关闭。

  5. 节点关机并重新开启后,执行下述命令将该节点标记为可调度。

    kubectl uncordon <Node-Name> # 使用关机并重启节点的 Node-Name 替换命令中的 <Node-Name> 部分

    回显信息:

    node/1.1.1.211 uncordoned
  6. 至此,该节点上的原虚拟机实例已迁移至其他健康节点,该节点重启后已允许新的 Pods 调度。

异常宕机恢复

  1. 在 CLI 工具中,执行下述命令获取节点信息。其中,回显信息中的 NAME 字段即为 Node-Name

    kubectl get nodes

    回显信息:

    NAME             STATUS   ROLES                  AGE   VERSION
    1.1.1.211   Ready    control-plane,master   99d   v1.28.8
  2. 执行下述命令,强制删除该节点上的所有虚拟机 Pods。

    kubectl get po -A -l kubevirt.io=virt-launcher -o wide | grep <Node-Name> | awk '{print "kubectl delete pod --force -n " $1, $2}'  | bash  # 需使用异常宕机节点的 Node-Name 替换命令中的 <Node-Name> 部分
  3. 执行下述命令删除该节点上的 volume attachments。

    kubectl get volumeattachments.storage.k8s.io | grep <Node-Name> | awk '{print $1}' | xargs kubectl delete volumeattachments.storage.k8s.io  # 需使用异常宕机节点的 Node-Name 替换命令中的 <Node-Name> 部分
  4. 执行下述命令查询异常宕机节点上是否存在具有标签 kubevirt.io=virt-api 的 Pods。

    kubectl -n kubevirt get po -l kubevirt.io=virt-api -o wide | grep <Node-Name> # 需使用异常宕机节点的 Node-Name 替换命令中的 <Node-Name> 部分

    若存在则执行下述命令删除 Pods。

    kubectl -n kubevirt get po -l kubevirt.io=virt-api -o name | xargs kubectl -n kubevirt delete --force --grace-period=0
  5. 执行下述命令查询异常宕机节点上是否存在具有标签 kubevirt.io=virt-controller 的 Pods。

    kubectl -n kubevirt get po -l kubevirt.io=virt-controller -o wide | grep <Node-Name> # 需使用异常宕机节点的 Node-Name 替换命令中的 <Node-Name> 部分

    若存在则执行下述命令删除 Pods。

    kubectl -n kubevirt get po -l kubevirt.io=virt-controller -o name | xargs kubectl -n kubevirt delete --force --grace-period=0
  6. 至此,节点异常宕机后,虚拟机实例将迁移至其他健康节点。