Pod 迁移及虚拟机节点异常关闭恢复

问题描述

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

原因分析

平台基于开源组件 KubeVirt 实现虚拟机方案,但从 KubeVirt 角度无法区分虚拟机真实宕机和网络等原因导致的连接失败。如果盲目将虚拟机迁移到其他节点,可能导致同一虚拟机存在多个实例。

解决方案

维护虚拟机节点时,需按照本文档进行手动操作。无论是正常关闭还是异常宕机,虚拟机 Pod 都必须手动驱逐或强制删除。

注意:以下命令需在对应集群的主节点上执行。

正常关闭时虚拟机 Pod 迁移

  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>  # 将命令中的 <Node-Name> 替换为步骤 1 中获取的 Node-Name

    输出:

    test-test         vm-t-export-clone   13d     Running      1.1.1.1   1.1.1.211   True    False   
  3. 在正常关闭前,执行以下命令驱逐即将关闭节点上的所有虚拟机 Pod,若输出如下则表示驱逐成功。

    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. 此时,该节点上原有的虚拟机实例已迁移至其他健康节点,节点重启后可用于新的 Pod 调度。

异常关闭恢复

  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. 执行以下命令强制删除该节点上的所有虚拟机 Pod。

    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 的 Pod。

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

    若存在,执行以下命令删除这些 Pod。

    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 的 Pod。

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

    若存在,执行以下命令删除这些 Pod。

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