技术博客

混合异构GPU集群运维:NVIDIA+昇腾/DCU共存调度与统一管理

讲解生产环境中NVIDIA GPU与国产GPU(昇腾/海光DCU)混合部署的运维方案:Kubernetes多设备类型调度(不同Device Plugin共存)、通过标签/污点实现任务精准分发、统一监控面板(Prometheus+Grafana同时采集NVIDIA和NPU指标)、混合集群资源配额管理,以及国产GPU逐步替换NVIDIA的平滑迁移策略。

国产GPU昇腾海光DCUNVIDIAKubernetes混合集群异构计算AI基础设施

很少有企业能一夜之间完成 GPU 国产化替换,更常见的场景是:NVIDIA GPU 继续跑现有业务,国产 GPU 接新业务或逐步承接迁移后的任务。本文讲解如何在 Kubernetes 中管理 NVIDIA + 昇腾/DCU 混合集群。

混合集群架构

Kubernetes 集群

节点池 A:NVIDIA GPU 节点
  nvidia-node-01 (4× A100)
  nvidia-node-02 (4× A100)
  → 跑:现有 CUDA 应用、已验证的训练任务

节点池 B:昇腾 NPU 节点
  ascend-node-01 (8× 910B)
  ascend-node-02 (8× 910B)
  → 跑:已迁移的训练任务、信创合规场景

节点池 C:海光 DCU 节点
  dcu-node-01 (8× Z100L)
  → 跑:ROCm 迁移后的推理服务、测试验证

多个 Device Plugin 共存:
  nvidia-device-plugin  → nvidia.com/gpu
  ascend-device-plugin  → huawei.com/Ascend910
  dcu-device-plugin     → amd.com/gpu

一、多 Device Plugin 共存

# K8s 支持多个 Device Plugin 同时运行(不同资源名称)
# 三类 Device Plugin 可以同时存在于同一集群

# 验证各 Device Plugin 状态
kubectl get daemonset -n kube-system | grep -E "nvidia|ascend|dcu"
# nvidia-device-plugin      3     3     3     ...
# ascend-device-plugin      2     2     2     ...
# dcu-device-plugin         1     1     1     ...

# 查看各节点的 GPU 资源
kubectl get nodes -o custom-columns=\
"NAME:.metadata.name,\
NVIDIA:.status.capacity.nvidia\.com/gpu,\
ASCEND:.status.capacity.huawei\.com/Ascend910,\
DCU:.status.capacity.amd\.com/gpu"

# NAME             NVIDIA  ASCEND  DCU
# nvidia-node-01   4       <none>  <none>
# nvidia-node-02   4       <none>  <none>
# ascend-node-01   <none>  8       <none>
# ascend-node-02   <none>  8       <none>
# dcu-node-01      <none>  <none>  8

二、节点标签与污点策略

# 打标签(区分硬件类型)
# NVIDIA 节点
kubectl label node nvidia-node-01 nvidia-node-02 \
    accelerator=nvidia-gpu \
    gpu-brand=nvidia \
    gpu-model=A100

# 昇腾节点
kubectl label node ascend-node-01 ascend-node-02 \
    accelerator=huawei-npu \
    gpu-brand=huawei \
    npu-model=910b

# 海光 DCU 节点
kubectl label node dcu-node-01 \
    accelerator=hygon-dcu \
    gpu-brand=hygon \
    dcu-model=Z100L

# 打污点(防止误调度)
kubectl taint node ascend-node-01 ascend-node-02 \
    accelerator=huawei-npu:NoSchedule

kubectl taint node dcu-node-01 \
    accelerator=hygon-dcu:NoSchedule

# NVIDIA 节点也打污点(可选,视需求)
kubectl taint node nvidia-node-01 nvidia-node-02 \
    accelerator=nvidia-gpu:NoSchedule

三、任务调度配置

NVIDIA 任务(现有任务不变)

apiVersion: batch/v1
kind: Job
metadata:
  name: cuda-training-job
spec:
  template:
    spec:
      nodeSelector:
        accelerator: nvidia-gpu
      tolerations:
        - key: accelerator
          value: nvidia-gpu
          effect: NoSchedule
      containers:
        - name: trainer
          image: pytorch/pytorch:2.3.0-cuda12.1-cudnn8-runtime
          resources:
            limits:
              nvidia.com/gpu: 4
          command: ["python3", "train_cuda.py"]

昇腾任务(迁移后的任务)

apiVersion: batch/v1
kind: Job
metadata:
  name: npu-training-job
spec:
  template:
    spec:
      nodeSelector:
        accelerator: huawei-npu
        npu-model: 910b
      tolerations:
        - key: accelerator
          value: huawei-npu
          effect: NoSchedule
      containers:
        - name: trainer
          image: ascendai/cann:8.0.RC3-ubuntu22.04-aarch64
          resources:
            limits:
              huawei.com/Ascend910: 8
          volumeMounts:
            - name: driver
              mountPath: /usr/local/Ascend/driver
              readOnly: true
          command: ["python3", "train_npu.py"]
      volumes:
        - name: driver
          hostPath:
            path: /usr/local/Ascend/driver

推理服务:灵活选择硬件

# 推理服务可以支持多种硬件,通过 Helm values 控制
# values-nvidia.yaml:
gpuType: nvidia
resources:
  limits:
    nvidia.com/gpu: 1
nodeSelector:
  accelerator: nvidia-gpu

# values-ascend.yaml:
gpuType: ascend
resources:
  limits:
    huawei.com/Ascend910: 1
nodeSelector:
  accelerator: huawei-npu

四、统一监控(Prometheus + Grafana)

混合集群的关键挑战:NVIDIA、昇腾、DCU 各有不同的 Exporter,需要统一到同一个 Prometheus。

# prometheus.yml 采集配置(三类 GPU 统一采集)
scrape_configs:
  # NVIDIA GPU(nvidia-smi exporter)
  - job_name: 'nvidia-gpu'
    kubernetes_sd_configs:
      - role: pod
    relabel_configs:
      - source_labels: [__meta_kubernetes_pod_label_name]
        action: keep
        regex: nvidia-dcgm-exporter
      - source_labels: [__meta_kubernetes_pod_node_name]
        target_label: node
      - target_label: gpu_brand
        replacement: nvidia

  # 昇腾 NPU(npu-exporter)
  - job_name: 'ascend-npu'
    kubernetes_sd_configs:
      - role: pod
    relabel_configs:
      - source_labels: [__meta_kubernetes_pod_label_name]
        action: keep
        regex: npu-exporter
      - source_labels: [__meta_kubernetes_pod_node_name]
        target_label: node
      - target_label: gpu_brand
        replacement: huawei

  # 海光 DCU(rocm-smi exporter)
  - job_name: 'hygon-dcu'
    kubernetes_sd_configs:
      - role: pod
    relabel_configs:
      - source_labels: [__meta_kubernetes_pod_label_name]
        action: keep
        regex: dcgm-exporter-dcu
      - target_label: gpu_brand
        replacement: hygon

统一 Grafana Dashboard

# 各厂商 GPU 利用率(统一展示,需要归一化指标名)

# 方法:在 Prometheus Recording Rules 中统一指标名
groups:
  - name: gpu_unified_metrics
    rules:
      # 统一利用率指标
      - record: gpu:utilization:percent
        expr: |
          # NVIDIA
          label_replace(
            DCGM_FI_DEV_GPU_UTIL,
            "gpu_brand", "nvidia", "", ""
          )
          or
          # 昇腾
          label_replace(
            container_npu_utilization,
            "gpu_brand", "huawei", "", ""
          )
          or
          # 海光 DCU
          label_replace(
            rocm_gpu_use_percent,
            "gpu_brand", "hygon", "", ""
          )

      # 统一显存使用率
      - record: gpu:memory_used_ratio:percent
        expr: |
          label_replace(
            DCGM_FI_DEV_FB_USED / DCGM_FI_DEV_FB_TOTAL * 100,
            "gpu_brand", "nvidia", "", ""
          )
          or
          label_replace(
            container_npu_memory_used_bytes / container_npu_memory_total_bytes * 100,
            "gpu_brand", "huawei", "", ""
          )
          or
          label_replace(
            rocm_gpu_memory_vram_used_bytes / rocm_gpu_memory_vram_total_bytes * 100,
            "gpu_brand", "hygon", "", ""
          )
# Grafana 统一 Dashboard 核心 PromQL

# 集群整体 GPU 数量(按厂商)
count by (gpu_brand) (gpu:utilization:percent)

# 各厂商平均利用率对比
avg by (gpu_brand) (gpu:utilization:percent)

# 各节点 GPU 利用率(混合展示)
gpu:utilization:percent

# 资源使用率最高的 10 个节点(不分厂商)
topk(10, avg by (node, gpu_brand) (gpu:utilization:percent))

五、资源配额管理

# 使用 ResourceQuota 控制不同团队的 GPU 资源使用
# 场景:算法团队有 NVIDIA 和昇腾的配额,运维团队只有 DCU

# 算法团队命名空间配额
apiVersion: v1
kind: ResourceQuota
metadata:
  name: ml-team-quota
  namespace: ml-team
spec:
  hard:
    requests.nvidia.com/gpu: "8"       # 最多 8 张 NVIDIA GPU
    limits.nvidia.com/gpu: "8"
    requests.huawei.com/Ascend910: "16" # 最多 16 个昇腾 NPU
    limits.huawei.com/Ascend910: "16"
    
# 推理团队命名空间配额
apiVersion: v1
kind: ResourceQuota
metadata:
  name: inference-team-quota
  namespace: inference
spec:
  hard:
    requests.amd.com/gpu: "8"         # 最多 8 个 DCU(用于推理)
    limits.amd.com/gpu: "8"
    requests.nvidia.com/gpu: "4"      # 保留部分 NVIDIA 做回退
    limits.nvidia.com/gpu: "4"

六、平滑迁移策略

推荐的国产化替换路径(降低业务风险):

阶段1:验证(1-2个月)
  - 选 1-2 个非关键推理服务
  - 部署到昇腾/DCU,并行跑(双轨)
  - 对比性能、稳定性、成本

阶段2:推理服务迁移(2-3个月)
  - 将验证通过的推理服务完全迁移
  - 新增推理产能使用国产 GPU
  - NVIDIA 推理节点开始缩减

阶段3:训练任务迁移(3-6个月)
  - 对训练任务做精度对比验证
  - 逐步将训练作业迁移到昇腾/DCU
  - 保留 NVIDIA 做 CUDA 新任务兜底

阶段4:NVIDIA 资源缩减
  - NVIDIA 节点保留最小规模(CUDA 生态兜底)
  - 新采购全部使用国产 GPU
# 蓝绿切换:同一推理服务在 NVIDIA 和国产 GPU 双轨运行
# 通过流量权重逐步切换

# NVIDIA 版本(旧)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: inference-service-nvidia
spec:
  replicas: 8   # 逐步缩减
  ...

# 昇腾版本(新)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: inference-service-ascend
spec:
  replicas: 2   # 逐步增加
  ...

# Service 通过 selector 控制流量比例(或使用 Istio 流量分割)

小结

混合集群的核心挑战是统一调度和统一监控:调度层通过节点标签 + 污点 + 不同资源名称(nvidia.com/gpu / huawei.com/Ascend910 / amd.com/gpu)实现精准分发;监控层通过 Recording Rules 归一化三类 GPU 的指标名称,在 Grafana 中统一展示。迁移策略的关键是先推理后训练、先非关键后核心,双轨并行验证,有数据支撑后再做切换,避免一刀切带来的风险。