本文中含有需要您注意的重要提示信息,忽略该信息可能对您的业务造成影响,请务必仔细阅读。
自定义弹性资源优先级调度是阿里云提供的弹性调度策略。您可以在应用发布或扩容过程中,自定义资源策略(ResourcePolicy),设置应用实例Pod被调度到不同类型节点资源的顺序。同时,在缩容过程中按照原调度顺序逆序缩容。
请勿在工作负载的标签选择器(如Deployment的spec.selector.matchLabels)中使用系统保留标签(如alibabacloud.com/compute-class、alibabacloud.com/compute-qos)。这些标签可能在自定义优先级调度期间被系统修改,导致控制器频繁重建Pod,影响应用稳定性。
前提条件
- 已创建1.20.11及以上版本的ACK托管集群Pro版。如需升级,请参见手动升级集群。 
- 对于不同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。 
注意事项
- 自调度器版本v1.x.x-aliyun-6.4开始,自定义弹性资源优先级的 - ignorePreviousPod字段的默认值修改为- False;- ignoreTerminatingPod修改为- True。涉及这些字段的存量ResourcePolicy不受影响,后续更新也不受影响。
- 本功能与pod-deletion-cost冲突,不能同时使用。 
- 本功能暂不支持与通过ElasticResource实现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:
  selector:
    key1: value1
  strategy: prefer
  units:
  - nodeSelector:
      unit: first
    podLabels:
      key1: value1
    podAnnotations:
      key1: value1
    resource: ecs
  - nodeSelector:
      unit: second
    max: 10
    resource: ecs
  - resource: eci
  # Optional, Advanced Configurations
  preemptPolicy: AfterAllUnits
  ignorePreviousPod: false
  ignoreTerminatingPod: true
  matchLabelKeys:
  - pod-template-hash
  whenTryNextUnits:
    policy: TimeoutOrExceedMax
    timeout: 1m- selector:声明ResourcePolicy作用于同一命名空间下- label上打了- key1=value1的Pod。- selector为空时将对该命名空间下所有Pod生效。
- strategy:调度策略选择,目前只支持- prefer。
- units:用户自定义的调度单元。扩容时,将按照- units下资源的顺序进行扩容;缩容时,将按照逆序进行缩容。- resource:弹性资源的类型,目前支持- eci、- ecs、- elastic以及- acs四种类型。- elastic在集群版本为1.24以上,且调度器版本为6.4.3及以上版本可用。- acs在集群版本为1.26以上,且调度器版本为6.7.1及以上版本可用。说明- elastic即将废弃。建议通过PodLabels中的- k8s.aliyun.com/resource-policy-wait-for-ecs-scaling: "true"的方式使用自动伸缩节点池。说明- acs类型将会默认为Pod添加- alibabacloud.com/compute-class: default以及- alibabacloud.com/compute-class: general-purpose的标签。您可以通过在PodLabels中声明不同的Value来对默认值进行覆盖。当PodAnnotation声明了- alpha.alibabacloud.com/compute-qos-strategy时,将不会默认添加- alibabacloud.com/compute-class: default。重要- 在调度器6.8.3以下的版本中,不支持同时使用多个 - acs的Unit。
- nodeSelector:用- node的- label标识该调度单元下的节点,只对- ecs资源生效。
- max(调度器为5.0版本及以上可用):在本调度单元中最多能调度的Pod的副本数。
- maxResources(调度器为6.9.5版本及以上可用):在本调度单元中最多能调度的Pod的资源量。
- podAnnotations:类型是- map[string]string{},配置在- podAnnotations中Key-Value将会由调度器更新到Pod上。在进行该Unit中的Pod数量统计时只有带有这些Key-Value的Pod会被统计。
- podLabels:类型是- map[string]string{},配置在- podLabels中Key-Value将会由调度器更新到Pod上。在进行该Unit中的Pod数量统计时只有带有这些Key-Value的Pod会被统计。说明- 当Unit的PodLabels中包含 - k8s.aliyun.com/resource-policy-wait-for-ecs-scaling: "true",或当前Unit的Pod数量低于设置的Max值时。Scheduler会让Pod在当前的Unit中等待。等待的时间可以在- whenTryNextUnits中设置。并且- k8s.aliyun.com/resource-policy-wait-for-ecs-scaling: "true"不会被更新到Pod上。统计Pod数量时也不要求Pod上带有该标签。
 
- preemptPolicy(调度器为6.1版本及以上可用,该参数对ACS不生效):当ResourcePolicy中存在多个- unit时,是否允许ResourcePolicy在每个Unit调度失败时尝试抢占。BeforeNextUnit表示调度器将在每个Unit调度失败时尝试抢占,AfterAllUnits表示ResourcePolicy只在最后一个Unit调度失败时尝试抢占。默认为AfterAllUnits。- 您可以通过配置ACK Scheduler参数,开启抢占。 
- 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采用的策略。可选值包括- ExceedMax、- LackResourceAndNoTerminating、- TimeoutOrExceedMax、- LackResourceOrExceedMax(默认值)。- ExceedMax:若当前Unit的Max以及MaxResources未设置,或当前Unit中的Pod数量大于等于设置的Max值(或当前Unit中的已使用资源量加上当前Pod超过MaxResource),允许Pod使用下一级资源。该策略可以与自动伸缩以及ECI配合,达到优先尝试节点池自动伸缩的效果。重要- 请注意,如果自动伸缩节点池长时间无法弹出节点,此策略可能导致Pod处于Pending状态。 
- 当前由于Cluster Autoscaler未感知ResourcePolicy的Max限制,实际弹出的实例数可能会多于设置的Max值。该问题将在后续版本中进行优化。 
 
- TimeoutOrExceedMax:当满足以下条件之一:- 当前Unit的Max已设置且Unit中的Pod数量小于设置的Max值或MaxResources已设置且已调度资源量加上当前调度Pod资源量小于设置的MaxResources时; 
- 当前Unit的Max未设置,且当前Unit的PodLabels中包含 - k8s.aliyun.com/resource-policy-wait-for-ecs-scaling: "true";
 - 若当前Unit资源不足以调度Pod,则在当前Unit中等待,等待时间的最大长度为 - timeout。该策略可以与自动伸缩以及ECI配合,达到优先尝试节点池自动伸缩,并且在超时后自动使用ECI的效果。重要- 请注意,若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(ACS Unit不支持timeout参数,只受到Max限制):当policy为- timeoutOrExceedMaxPolicy时,该字段可以被用来描述超时时长,当该字段为空值时,我们将此值视为15分钟。
 
使用场景示例
场景一:基于节点池优先级调度
当您需要部署一个Deployment,此时集群有两个节点池,一个是节点池A,一个是节点池B。您希望优先调度节点池A,资源不足时调度节点池B。当进行缩容时,优先缩容在节点池B中的Pod,然后缩容节点池A中的Pod。如下示例中,cn-beijing.10.0.3.137和cn-beijing.10.0.3.138属于节点池A, cn-beijing.10.0.6.47和cn-beijing.10.0.6.46属于节点池B,节点规格均为2核4 GB。基于节点池优先级调度的具体操作步骤如下:
- 使用以下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可以从所在集群的节点管理 > 节点池中获取。具体操作,请参见创建和管理节点池。 
- 使用以下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
- 创建应用Nginx并查看部署结果。 - 执行以下命令,创建应用Nginx。 - kubectl apply -f nginx.yaml- 预期输出: - deployment.apps/nginx created
- 执行以下命令,查看部署结果。 - 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的节点上。 
 
- 对Pod进行扩容。 - 执行以下命令,将Pod扩容到4个。 - kubectl scale deployment nginx --replicas 4- 预期输出: - deployment.apps/nginx scaled
- 执行以下命令,查看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的节点上。 
 
- 对Pod进行缩容。 - 执行以下命令,将Pod从4个副本缩容到2个。 - kubectl scale deployment nginx --replicas 2- 预期输出: - deployment.apps/nginx scaled
- 执行以下命令,查看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混合调度的具体操作步骤如下:
- 执行以下命令,对不同付费类型的节点分别打不同的 - 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
- 使用以下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
- 使用以下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
- 创建应用Nginx并查看部署结果。 - 执行以下命令,创建应用Nginx。 - kubectl apply -f nginx.yaml- 预期输出: - deployment.apps/nginx created
- 执行以下命令,查看部署结果。 - 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被调度到 - label为- paidtype=subscription的节点上。
 
- 对Pod进行扩容。 - 执行以下命令,将Pod扩容到4个。 - kubectl scale deployment nginx --replicas 4- 预期输出: - deployment.apps/nginx scaled
- 执行以下命令,查看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>- 由预期输出得到,当 - label为- paidtype=subscription的节点资源不足时,调度到- label为- paidtype=pay-as-you-go的节点上。
- 执行以下命令,将Pod扩容到6个。 - kubectl scale deployment nginx --replicas 6- 预期输出: - deployment.apps/nginx scaled
- 执行以下命令,查看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的资源上。 
 
- 对Pod进行缩容。 - 执行以下命令,将Pod从6个副本缩容到4个。 - kubectl scale deployment nginx --replicas 4- 预期输出: - deployment.apps/nginx scaled
- 执行以下命令,查看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。 
- 执行以下命令,将4个副本缩容到2个。 - kubectl scale deployment nginx --replicas 2- 预期输出: - deployment.apps/nginx scaled
- 执行以下命令,查看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>- 由预期输出得到,根据调度节点的逆序,优先缩容位于 - label为- paidtype=pay-as-you-go节点上的Pod。
- 执行以下命令,查看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>- 由预期输出得到,当前只存在 - label为- paidtype=subscription节点上的Pod。
 
相关文档
- 在ACK集群中部署服务时,您可以使用容忍度和节点亲和性来声明只使用ECS或ECI弹性资源,或者是在ECS资源不足时自动申请ECI资源。通过配置调度策略,您可以在不同工作负载场景下实现对弹性资源的不同需求。详细信息,请参见指定ECS和ECI的资源分配。 
- 高可用以及高性能是分布式任务执行过程中的重要要求。在ACK托管集群Pro版中,您可以通过Kubernetes原生调度语义实现分布式任务的跨可用区打散,以达到高可用区部署的要求,或者通过Kubernetes原生调度语义实现分布式任务在指定可用区中的亲和性部署,以达到高性能部署的要求。详细信息,请参见实现ECI Pod可用区打散以及亲和调度。