拓扑感知调度

容器服务 Kubernetes 版中,您可以结合Gang调度和拓扑感知调度,实现Pod在多个拓扑域中重试,直到找到满足条件的拓扑域。此外,结合节点池以及ECS的部署集能力,可以将Pod调度到同一低延时部署集的ECS中,实现低维度拓扑域的亲和调度。本文介绍如何实现拓扑感知调度。

拓扑感知调度介绍

在机器学习和大数据分析类作业中,Pod间通常有较大的网络通信需求。默认情况下,原生Kubernetes调度器会将Pod均匀打散在集群中,增加了通信距离,导致作业完成时间变长。您可以将Pod部署在同一可用区或机架上,减少通信跳数和时延以优化作业执行时间。目前Kubernetes原生支持了通过NodeAffinity以及PodAffinity的方式实现Pod亲和调度,然而原生的节点或Pod亲和调度方式存在以下的弊端。

  • Pod无法做到在多个不同的拓扑域上进行重试。在原生Kubernetes亲和调度策略中,作业的调度将依赖第一个Pod的调度结果。若第一个Pod的调度位置无法满足所有Pod的需求,则部分Pod将会处于Pending状态,且后续调度时即使有其他拓扑域能够满足整个作业需求也不会自动切换可用区。

  • 当前节点上仅有可用区级别的标签,即Pod调度时仅能够调度亲和到同一个可用区下,而无法做到更进一步的亲和到更低维度的拓扑域中。

Pod在多个拓扑域中重试

您可以通过为作业添加Gang调度标识,使kube-scheduler限制Pod同时获得需求的资源,并实现在多个拓扑域中进行重试的效果。

  1. Pod Label中添加Gang调度标识。关于Gang调度的信息,请参见使用Gang scheduling

    ...
    labels:
      pod-group.scheduling.sigs.k8s.io/name: tf-smoke-gpu # tf-smoke-gpuPodGroup的名称,需要自定义。
      pod-group.scheduling.sigs.k8s.io/min-available: "3" # 该值可以保持与作业的Pod数相等。
    ...
  2. PodAnnotation中添加拓扑调度约束。

    annotations:
      alibabacloud.com/topology-aware-constraint: {\"name\":\"test\",\"required\":{\"topologies\":[{\"key\":\"kubernetes.io/hostname\"}],\"nodeSelectors\":[{\"matchLabels\":{\"test\":\"abc\"}}]}}

    alibabacloud.com/topology-aware-constraint的值必须是一个合法的JSON字符串,该值需要满足以下结构。

    {
      "name": xxx # 任意的名称。
      "required": {
        "topologies": [
          {
            "key": xxx # 需要亲和的拓扑域的Key。
          }
        ],
        "nodeSelectors": [
          {
            # 该结构可以参考kubernetes原生的nodeaffinitylabelSelector的结构。
            "matchLabels": {},
            "matchExpressions": {} 
          }
        ]
      }
    }

    在设定了上述例子后,所有带有pod-group.scheduling.sigs.k8s.io/name: tf-smoke-gpu标签的Pod将会调度到满足test=abc的节点上。最终结果如下所示:

    kubectl get pod -ojson | jq '.items[] | {"name":.metadata.name,"ann":.metadata.annotations["alibabacloud.com/topology-aware-constraint"], "node": spec.nodeName}'
    {
        "name": "nginx-deployment-basic-69f47fc6db-6****"
        "ann": "{\"name\": \"test\", \"required\": {\"topologies\":[{\"key\": \"kubernetes.io/hostname\"}], \"nodeSelectors\": [{\"matchLabels\": {\"test\": \"a\"}}]}} "
        "node": "cn-shenzhen.10.0.2.4"
    }
    {
        "name":"nginx-deployment-basic-69f47fc6db-h****"
        "ann": "{\"name\": \"test\", \"required\": {\"topologies\":[{\"key\": \"kubernetes.io/hostname\"}], \"nodeSelectors\": [{\"matchLabels\": {\"test\": \"a\"}}]}} "
        "node": "cn-shenzhen.10.0.2.4"
    }

Pod调度到同一低延时部署集

在一些特定场景中,作业需要在更低维度的拓扑域中亲和来达成更优的性能。ECS提供了低延时部署集的功能,您可以用来限制ECS节点的创建位置。关于在ACK中使用部署集的相关信息,请参见节点池部署集最佳实践

当需要创建一个低延时部署集的节点池时,您还需要在节点标签中添加您自定义的节点标签,用于与其他节点池做区分,如下图所示。

image.png

完成上述步骤后,您可以通过以下Annotation以及Label来声明一个低延时部署集中调度的作业。

  1. Pod Label中添加Gang调度标识。关于Gang调度的信息,请参见使用Gang scheduling

    labels:
      pod-group.scheduling.sigs.k8s.io/name: xxx # xxxPodGroup的名称,需要自定义。
      pod-group.scheduling.sigs.k8s.io/min-available: "x" # 该值可以保持与作业的Pod数相等。
  2. PodAnnotation中添加拓扑调度约束。

    重要

    请将matchLabels替换成您自定义的低延时部署集的节点标签,并按需修改name

    annotations:
      alibabacloud.com/topology-aware-constraint: {\"name\":\"test\",\"required\":{\"topologies\":[{\"key\":\"alibabacloud.com/nodepool-id\"}],\"nodeSelectors\":[{\"matchLabels\":{\"np-type\":\"low-latency\"}}]}}