为GPU应用配置节点自动伸缩

在进行AI模型训练、推理或科学计算等GPU计算密集型任务时,工作负载常呈现显著波动,同时GPU硬件成本较高。通过为集群创建支持自动伸缩的GPU节点池,可根据实际资源需求动态增减节点数量,实现按需使用与弹性调度,有效提升GPU资源利用率并降低运维成本。

准备工作

步骤一:创建GPU节点池并开启自动伸缩

为保障GPU工作负载的独立调度与资源隔离,需创建专用GPU节点池,并启用自动扩缩容能力,使系统能根据负载变化动态调整计算资源。

  1. 登录容器服务管理控制台,在左侧导航栏选择集群列表

  2. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择节点管理 > 节点池

  3. 单击创建节点池,按照页面提示完成节点池的配置。

    关键配置项如下。详细配置项说明,请参见创建和管理节点池

    • 扩缩容模式:选择自动,配置实例数量。当集群的容量规划无法满足应用Pod调度时,ACK会根据配置的最小和最大实例数自动扩缩节点资源。

    • 实例规格配置:

      选择指定实例规格

      • 架构:选择GPU云服务器

      • 实例规格:根据业务需求选择合适的GPU实例规格族,例如ecs.gn7i-c8g1.2xlarge(NVIDIA A10)。为提高扩容成功率,建议配置多个实例规格。

        image

    • 污点 (Taints):为防止非目标应用被调度到GPU节点上,建议为节点池配置污点,例如:

      • :scaler

      • :gpu

      • Effect:NoSchedule (禁止调度)

      image

    • 节点标签(Labels):为节点池添加一个唯一的标签,例如 gpu-spec: NVIDIA-A10。此标签将用于后续的应用调度,确保GPU应用只在指定的节点池中运行。

      image

步骤二:为应用配置GPU资源与节点亲和性

将应用调度到GPU节点池时,需要修改其部署配置,包括请求GPU资源和设置节点亲和性。

  • 配置GPU资源请求。

    在容器的resources字段中,声明需要使用的GPU数量。

    # ...
    spec:
      containers:
      - name: gpu-auto-scaler
        # ...
        resources:
          limits:
            nvidia.com/gpu: 1 # 请求1GPU卡资源
    # ...
    
  • 配置节点亲和性。

    通过nodeAffinity,确保Pod被调度到此前创建的、带有特定标签的GPU节点上。

    # ...
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                - key: gpu-spec       # 匹配节点池设置的标签 Key
                  operator: In
                  values:
                  - NVIDIA-A10    # 匹配节点池设置的标签 Value
    # ...
    
  • 配置污点容忍。

    匹配节点池的配置,配置污点容忍,确保Pod可以被调度到带有特定污点的GPU节点上。

    # ...
    spec:
       tolerations:
        - key: "scaler"          # 匹配节点池设置的污点 Key
          operator: "Equal"
          value: "gpu"           # 匹配节点池设置的污点 Value
          effect: "NoSchedule"   # 匹配节点池设置的污点 Effect
    # ...
    

步骤三:部署应用并验证节点扩缩容效果

为了便于验证节点动态扩容与缩容,下文以 Deployment 为例进行介绍。

  1. 创建 gpu-deployment.yaml

    Deployment运行2Pod副本,Pod需调度至带有gpu-spec=NVIDIA-A10标签的GPU节点上,且每个Pod占用1GPU。

    YAML示例

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: gpu-auto-scaler
      namespace: default
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: gpu-auto-scaler
      template:
        metadata:
          labels:
            app: gpu-auto-scaler
        spec:
          containers:
            - name: gpu-auto-scaler
              image: registry-cn-hangzhou.ack.aliyuncs.com/dev/ubuntu:22.04
              command: ["bash", "-c"]
              args: ["while [ 1 ]; do date; nvidia-smi -L; sleep 60; done"]
              resources:
                limits:
                  # 请求1GPU卡资源
                  nvidia.com/gpu: 1 
          # 节点亲和性配置,确保 Pod 调度到带有特定标签的 GPU 节点
          affinity:
            nodeAffinity:
              requiredDuringSchedulingIgnoredDuringExecution:
                nodeSelectorTerms:
                  - matchExpressions:
                    - key: gpu-spec
                      operator: In
                      values:
                      - NVIDIA-A10
          # 声明污点容忍,确保Pod可以被调度到带有特定污点的GPU节点上
          tolerations:
          - key: "scaler"
            operator: "Equal"
            value: "gpu"
            effect: "NoSchedule"
  2. 部署应用并验证首次扩容。

    1. 部署应用。

      kubectl apply -f gpu-deployment.yaml

      由于当前集群没有满足条件的GPU节点,Pod将处于Pending状态,并触发节点池扩容。从触发扩容到新GPU节点就绪通常需要数分钟。

    2. 查看Pod Event,确认扩容已被触发。

      kubectl describe pod <your-pod-name>

      预期输出:

      Events:
        Type     Reason            Age                    From                Message
        ----     ------            ----                   ----                -------
        Normal   Scheduled         6m8s                   default-scheduler   Successfully assigned default/gpu-auto-scaler-565994fcf9-6nmz2 to cn-shanghai.10.XX.XX.244
        Normal   TriggeredScaleUp  8m32s                  cluster-autoscaler  pod triggered scale-up: [{asg-uf646aomci1pkqya54y7 0->2 (max: 10)}]
        Normal   AllocIPSucceed    6m4s                   terway-daemon       Alloc IP 10.XX.XX.245/16 took 4.505870999s
        Normal   Pulling           6m4s                   kubelet             Pulling image "registry-cn-hangzhou.ack.aliyuncs.com/dev/ubuntu:22.04"
        Normal   Pulled            6m2s                   kubelet             Successfully pulled image "registry-cn-hangzhou.ack.aliyuncs.com/dev/ubuntu:22.04" in 1.687s (1.687s including waiting). Image size: 29542023 bytes.
        Normal   Created           6m2s                   kubelet             Created container: gpu-auto-scaler
        Normal   Started           6m2s                   kubelet             Started container gpu-auto-scaler
    3. Pod 正常运行后,查看当前集群中带有对应标签的GPU节点。

      kubectl get nodes -l gpu-spec=NVIDIA-A10

      预期输出中,应有2GPU节点。

      NAME                       STATUS   ROLES    AGE     VERSION
      cn-shanghai.10.XX.XX.243   Ready    <none>   7m26s   v1.34.1-aliyun.1
      cn-shanghai.10.XX.XX.244   Ready    <none>   7m25s   v1.34.1-aliyun.1
  3. 验证节点自动扩容。

    1. 将应用副本数扩展至3个。

      kubectl scale deployment gpu-auto-scaler --replicas=3

      执行kubectl get pod,此时2Pod正在运行,1个新增Pod因资源不足而处于Pending状态,从而再次触发节点池扩容。

    2. 等待几分钟后,再次执行kubectl get nodes -l gpu-spec=NVIDIA-A10

      输出中,集群中带有对应标签的节点增加至3个。

      NAME                       STATUS   ROLES    AGE   VERSION
      cn-shanghai.10.XX.XX.243   Ready    <none>   11m   v1.34.1-aliyun.1
      cn-shanghai.10.XX.XX.244   Ready    <none>   11m   v1.34.1-aliyun.1
      cn-shanghai.10.XX.XX.247   Ready    <none>   45s   v1.34.1-aliyun.1
  4. 验证节点自动缩容。

    1. 将应用副本数缩减至1个。

      kubectl scale deployment gpu-auto-scaler --replicas=1

      此时,2个多余的Pod会被终止,导致2GPU节点为空闲状态。节点伸缩组件会在达到缩容触发时延后,会自动将其从集群中移除以节省成本。

    2. 等待达到缩容触发时延后,再次执行kubectl get nodes -l gpu-spec=NVIDIA-A10

      输出中,集群中带有对应标签的节点应已缩减至1个。

      NAME                       STATUS   ROLES    AGE   VERSION
      cn-shanghai.10.XX.XX.243   Ready    <none>   31m   v1.34.1-aliyun.1

生产环境使用建议

  • 成本优化:GPU云服务器实例成本较高,扩容节点采用按量付费。建议在节点池中配置抢占式实例作为补充,可大幅降低计算成本。同时,请为节点池合理配置最大实例数,以防意外的业务峰值导致成本失控。

  • 高可用性配置:为避免因单可用区或单实例规格库存不足导致的扩容失败,建议在创建节点池时选择多个可用区的交换机,并选择多个GPU实例规格。

  • 监控与告警:开启集群GPU监控,通过监测GPU相关指标,了解GPU使用情况、健康状态、工作负载性能等,从而实现对异常问题的快速诊断、优化GPU资源分配。

常见问题

提交了GPU应用后,Pod一直处于Pending状态,但节点池没有扩容,是什么原因?

可能的原因有:

  • 亲和性配置错误:检查应用的nodeAffinity配置中的标签是否与节点池中设置的节点标签完全匹配。

  • 资源请求不匹配:确认应用请求的GPU数量(nvidia.com/gpu)没有超过单个节点可提供的上限。

  • 节点伸缩组件异常:检查组件日志,排查是否有错误信息。

    如需采集组件日志:

  • 节点池配置限制:检查节点池设置的最大节点数配额是否已达到上限。

如何在同一个集群中使用不同类型的GPU?

可创建多个节点池,每个节点池配置不同的GPU实例规格和唯一的节点标签(例如 gpu-spec: NVIDIA-A10gpu-spec: NVIDIA-L20)。在部署应用时,通过nodeAffinity指定对应的标签,将不同应用调度到不同类型的GPU节点上。

如何查看节点挂载的GPU设备?

节点池创建成功后,可查看节点挂载的GPU设备