自定义弹性资源优先级调度

自定义弹性资源优先级调度是阿里云提供的弹性调度策略。您可以在应用发布或扩容过程中,自定义资源策略(ResourcePolicy),设置应用实例Pod被调度到不同类型节点资源的顺序。同时,在缩容过程中按照原调度顺序逆序缩容。

重要

自调度器版本v1.x.x-aliyun-6.4开始,自定义弹性资源优先级功能的ignorePreviousPod字段的默认值将修改为False,ignoreTerminatingPod字段的默认值将修改为True。涉及这些字段的存量ResourcePolicy不受影响,后续更新也不受影响。

前提条件

  • Kubernetes集群为ACK Pro且版本为1.20.11及以上。关于如何升级,请参见升级ACK集群K8s版本

  • 对于不同ACK版本的集群,调度器版本需要满足以下要求。关于调度器各版本支持的功能,请参见kube-scheduler

    ACK版本

    调度器版本

    1.20

    v1.20.4-ack-7.0及以上

    1.22

    v1.22.15-ack-2.0及以上

    1.24及以上

    所有版本均支持

  • 需要使用ECI资源时,已部署ack-virtual-node。具体操作,请参见ACK使用ECI

使用限制

  • 本功能与pod-deletion-cost冲突,不能同时使用。关于pod-deletion-cost的更多信息,请参见pod-deletion-cost

  • 本功能暂不支持与使用ECI弹性调度混合使用。关于ECI弹性调度的更多信息,请参见使用ECI弹性调度

  • 本功能目前使用的是BestEffort策略,无法保证一定按照逆序缩容。

  • max字段仅在集群版本为1.22及以上,且调度器版本为5.0及以上的版本中开启。

  • 与弹性节点池同时使用时,可能导致弹性节点池无效弹出节点。使用时请将弹性节点池包含在某个Unit中,且弹性节点池的Unit不要设置max字段。

  • 若您的调度器为5.0版本以下或集群版本为1.20及以下,请注意在ResourcePolicy创建前存在的Pod会在缩容时最先缩容。

  • 若您的调度器为6.1版本以下或集群版本为1.20及以下,在与ResourcePolicy关联的Pod未完全删除时,请不要对ResourcePolicy进行修改。

使用方式

创建ResourcePolicy定义弹性资源优先级:

apiVersion: scheduling.alibabacloud.com/v1alpha1
kind: ResourcePolicy
metadata:
  name: test
  namespace: default
spec:
  ignorePreviousPod: false
  ignoreTerminatingPod: true
  matchLabelKeys:
  - pod-template-hash
  preemptPolicy: AfterAllUnits
  selector:
    key1: value1
  strategy: prefer
  units:
  - nodeSelector:
      unit: first
    resource: ecs
  - nodeSelector:
      unit: second
    max: 10
    resource: ecs
  - resource: eci
  whenTryNextUnits:
    policy: TimeoutOrExceedMax
    timeout: 1m
  • selector:声明ResourcePolicy作用于同一命名空间下label上打了key1=value1的Pod。selector为空时将对该命名空间下所有Pod生效。

  • strategy:调度策略选择,目前只支持prefer

  • units:用户自定义的调度单元。扩容时,将按照units下资源的顺序进行扩容;缩容时,将按照逆序进行缩容。

    • resource:弹性资源的类型,目前支持eciecs以及elastic三种类型。elastic在集群版本为1.24以上,且调度器版本为6.4.3及以上版本可用。

    • nodeSelector:用nodelabel标识该调度单元下的节点,只对ecs资源生效。

    • max(调度器为5.0版本及以上可用):在本调度单元中最多能调度的Pod的副本数。

  • preemptPolicy(调度器为6.1版本及以上可用):当ResourcePolicy中存在多个unit时,是否允许ResourcePolicy在每个Unit调度失败时尝试抢占。BeforeNextUnit表示调度器将在每个Unit调度失败时尝试抢占,AfterAllUnits表示ResourcePolicy只在最后一个Unit调度失败时尝试抢占。默认为AfterAllUnits。

  • ignorePreviousPod(调度器为6.1版本及以上可用):需要与units中的max一起使用。该值为true时,在进行Pod数量统计时将忽略ResourcePolicy创建之前已经调度的Pod。

  • ignoreTerminatingPod(调度器为6.1版本及以上可用):需要与units中的max一起使用。该值为true时,在进行Pod数量统计时将忽略处于Terminating状态的Pod。

  • matchLabelKeys(调度器为6.2版本及以上可用):需要与units中的max一起使用,Pod会根据自身Label的值进行分组,不同分组的Pod将适用于不同的max计数。当使用该功能时,若Pod上缺少任务matchLabelKeys中申明的Label,Pod将会被拒绝调度。

  • whenTryNextUnits(集群版本1.24及以上,调度器为6.4版本及以上可用):描述Pod在何种情况下被允许使用后续Unit中的资源。

    • policy:代表Pod采用的策略。可选值包括ExceedMaxLackResourceAndNoTerminatingTimeoutOrExceedMaxLackResourceOrExceedMax(默认值)。

      • ExceedMax:若当前Unit的Max未设置,或当前Unit中的Pod数量大于等于设置的Max值,允许Pod使用下一级资源。该策略可以与自动伸缩以及ECI配合,达到优先尝试节点池自动伸缩的效果。

        重要
        • 请注意,如果自动伸缩节点池长时间无法弹出节点,此策略可能导致Pod Pending。

        • 当前由于Cluster Autoscaler未感知ResourcePolicy的Max限制,实际弹出的实例数可能会多于设置的Max值。该问题将在后续版本中进行优化。

      • TimeoutOrExceedMax:当满足以下条件之一:

        • 当前Unit的Max已设置且Unit中的Pod数量小于设置的Max值时;

        • 当前Unit的Max未设置,且当前Unit的Type为elastic

        若当前Unit资源不足以调度Pod,则在当前Unit中等待,等待时间的最大长度为timeout。该策略可以与自动伸缩以及ECI配合,达到优先尝试节点池自动伸缩,并且在超时后自动使用eci的效果。

      • 重要

        请注意,若Timeout期间内弹出节点,在Timeout期间内节点未达到Ready状态,且Pod未容忍NotReady的污点,则Pod仍然会被调度到ECI上。

      • LackResourceOrExceedMax:若当前Unit中的Pod数量大于等于设置的Max值,或当前Unit中已没有多余资源,允许Pod使用下一级资源。该策略为默认策略,适合大部分场景的基本需求。

      • LackResourceAndNoTerminating:若当前Unit中的Pod数量大于等于设置的Max值,或当前Unit中已没有多余资源,并且当前Unit中无处于Terminating状态的Pod时,允许Pod使用下一级资源。该策略适合与滚动更新策略配置使用,达到滚动更新时不会由于Terminating导致新Pod滚动到后续Unit上的效果。

    • timeout:当policy为timeoutOrExceedMaxPolicy时,该字段可以被用来描述超时时长,当该字段为空值时,我们将此值视为15分钟。

使用场景示例

场景一:基于节点池优先级调度

当您需要部署一个Deployment,此时集群有两个节点池,一个是节点池A,一个是节点池B。您希望优先调度节点池A,资源不足时调度节点池B。当进行缩容时,优先缩容在节点池B中的Pod,然后缩容节点池A中的Pod。如下示例中,cn-beijing.10.0.3.137cn-beijing.10.0.3.138属于节点池A, cn-beijing.10.0.6.47cn-beijing.10.0.6.46属于节点池B,节点规格均为2核4 GB。基于节点池优先级调度的具体操作步骤如下:

  1. 使用以下YAML内容,创建ResourcePolicy自定义节点池调度顺序。

    apiVersion: scheduling.alibabacloud.com/v1alpha1
    kind: ResourcePolicy
    metadata:
      name: nginx
      namespace: default
    spec:
      selector:
        app: nginx # 此处要与后续创建的Pod的label相关联。
      strategy: prefer
      units:
      - resource: ecs
        nodeSelector:
          alibabacloud.com/nodepool-id: np7ec79f2235954e879de07b780058****
      - resource: ecs
        nodeSelector:
          alibabacloud.com/nodepool-id: npab2df797738644e3a7b7cbf532bb****
    说明

    节点池ID可以从所在集群的节点管理 > 节点池中获取。具体操作,请参见创建节点池

  2. 使用以下YAML内容创建Deployment,部署2个Pod。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx
      labels:
        app: nginx
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          name: nginx
          labels:
            app: nginx # 此处要与上一步创建的ResourcePolicy的selector相关联。
        spec:
          containers:
          - name: nginx
            image: nginx
            resources:
              limits:
                cpu: 2
              requests:
                cpu: 2
  3. 创建应用Nginx并查看部署结果。

    1. 执行以下命令,创建应用Nginx。

      kubectl apply -f nginx.yaml

      预期输出:

      deployment.apps/nginx created
    2. 执行以下命令,查看部署结果。

      kubectl get pods -o wide

      预期输出:

      NAME                    READY   STATUS    RESTARTS   AGE   IP               NODE                    NOMINATED NODE   READINESS GATES
      nginx-9cdf7bbf9-b****   1/1     Running   0          17s   172.29.112.216   cn-beijing.10.0.3.137   <none>           <none>
      nginx-9cdf7bbf9-k****   1/1     Running   0          17s   172.29.113.24    cn-beijing.10.0.3.138   <none>           <none>

      由预期输出得到,前两个Pod被调度在节点池A的节点上。

  4. 对Pod进行扩容。

    1. 执行以下命令,将Pod扩容到4个。

      kubectl scale deployment nginx --replicas 4                      

      预期输出:

      deployment.apps/nginx scaled
    2. 执行以下命令,查看Pod状态。

      kubectl get pods -o wide

      预期输出:

      NAME                    READY   STATUS    RESTARTS   AGE    IP               NODE                    NOMINATED NODE   READINESS GATES
      nginx-9cdf7bbf9-b****   1/1     Running   0          101s   172.29.112.216   cn-beijing.10.0.3.137   <none>           <none>
      nginx-9cdf7bbf9-k****   1/1     Running   0          101s   172.29.113.24    cn-beijing.10.0.3.138   <none>           <none>
      nginx-9cdf7bbf9-m****   1/1     Running   0          18s    172.29.113.156   cn-beijing.10.0.6.47    <none>           <none>
      nginx-9cdf7bbf9-x****   1/1     Running   0          18s    172.29.113.89    cn-beijing.10.0.6.46    <none>           <none>

      由预期输出得到,当节点池A的节点资源不足时,调度到节点池B的节点上。

  5. 对Pod进行缩容。

    1. 执行以下命令,将Pod从4个副本缩容到2个。

      kubectl scale deployment nginx --replicas 2

      预期输出:

      deployment.apps/nginx scaled
    2. 执行以下命令,查看Pod状态。

      kubectl get pods -o wide

      预期输出:

      NAME                    READY   STATUS        RESTARTS   AGE     IP               NODE                    NOMINATED NODE   READINESS GATES
      nginx-9cdf7bbf9-b****   1/1     Running       0          2m41s   172.29.112.216   cn-beijing.10.0.3.137   <none>           <none>
      nginx-9cdf7bbf9-k****   1/1     Running       0          2m41s   172.29.113.24    cn-beijing.10.0.3.138   <none>           <none>
      nginx-9cdf7bbf9-m****   0/1     Terminating   0          78s     172.29.113.156   cn-beijing.10.0.6.47    <none>           <none>
      nginx-9cdf7bbf9-x****   0/1     Terminating   0          78s     172.29.113.89    cn-beijing.10.0.6.46    <none>           <none>

      由预期输出得到,根据调度的逆序,优先缩容在节点池B中的Pod。

场景二:ECS和ECI混合调度

当您需要部署一个Deployment,此时集群中有3种类型的资源,分别是包年包月的ECS、按量付费的ECS和弹性实例ECI。为了降低资源使用成本,您希望部署的服务优先调度顺序依次为:包年包月的ECS、按量付费的ECS、弹性实例ECI。同时在服务缩容时优先删除ECI上的Pod,释放ECI的节点资源,然后删除按量付费的ECS上的Pod,最后删除包年包月的ECS上的Pod。示例节点为2核4 GB,ECS和ECI混合调度的具体操作步骤如下:

  1. 执行以下命令,对不同付费类型的节点分别打不同的label(此处也可以通过节点池的功能自动标识label)。

    kubectl label node cn-beijing.10.0.3.137 paidtype=subscription
    kubectl label node cn-beijing.10.0.3.138 paidtype=subscription
    kubectl label node cn-beijing.10.0.6.46 paidtype=pay-as-you-go
    kubectl label node cn-beijing.10.0.6.47 paidtype=pay-as-you-go
  2. 使用以下YAML内容,创建ResourcePolicy自定义节点池调度顺序。

    apiVersion: scheduling.alibabacloud.com/v1alpha1
    kind: ResourcePolicy
    metadata:
      name: nginx
      namespace: default
    spec:
      selector:
        app: nginx # 此处要与后续创建的Pod的label相关联。
      strategy: prefer
      units:
      - resource: ecs
        nodeSelector:
          paidtype: subscription
      - resource: ecs
        nodeSelector:
          paidtype: pay-as-you-go
      - resource: eci
  3. 使用以下YAML内容创建Deployment,部署2个Pod。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx
      labels:
        app: nginx
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          name: nginx
          labels:
            app: nginx # 此处要上一步创建的ResourcePolicy的selector相关联。
        spec:
          containers:
          - name: nginx
            image: nginx
            resources:
              limits:
                cpu: 2
              requests:
                cpu: 2
  4. 创建应用Nginx并查看部署结果。

    1. 执行以下命令,创建应用Nginx。

      kubectl apply -f nginx.yaml

      预期输出:

      deployment.apps/nginx created
    2. 执行以下命令,查看部署结果。

      kubectl get pods -o wide

      预期输出:

      NAME                    READY   STATUS    RESTARTS   AGE   IP               NODE                    NOMINATED NODE   READINESS GATES
      nginx-9cdf7bbf9-b****   1/1     Running   0          66s   172.29.112.215   cn-beijing.10.0.3.137   <none>           <none>
      nginx-9cdf7bbf9-r****   1/1     Running   0          66s   172.29.113.23    cn-beijing.10.0.3.138   <none>           <none>

      由预期输出得到,前两个Pod被调度到labelpaidtype=subscription的节点上。

  5. 对Pod进行扩容。

    1. 执行以下命令,将Pod扩容到4个。

      kubectl scale deployment nginx --replicas 4

      预期输出:

      deployment.apps/nginx scaled
    2. 执行以下命令,查看Pod状态。

      kubectl get pods -o wide

      预期输出:

      NAME                    READY   STATUS    RESTARTS   AGE     IP               NODE                    NOMINATED NODE   READINESS GATES
      nginx-9cdf7bbf9-4****   1/1     Running   0          16s     172.29.113.155   cn-beijing.10.0.6.47    <none>           <none>
      nginx-9cdf7bbf9-b****   1/1     Running   0          3m48s   172.29.112.215   cn-beijing.10.0.3.137   <none>           <none>
      nginx-9cdf7bbf9-f****   1/1     Running   0          16s     172.29.113.88    cn-beijing.10.0.6.46    <none>           <none>
      nginx-9cdf7bbf9-r****   1/1     Running   0          3m48s   172.29.113.23    cn-beijing.10.0.3.138   <none>           <none>

      由预期输出得到,当labelpaidtype=subscription的节点资源不足时,调度到labelpaidtype=pay-as-you-go的节点上。

    3. 执行以下命令,将Pod扩容到6个。

      kubectl scale deployment nginx --replicas 6

      预期输出:

      deployment.apps/nginx scaled
    4. 执行以下命令,查看Pod状态。

      kubectl get pods -o wide

      预期输出:

      NAME                    READY   STATUS    RESTARTS   AGE     IP               NODE                           NOMINATED NODE   READINESS GATES
      nginx-9cdf7bbf9-4****   1/1     Running   0          3m10s   172.29.113.155   cn-beijing.10.0.6.47           <none>           <none>
      nginx-9cdf7bbf9-b****   1/1     Running   0          6m42s   172.29.112.215   cn-beijing.10.0.3.137          <none>           <none>
      nginx-9cdf7bbf9-f****   1/1     Running   0          3m10s   172.29.113.88    cn-beijing.10.0.6.46           <none>           <none>
      nginx-9cdf7bbf9-r****   1/1     Running   0          6m42s   172.29.113.23    cn-beijing.10.0.3.138          <none>           <none>
      nginx-9cdf7bbf9-s****   1/1     Running   0          36s     10.0.6.68        virtual-kubelet-cn-beijing-j   <none>           <none>
      nginx-9cdf7bbf9-v****   1/1     Running   0          36s     10.0.6.67        virtual-kubelet-cn-beijing-j   <none>           <none>

      由预期输出得到,ECS上的资源不足,Pod被调度ECI的资源上。

  6. 对Pod进行缩容。

    1. 执行以下命令,将Pod从6个副本缩容到4个。

      kubectl scale deployment nginx --replicas 4

      预期输出:

      deployment.apps/nginx scaled
    2. 执行以下命令,命令查看Pod状态。

      kubectl get pods -o wide

      预期输出:

      NAME                    READY   STATUS        RESTARTS   AGE     IP               NODE                           NOMINATED NODE   READINESS GATES
      nginx-9cdf7bbf9-4****   1/1     Running       0          4m59s   172.29.113.155   cn-beijing.10.0.6.47           <none>           <none>
      nginx-9cdf7bbf9-b****   1/1     Running       0          8m31s   172.29.112.215   cn-beijing.10.0.3.137          <none>           <none>
      nginx-9cdf7bbf9-f****   1/1     Running       0          4m59s   172.29.113.88    cn-beijing.10.0.6.46           <none>           <none>
      nginx-9cdf7bbf9-r****   1/1     Running       0          8m31s   172.29.113.23    cn-beijing.10.0.3.138          <none>           <none>
      nginx-9cdf7bbf9-s****   1/1     Terminating   0          2m25s   10.0.6.68        virtual-kubelet-cn-beijing-j   <none>           <none>
      nginx-9cdf7bbf9-v****   1/1     Terminating   0          2m25s   10.0.6.67        virtual-kubelet-cn-beijing-j   <none>           <none>

      由预期输出得到,根据调度节点的逆序,优先缩容在ECI上的Pod。

    3. 执行以下命令,将4个副本缩容到2个。

      kubectl scale deployment nginx --replicas 2

      预期输出:

      deployment.apps/nginx scaled
    4. 执行以下命令,查看Pod状态。

      kubectl get pods -o wide

      预期输出:

      NAME                    READY   STATUS        RESTARTS   AGE     IP               NODE                    NOMINATED NODE   READINESS GATES
      nginx-9cdf7bbf9-4****   0/1     Terminating   0          6m43s   172.29.113.155   cn-beijing.10.0.6.47    <none>           <none>
      nginx-9cdf7bbf9-b****   1/1     Running       0          10m     172.29.112.215   cn-beijing.10.0.3.137   <none>           <none>
      nginx-9cdf7bbf9-f****   0/1     Terminating   0          6m43s   172.29.113.88    cn-beijing.10.0.6.46    <none>           <none>
      nginx-9cdf7bbf9-r****   1/1     Running       0          10m     172.29.113.23    cn-beijing.10.0.3.138   <none>           <none>

      由预期输出得到,根据调度节点的逆序,优先缩容位于labelpaidtype=pay-as-you-go节点上的Pod。

    5. 执行以下命令,查看Pod状态。

      kubectl get pods -o wide

      预期输出:

      NAME                    READY   STATUS    RESTARTS   AGE   IP               NODE                    NOMINATED NODE   READINESS GATES
      nginx-9cdf7bbf9-b****   1/1     Running   0          11m   172.29.112.215   cn-beijing.10.0.3.137   <none>           <none>
      nginx-9cdf7bbf9-r****   1/1     Running   0          11m   172.29.113.23    cn-beijing.10.0.3.138   <none>           <none>

      由预期输出得到,当前只存在labelpaidtype=subscription节点上的Pod。

相关文档

  • 在ACK集群中部署服务时,您可以使用容忍度和节点亲和性来声明只使用ECS或ECI弹性资源,或者是在ECS资源不足时自动申请ECI资源。通过配置调度策略,您可以在不同工作负载场景下实现对弹性资源的不同需求。详细信息,请参见指定ECS和ECI的资源分配

  • 高可用以及高性能是分布式任务执行过程中的重要要求。在ACK集群Pro版中,您可以通过Kubernetes原生调度语义实现分布式任务的跨可用区打散,以达到高可用区部署的要求,或者通过Kubernetes原生调度语义实现分布式任务在指定可用区中的亲和性部署,以达到高性能部署的要求。详细信息,请参见实现ECI Pod可用区打散以及亲和调度