
# 如何根据Cluster节点故障自动恢复业务
AI服务器单点硬件故障不可避免，在大规模算力使用场景下，资源池规模越大存在硬件故障的可能性越高。当发生硬件故障时可能会影响节点上服务的正常运行。
轻量算力集群节点巡检到故障后，会上报故障信息到k8s节点和AOM云服务，详情请见[Cluster节点故障上报]。ModelArts提供故障感知、通知能力，配合业务在原生k8s中进行快速恢复。
针对故障节点信息，自动恢复业务的解决方案大致流程如下：
[步骤1：获取故障节点信息]（以Watch k8s节点方式为例）
[步骤2：用Taint隔离集群中的故障节点]
[步骤3：重新下发业务]
自动恢复业务后，处理故障节点请参见[如何定位和处理Cluster资源池节点故障](https://support.huaweicloud.com/trouble-modelarts/modelarts_13_0287.html)。
 #### Cluster节点故障上报
对于ModelArts 轻量算力集群资源池，每个节点会以DaemonSet方式部署node-agent组件。
如果是GPU资源池会同时安装node-agent组件和gpu device-plugin组件。如果是NPU资源池则是会同时安装node-agent组件和npu device-plugin组件。
节点故障上报如[图1]所示。
图1节点故障上报   
![](https://support.huaweicloud.com/trouble-modelarts/figure/zh-cn_image_0000002607112397.png "点击放大")
故障感知：device-plugin负责xpu卡的故障巡检，node-agent负责AI运行环境的巡检。 device-plugin组件会从驱动侧获取芯片故障并实时上报可用卡数到K8S NodeAllocatable，同时，对使用NPU卡的k8s Pod，device-plugin会自动为其挂载npu状态文件可用于pod内进行健康检查。node-agent组件则是通过巡检脚本收集各故障信息，同时将检测结果汇聚并写到K8S NodeCondition中。
故障通知：node-agent收集到巡检结果后，会周期性上报节点故障指标到AOM服务，配置及时通知方法可参见[如何定位和处理Cluster资源池节点故障](https://support.huaweicloud.com/trouble-modelarts/modelarts_13_0287.html)
K8S Node Allocatable以及Condition详情可参考[Kubernetes节点状态](https://kubernetes.io/zh-cn/docs/reference/node/node-status/)。
```
K8S NodeCondition样例：
{
"type": "NT_NPU_CARD_LOSE",
"status": "False",
"lastHeartbeatTime": null,
"lastTransitionTime": "2024-09-27T10: 45: 55Z",
"reason": "os_task_name:npu-card-lose",
"message": "ok"
}
```
status有3种值：False、True以及Unknown。以上述为例，当status为True时，代表节点发生了Type类型为"NT_NPU_CARD_LOSE"的故障，所有故障类型定义请参见[如何定位和处理Cluster资源池节点故障](https://support.huaweicloud.com/trouble-modelarts/modelarts_13_0287.html)。
 #### 步骤1：获取故障节点信息
图2获取故障节点信息
![](https://support.huaweicloud.com/trouble-modelarts/figure/zh-cn_image_0000002341022576.png "点击放大")
可通过[Kubernetes API访问集群](https://kubernetes.io/zh-cn/docs/tasks/administer-cluster/access-cluster-api/)，然后获取集群中Nodes的详情，Go客户端样例如下：
```
package main
import (
    "context"
    "fmt"
    "time"
    "k8s.io/api/core/v1"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/tools/clientcmd"
)
func main() {
    // 通常可以使用clientcmd.RecommendedHomeFile，值是$HOME/.kube/config，根据自身情况可以修改
    config, _ := clientcmd.BuildConfigFromFlags("", clientcmd.RecommendedHomeFile)
    // 创建 clientset 客户端
    clientset, _ := kubernetes.NewForConfig(config)
    // 创建一个 watcher
    watcher, err := clientset.CoreV1().Nodes().Watch(context.TODO(), metav1.ListOptions{})
    if err != nil {
       fmt.Printf("Failed to create watcher: %v\n", err)
    }
    defer watcher.Stop()
    termCh := make(chan struct{}, 1)
    // 事件驱动获取节点故障信息
    go func() {
       for {
          select {
          case <-termCh:
             return
          case event, ok := <-watcher.ResultChan():
             if !ok {
                fmt.Printf("Failed to get watcher chan: %v\n", err)
                return
             }
             node := event.Object.(*v1.Node)
             fmt.Printf("Event type: %v, Node name: %s\n", event.Type, node.Name)
             for _, v := range node.Status.Conditions {
                fmt.Printf("Node Condition Type: %v, Type Status: %v\n", v.Type, v.Status)
             }
          }
       }
    }()
    // 或者全量获取Nodes
    nodes, _ := clientset.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{})
    fmt.Printf("There are %d nodes in the cluster\n", len(nodes.Items))
    time.Sleep(10 * time.Second)
    // 定义结束信号
    termCh <- struct{}{}
}
```
 #### 步骤2：用Taint隔离集群中的故障节点
图3**用Taint隔离集群中的故障节点**   
![](https://support.huaweicloud.com/trouble-modelarts/figure/zh-cn_image_0000002341034916.png "点击放大")
Taint相关资料可参考[污点和容忍度](https://kubernetes.io/zh-cn/docs/concepts/scheduling-eviction/taint-and-toleration/)。
 #### 步骤3：重新下发业务
图4重新下发业务   
![](https://support.huaweicloud.com/trouble-modelarts/figure/zh-cn_image_0000002375113649.png "点击放大")
当业务为训练作业时，可参考[设置断点续训练](https://support.huaweicloud.com/develop-modelarts/develop-modelarts-0023.html)。
