标签搜索

容器的调度策略介绍

mrui
2025-04-18 / 0 评论 / 33 阅读 / 正在检测是否收录...

kubernetes scheduler是负责Pod调度的进程(组件),它的作用是先对等待调度的Pod通过一些复杂的调度流程计算出其最佳的目标Node,再將Pod绑定到目标Node上。

随着kubernetes功能的不断增强和完善,Pod的调度也变得越来越复杂。Scheduler内部的实现机制也在不断优化,从最初的两阶段调度机制(Predicates&Priorities)发展到现在的调度框架(Scheduling Framework),以满足越来越复杂的调度场景。

Pod调度复杂的原因:kubernetes要努力满足不同类型应用的不同需求并努力让大家和平相处。

kubernetes集群里的Pod可以分为三类:无状态服务类,有状态集群类,批处理类。不同类型的Pod对资源占用的需求不同,对Node故障引发的中断/恢复及Node迁移方面的容忍度不同。

调度流程

kube-apiserver将待调度的Pod的信息发送给kube-scheduler,scheduler通过一系列的计算把Pod要绑定的最优Node(或者暂时不存在)信息返还返还给apiserver。

调度流程
  1. 过滤阶段(Filtering):遍历所有的Node,筛选出符合要求的候选Node。此阶段Scheduler会将不合适的Node全部过滤掉,只留下符合条件的候选Node。具体方式是通过一系列待定的Predicates对每个Node进行筛选,在筛选完成后通常会有多个候选Node供调度,从而进入打分阶段。如果筛选的结果集为空,则表示当前没有符合条件的Node,此时Pod会一直处于Pending状态。
  2. 打分阶段(Scoring):在过滤阶段的基础上,采用优选策略计算出每个候选Node的积分,积分最高者胜出。在挑选出最佳Node后,Scheduler会把目标Pod安置到该Node上,完成调度。

注:当Node处于以下状态时,Scheduler不在给它调度新的Pod。

  • NotReady
  • Unschedulable
  • MemoryPressure(不再调度新的BestEffort PodPod到这个Node)
  • DiskPressure

调度策略

指定Node名称的定向调度策略

Kubernetes支持在Pod的配置中通过指定nodeName字段的方式指定要调度的目标Node名称。这个字段的优先级高于nodeSelector和亲和性策略。设置了nodeName字段的Pod将不再参与调度器的调度过程,相当于已经完成了调度,apiserver将直接通知目标Node上的kubelet开始创建这个Pod。
使用nodeName具有以下限制:

  • 如果指定的node不存在或者失联,则Pod将无法运行;
  • 如果指定的node资源不足,则pod可能会运行失败;
  • 在某些云环境下,node名称不一定是稳定的。
  • 验证一下污点策略的优先级
    示例:

    ---
    apiVersion: v1
    kind: pod
    metadata:
    name: nginx
    spec:
    containers:
    - name: nginx
      image: nginx
    nodeName: 192.168.88.61
基于Node Label的调度策略

Node也是kubernetes管理的一种资源对象,可以为其设置多个Label。在Pod的配置中,可以方便的使用Label Selector来声明需要调度到具有指定Label的Node上,调度器会在具有这些Label的Node中进行选择。

通过基于Node Label的调度方式,可以把集群中具有不同特点的Node都贴上不同的Label(如“role=frontend”,“role=backend”,“role=database”等),在部署应用时可以根据应用的需求设置NodeSelector来进行指定Node范围的调度。

需要注意的是,如果指定了nodeselector条件,但是在集群中不存在包含相应Label的Node,那么集群中即便存在可供使用的Node,这个Pod也无法被成功调度。
示例:

---
apiVersion: v1
kind: pod
metadata:
  name: pod-node-selector
spec:
  nodeSelector:
    disk: ssd
  containers:
  - name: busybox
    image: busybox
    command: ['sh','-c','sleep 3600']
亲和性调度策略

亲和性和反亲和性的机制,扩展了Pod的调度能力,实现了更加灵活和精细的策略。其具有如下优点:

  • 更强的逻辑选择能力(不仅仅是“符合全部”的简单情况)
  • 可以设置为软性限制或优选,使得调度器在无法找到全部满足要求的Node时,也会寻找其他Node来调度Pod。
  • 除了基于Node上的Label,还可以依据Node上正在运行的其他Pod的Label来进行亲和性和反亲和性设置。这样可以定义一组规则来描述Pod间的亲和或者互斥关系。
    亲和性调度功能包括节点亲和性(NodeAffinity)和Pod亲和性(PodAffinity)两种类型。
节点亲和性调度策略

节点亲和性调度策略与NodeSelector类似,但表达能力更强,并且允许设置软性匹配规则。设置方法也是通过Node上的Label来设置Pod是否可以调度到目标Node上。

节点亲和性的配置类型有以下两种:

  • requiredDuringSchedulingIgnoredDuringExecution:必须满足指定的规则才可以调度Pod到Node上,是硬性要求,它的功能与nodeSelector相似,但是使用的是更加灵活的语法。
  • preferredDuringSchedulingIgnoredDuringExecution:强调优先满足指定规则,调度器会尝试调度Pod到Node上,但并不强求,是软性限制。可以设置多个规则,还可以给每个规则设置权重值(weight),以定义判断的优先级顺序。

权重
可以为每个规则设置一个1-100的权重值(weight),用于给调度器提供一个类似于优先级的分数,调度器会为满足条件的Node加上weight设置的值,以选出最终得分最高的Node。

这两种策略中的IgnoredDuringExecution的意思是:如果一个Pod所在的节点在Pod运行期间其标签发生了变化,不再符合该Pod的亲和性需求,则系统将忽略Node上的Label变化,让Pod在原Node上继续运行。也就是说Pod正常运行后,不再对Node进行亲和性验证。

在Label的匹配规则中,使用逻辑操作符(operator)进行设置,可用使用的操作符及其含义如下:

  • In:Label的值(value)在给定的集合中。
  • NotIn: Label的值(value)不在给定的集合中。
  • Exists:需要具有此Label Key,此时不需要设置key的值。
  • DoseNotExist:需要不存在此Label的值,此时不需要设置key的值。
  • Gt;Label的值(Value)的整数值需要大于给定的值。
  • Lt:Label的值(Value)的整数值需要小于给定的值。

Pod亲和性调度策略

Pod亲和性:存在某些相互依赖,需要频繁互相调用的Pod,它们需要被尽可能地部署在同一个节点、机架、机房、网段或者区域(Zone)内。

Pod反亲和性:处于避免竞争或者容错的需求,也可能使某些Pod尽可能地远离另外一些Pod。

简单来说,某几个Pod可以在同一个拓扑域中共存,就是“Pod Affinity”,不能在同一个拓扑域中共存,就是“Pod Anti Affinity”。

Pod亲和性与反亲和性调度的具体做法,就是通过在Pod的定义中增加topologyKey属性,来声明对应的目标拓扑域内几种相关联的Pod是“在一起还是不在一起”。

需要注意的是,对于Pod的反亲和性策略,要求目标Node上需要存在相同的Label,实际上就是要求每个节点都具有相同的topologyKey指定的Label。如果某些Node不具有topologyKey指定的Label,则可能造成不可预估的调度结果。

另外,设置Pod间的亲和性和反亲和性规则,会给调度器引入更多的计算量,在大规模集群中可能会造成性能问题,因此在配置Pod间的亲和性策略时需要谨慎。

关于topoloygKey:

拓扑域:一个拓扑域由一些Node组成。这些Node通常具有相同的地理空间坐标。比如,在同一个机架、机房或地区。一般用Region表示机架、机房等的拓扑区域,用Zone表示地区这样跨度更大的拓扑区域。在某些情况下,可以认为一个Node就是一个拓扑区域。

kubernetes为Node内置了一些常用的用于表示拓扑域概念的Label。

  • kubernetes.io/hostname
  • topoloyg.kubernetes.io/region
  • topoloyg.kubernetes.io/zone

以上拓扑域是由kubernetes自己维护的。在node初始化时,Controller Manager会为Node设置许多标签。如,kubernetes.io/hostname这个标签的值会被设置为Node的hostname,云厂商会设置topoloyg.kubernetes.io/region和topoloyg.kubernetes.io/zone的值,以确定各个Node所属的拓扑域。

污点和容忍度调度策略

污点(Taint)配置在Node上,可以让Node拒绝一些具有某些特征的Pod在其上运行。容忍度(Toleration)配置在Pod中,用于高速系统允许调度到具有指定污点的节点上运行。

默认情况下,在Node上设置一个或多个Taint后,除非Pod声明中明确能够容忍这些污点,否则无法在这些Node上运行。

污点和容忍度的配合使用,可以避免将Pod调度到不合适的Node上。例如,某个Node存在问题(磁盘空间不足,计算资源不足,存在安全隐患等),希望新的Pod不要调度过来,就可以通过设置某些污点来实现。但设置了污点的Node并非不可用,仍是有效的Node。所以对于可用在这些Node上运行的Pod,可以给Pod设置与污点匹配的容忍度来实现调度。

污点策略:

  • PreferNoSchedule 尽量不调度,一个Pod如果没有声明容忍这个Taint,则系统会尽量避免把这个Pod调度到这一个Node上,但不保证一定能够避免
  • NoScheduler 不被调度,除非Pod设置了与Taint匹配的容忍度。
  • NoExecute 驱逐节点,不能在改node上运行,包括以下几种情况。

    对于正在该Node上运行的Pod,如果不能容忍指定的污点,则会被立刻从该Node驱逐。
    对于正在该Node上运行的Pod,如果能够容忍指定的污点,但未设置运行时限(tolerationSeconds),则会在该Pod上持续运行。
    对于正在该Node上运行的Pod,如果能够容忍指定的污点,但设置了运行时限(tolerationSeconds),则会在到达运行时限后从该Node上被驱逐。

添加污点标签

kubectl taint node node-0001 key=v1:PreferNoSchedule
kubectl taint node node-0002 key=v2:NoScheduler

容忍策略

优先级和抢占调度策略

技术背景:对于运行各种负载(如Service,Job)的中等规模或者大规模的集群来说,需要尽可能提高集群的资源利用率。常规做法是采用优先级方案,即不同类型的负载对应不同的优先级,同时允许集群中的所有负载 所需要的资源总量超过集群可提供的资源。在这种情况下,当资源不足时,系统可以选择释放一些低优先级的负载,保障高优先级的负载获得足够的资源稳定运行。

调度方式:
由集群管理员创建priorityClass,Priority是不受限于命名空间的资源类型


其中,优先级的值越高,优先级越高,允许的设置范围是(-2147483648到1000000000),最大值是10亿,超过10亿的数字被系统保留,用于设置给系统组件。

在上面的配置中,globalDefault设置为true表示这个优先级配置是全局默认配置,即对没有配置priorityCKassName的Pod都默认使用这个优先级设置。

在系统没有设置全局默认优先级的情况下,对于没有配置priorityClassName的Pod,系统默认设置这些Pod的优先级为0。

description字段用于设置一个说明,通常用来描述该priorityClass的用途。

preemptionPolicy字段用于设置抢占策略。可用设置的策略有下面两个:

  • PreemptLowerPriority:默认策略,表示允许具有该priorityClass优先级的Pod抢占较低优先级Pod的资源。
  • Never:具有该优先级的Pod会被置于调度优先级队列中优先级数值更低的Pod之前,但不抢占其他Pod的资源,这些Pod将一直在调度列队中等待,知道有足够的可用资源后,才会被调度。
抢占式调度的主要流程
  1. 考察每个候选Node,找出为了满足新Pod的调度要求,需要释放的最少Pod实例;
  2. 以抢占导致的代价最小原则,对筛查出来的所有候选Node进行考察,挑选出最优的候选Node作为最终被占用的目标Node;
  3. 把目标Node与新Pod绑定,使得新Pod在下一轮的调度过程中可以使用这个目标Node来完成最终的调度流程,同时,调用APIServer删除目标Node上需要被释放的Pod以释放Node资源。
最优Node选择规则
  1. 拥有最小违反PodDisruptionBudget约束的Node;
  2. 把Node上被释放的拥有最高优先级的Pod都找出来并进行比较,优先级排名垫底的Pod所在的Node;
  3. 被释放的Pod的优先级之和(目标Pod需要的资源可能需要释放多个Pod才能满足)排名垫底的Node;
  4. 被释放的Pod数量最少的Node;
  5. 把Node上被释放的拥有最高优先级的Pod找出来,最晚启动的那个Pod所在的Node
  6. 如果上述步骤还是无法选出最佳Node(可供选择的Node还有多个),就随机选择一个。
注意事项

如果目标Pod与候选Node上的某个优先级比它低的Pod之间有亲和性,则发生资源抢占后(这个低优先级的Pod被删除),目标pod不满足节点亲和性规则,此时该Node不符合抢占要求,Scheduler会考虑其他候选Node,无法保证目标Pod调度成功。要避免此类情况,要注意Pod亲和性和优先级的关系——具有亲和性关系的Pod不应该被设置为低优先级的。

0

评论 (0)

取消