更新时间:2026-05-21 GMT+08:00
分享

分组Pod故障迁移

功能介绍

在数据中心分布式AI训练/推理场景下,作业实例具有强协同依赖性、长时间运行性和资源独占性(如NPU、GPU)等特点,而数据中心很有可能出现节点宕机、网络分区等故障。当集群出现故障并直接影响某些Pod运行时,重启整个作业是代价高昂的,有可能导致整个作业一直处于运行、失败、重启的循环中,永远无法顺利完成;而只迁移这些受直接影响的Pod,虽然代价较小,但却有可能导致这些Pod与同组内的其他Pod割裂,出现运行信息过时、拓扑约束失效等情况,致使整个分组处于占用资源、但未正常运行的状态,造成集群资源浪费。

为此,Volcano进一步提出了故障场景下支持分组Pod迁移的能力,即当检测到集群出现故障导致某些Pod被驱逐或失活时,主动迁移整个分组的Pod到别的适合的节点上,以加快作业恢复速度,避免浪费集群资源。

以下图场景为例,在由8个空闲节点、4个一层HyperNode、2个二层HyperNode和1个三层HyperNode组成的集群中,运行着一个Volcano Job。该Job包含两个分组,每个分组都被约束调度到同一个一层HyperNode下,其中分组1由Pod0和Pod1组成,运行在节点node0和node1上;分组2有Pod2和Pod3组成,运行在节点node2和node3上。此时,node3节点失效,导致其上的Pod3失活。

图1 不支持分组Pod迁移能力
  • 若不支持分组Pod迁移能力,则新建的Pod3将因为不存在满足网络拓扑约束的节点而一直处于Pending状态,导致Pod2占用node2节点资源,但却不能正常运行,造成集群资源浪费。或者,用户需重启整个Job,导致Pod0和Pod1也需要重新运行,作业恢复成本较大。
  • 若支持分组Pod迁移能力,则可主动中止同一分组内的Pod2,并将新创建的Pod2和Pod3统一调度到HyperNode3下,即节点node6和node7上,从而使整个作业高效恢复运行。
图2 支持分组Pod迁移能力

为此,Volcano Job在作业生命周期管理策略中提供了RestartPartition动作,允许在发生特定事件时重启或迁移整个分组。例如,在Job中添加如下配置,表示在发生Pod驱逐、Pod失败时重启、迁移该Pod所在的整个分组。

spec:
  policies:
  - action: RestartPartition
    event: PodEvicted
  - action: RestartPartition
    event: PodFailed

前提条件

集群中已安装Volcano调度器插件,且插件版本在1.21.1及以上。

约束与限制

  • 网络拓扑感知调度暂不支持抢占。当资源紧张时,调度器不会主动抢占已分配给Pod的资源。
  • 若配置了分组亲和策略,则不支持soft模式的网络拓扑约束。
  • HyperJob工作负载不支持网络拓扑感知调度。即使在HyperJob的JobTemplate中配置了networkTopology或分组亲和策略,这些配置将被忽略且不会生效。
  • HyperNode自动发现功能不支持多种网络拓扑结构混部的场景(例如,A2与A3拓扑类型共存于同一集群)。
  • 应尽量避免在运行中变更网络拓扑配置项,因为这可能导致集群内HyperNode结构重建,进而引发Volcano调度器进程的负载波动或调度异常。
  • 若在调度过程中,集群网络拓扑结构或配置项发生变更,Volcano无法保证调度结果的正确性。

使用示例

  1. 登录CCE控制台,单击集群名称进入集群。
  2. 单击左侧导航栏的“配置中心”,切换至“调度配置”页面,选择Volcano调度器找到对应的“专家模式”,单击“开始使用”。

  3. 进入CCE专家模式配置页面,在YAML配置文件中,修改default_controller_conf配置为如下内容,以启用HyperNode自动发现功能。其中配置参数,请根据实际需求调整。

    ...
    default_controller_conf:
      networkTopologyDiscovery:
        - source: label # HyperNode自动发现插件的名称,不可修改
          enabled: true # HyperNode自动发现插件开关,true表示开启,false表示关闭(原有的HyperNode实例不会删除)
          config:
            networkTopologyTypes:
              testtopology:                         # 网络拓扑层级关系的名称,最大限制20字符;当前仅支持配置一组
                - nodeLabel: test-tier-3            # 第3层网络拓扑对应的节点标签名,对应HyperNode tier=3
                - nodeLabel: test-tier-2            # 第2层网络拓扑对应的节点标签名,对应HyperNode tier=2
                - nodeLabel: test-tier-1            # 第1层网络拓扑对应的节点标签名,对应HyperNode tier=1
                - nodeLabel: kubernetes.io/hostname # 第0层网络拓扑对应的节点标签名,即节点层级,仅支持根据Node名匹配,不支持修改
    ...

  4. 以下图中的多级网络拓扑结构为例,创建8个节点,并执行如下命令,为它们添加如下网络拓扑标签。

    本示例仅用于演示,实际创建的HyperNode应依据集群的真实拓扑。此外,对于没有网络拓扑关系的普通节点,不应添加与网络拓扑相关的节点标签,否则可能导致创建的HyperNode不符合预期。

    kubectl label node 192.168.5.17  test-tier-3=HyperNode6 test-tier-2=HyperNode4 test-tier-1=HyperNode0 # node0
    kubectl label node 192.168.5.224 test-tier-3=HyperNode6 test-tier-2=HyperNode4 test-tier-1=HyperNode0 # node1
    kubectl label node 192.168.5.235 test-tier-3=HyperNode6 test-tier-2=HyperNode4 test-tier-1=HyperNode1 # node2
    kubectl label node 192.168.5.239 test-tier-3=HyperNode6 test-tier-2=HyperNode4 test-tier-1=HyperNode1 # node3
    kubectl label node 192.168.5.240 test-tier-3=HyperNode6 test-tier-2=HyperNode5 test-tier-1=HyperNode2 # node4
    kubectl label node 192.168.5.251 test-tier-3=HyperNode6 test-tier-2=HyperNode5 test-tier-1=HyperNode2 # node5
    kubectl label node 192.168.5.83  test-tier-3=HyperNode6 test-tier-2=HyperNode5 test-tier-1=HyperNode3 # node6
    kubectl label node 192.168.5.95  test-tier-3=HyperNode6 test-tier-2=HyperNode5 test-tier-1=HyperNode3 # node7
    表1 节点、IP与多级HyperNode归属映射表

    节点名

    IP地址

    标签(Labels)

    node0

    192.168.5.17

    test-tier-3=HyperNode6 test-tier-2=HyperNode4 test-tier-1=HyperNode0

    node1

    192.168.5.224

    test-tier-3=HyperNode6 test-tier-2=HyperNode4 test-tier-1=HyperNode0

    node2

    192.168.5.235

    test-tier-3=HyperNode6 test-tier-2=HyperNode4 test-tier-1=HyperNode1

    node3

    192.168.5.239

    test-tier-3=HyperNode6 test-tier-2=HyperNode4 test-tier-1=HyperNode1

    node4

    192.168.5.240

    test-tier-3=HyperNode6 test-tier-2=HyperNode5 test-tier-1=HyperNode2

    node5

    192.168.5.251

    test-tier-3=HyperNode6 test-tier-2=HyperNode5 test-tier-1=HyperNode2

    node6

    192.168.5.83

    test-tier-3=HyperNode6 test-tier-2=HyperNode5 test-tier-1=HyperNode3

    node7

    192.168.5.95

    test-tier-3=HyperNode6 test-tier-2=HyperNode5 test-tier-1=HyperNode3

  5. 执行以下命令,查询Volcano自动发现的HyperNode。

    kubectl get hypernodes

    返回信息如下所示。

    NAME                                      TIER   TIERNAME      NODECOUNT   AGE
    hypernode-testtopology-tier1-2****   1      test-tier-1   2           8s
    hypernode-testtopology-tier1-4****   1      test-tier-1   2           8s
    hypernode-testtopology-tier1-j****   1      test-tier-1   2           8s
    hypernode-testtopology-tier1-l****   1      test-tier-1   2           8s
    hypernode-testtopology-tier2-m****   2      test-tier-2   2           8s
    hypernode-testtopology-tier2-n****   2      test-tier-2   2           8s
    hypernode-testtopology-tier3-c****   3      test-tier-3   2           8s

  6. 创建一个Volcano Job工作负载,包含4个Pod,每个Pod独占一个节点的所有NPU资源,并配置分组策略将这4个Pod均分为2组,每个分组最高亲和到tier=1的HyperNode上。此外,配置事件为PodEvicted、动作为RestartPartition的生命周期管理策略,已启用分组Pod故障迁移能力。示例如下所示。

    apiVersion: batch.volcano.sh/v1alpha1
    kind: Job
    metadata:
      name: network-topology-job
      namespace: default
    spec:
      schedulerName: volcano
      policies:
      - action: RestartPartition   # 发生PodEvicted事件时,重启该pod所在的整个分组pod
        event: PodEvicted
      minAvailable: 4         # gang调度条件,需要满足至少4个pod可调度成功
      tasks:
        - replicas: 4 # 一共4个实例
          name: t0
          partitionPolicy:          # 配置分组亲和调度策略
            totalPartitions: 2      # 将当前task内的pod分为2组
            partitionSize: 2        # 每个分组包含2个pod
            networkTopology:        # 配置分组级网络拓扑约束
              mode: hard            # 该网络拓扑约束为硬约束,必须满足
              highestTierAllowed: 1 # 最高亲和到tier=1的HyperNode
          template:
            spec:
              containers:
                - name: container1
                  image: nginx:latest
                  resources:
                    requests:
                      huawei.com/ascend-1980: 16 # 每个pod独占一个节点的NPU资源
                    limits:
                      huawei.com/ascend-1980: 16

  7. 执行以下命令,查看调度结果。此时,第一组Pod已被调度至HyperNode0的node0和node1上,第二组Pod已被调度至HyperNode1的node2和node3上。

    kubectl get pod -o wide

    返回信息如下所示。

    NAME                        READY   STATUS    RESTARTS   AGE   IP             NODE            NOMINATED NODE   READINESS GATES
    network-topology-job-t0-0   1/1     Running   0          6s    172.19.1.36    192.168.5.17    <none>           <none>
    network-topology-job-t0-1   1/1     Running   0          6s    172.19.2.143   192.168.5.224   <none>           <none>
    network-topology-job-t0-2   1/1     Running   0          6s    172.19.3.19    192.168.5.239   <none>           <none>
    network-topology-job-t0-3   1/1     Running   0          6s    172.19.1.162   192.168.5.235   <none>           <none>

  8. 执行以下命令,驱逐node3节点上的Pod,模拟节点故障场景。

    kubectl drain 192.168.5.239 --ignore-daemonsets

  9. 重新检查调度结果。此时,第二个分组的两个Pod已被调度到HyperNode3的node6和node7上,保持了与分组内其他Pod的网络拓扑一致性。

    kubectl get pod -o wide

    返回信息如下所示。

    NAME                        READY   STATUS    RESTARTS   AGE     IP             NODE            NOMINATED NODE   READINESS GATES
    network-topology-job-t0-0   1/1     Running   0          2m51s   172.19.1.29    192.168.5.17    <none>           <none>
    network-topology-job-t0-1   1/1     Running   0          2m51s   172.19.2.136   192.168.5.224   <none>           <none>
    network-topology-job-t0-2   1/1     Running   0          80s     172.19.3.143   192.168.5.95    <none>           <none>
    network-topology-job-t0-3   1/1     Running   0          82s     172.19.4.12    192.168.5.83    <none>           <none>

  10. 执行以下命令,恢复node3节点。

    kubectl uncordon 192.168.5.239

相关文档