Pod可以拥有优先级.优先意味着相对于其它pod某个pod更为重要.如果重要的pod不能被调度,则kubernetes调度器会优先于(驱离)低优先级的pod来让处于pending状态的高优先级pod被调度.
kubernetes 1.9以后,优先级会影响pod的调度顺序和资源耗尽时pod的驱离顺序
警告:在一个不是所有用户都被信任的集群里,可能有恶意用户创建最高可能优先级的pod,导致其它pod被驱离或者无法调度.为了解决这个问题,需要增大资源配额来支持优先pod.集群管理员可以为特定用户创建特定优先级级别,防止他们创建高优先级的pod.这项功能在1.12版本里为beta状态.
怎样使用优先级和抢占
在1.11或以后的版本里,按下面指示来操作:
创建一个或者多个
PriorityClasses
创建一个pod,并把
priorityClassName
设置为以上添加的priorityClassName
中的一个.当然你不必直接创建pod,你可以把priorityClassName
添加到集合对象(比如deployment)的template里.
如果你仅想尝试这项功能并且然后把它禁用,你必须把PodPriority
设置为false,然后重启apiserver和调度器.被禁用以后,已经存在的pod仍然保留有它们的优先级字段,但是抢占不会再生效,并且优先字段被忽略.你也不能再向新的pod添加priorityClassName
字段
怎样禁用抢占
在kubernetes 1.12+ 当集群处于较大资源压力时,一些关键的pod依赖抢占调度.因此强烈为建议禁用抢占
在kubernetes1.11以后版本,抢占被kube-scheduler的的disablePreemption
标识控制,默认设置是false.如果你不顾建议仍然想要禁用它,可以把它设置为true
这个选项仅仅在组件的配置里有效,在旧式的命令行下无效.下面是一个配置的示例:
apiVersion: componentconfig/v1alpha1
kind: KubeSchedulerConfiguration
algorithmSource:
provider: DefaultProvider
...
disablePreemption: true
抢占
当pod被创建,他们进入队列等待被调度.调度器从队列取出一个pod并且尝试把它调度到一个节点上.如果没有节点能够满足这个pod的所有要求,抢占逻辑被触发,我们把这个挂起的pod称作P.调度器尝试寻找移除一个或者多个比P低的pod后能够使得P被调度的节点.如果找到了一个这样的节点,一个或者多个优先级低的节点被驱离,然后P被调度到这个节点上.
当pod P抢占了Node N上的一个或者多个pod的资源,P的nominatedNodeName(候选节点)
字段被设置为节点N的名字.这个字段帮助调度器追踪为P预留的资源信息,并给用户提供集群资源抢占的一些信息.
需要注意的是pod P并不总是调度到候选节点(nominated Node)上,当受害的pod被抢占,他们进入终止阶段.当受害pod停止的过程中其它节点变得可用,这时候调度器就会使用这个可用的节点来接收pod P,这样就造成nominatedNodeName
和nodeName
并不总是相同.并且,pod P抢占了节点N上的优先级低的pod的资源时,这时候有更高优先级的pod到达,这时候调度器可能会把节点N让给这个更高优先级的pod使用.这时候调度器会清除pod P的nominatedNodeName
字段,这样,调度器使用pod P可以抢占其它节点上的资源.
抢占限制
受害pod的优雅终止
当被抢占,受害pod进入优雅终止期,它们将有时间完成工作并退出.否则,会被杀掉.这个优雅终止期在调度器抢占受害pod资源和优先pod被调度到Node N之间创建了一个时间间隔.同时,调度器继续调度其它状态为pending
的pod.为了缩短这个时间间隔,用户可以把优雅终止期设置为0或者一个很小的时间
低优先级pod的pod间亲和性
问题:如果所有低优先级的pod都从一个节点上移除了,那么挂起(pending)的pod是否可以调度到此节点上?
这个问题的意义在于如果所有的pod都被移除,资源仍然不够容纳挂起的pod会怎么样?
仅当以上问题的答案是肯定的(yes)的时候,节点的抢占才会发生(也就是如果全部低优先级的pod都被驱离仍然不够容纳新的pod时,节点上不会发生抢占)
需要注意的是,并不是总是要移除节点上的所有低优先级的pod.如果仅仅移除一些pod就足以容纳挂起的pod时,仅有部分低优先级的pod被移除.但是以上问题的答案仍然需要是肯定的(也就是说低优先级pod的移除建立在移除后资源足以容纳新的挂起的节点的基础上的)
如果挂起的pod(即将被调度的)和一个或者多个节点N上的低优先级的pod有pod间亲和关系,如果低优先级pod离开后pod间的亲和关系不能被满足时,调度器这时候不会再抢占节点N上的pod.调度器可能会找到一个其它的合适的节点,也可能找不到.这就无法保证挂起的pod被调度.
对于这个问题我们的建议是创建pod间亲和关系时,只向同等优先级和更高优先级的pod创建.
跨节点抢占
假设Node N 上准备抢占以便是pod P可以被调度到N上,但是P依赖于其它节点上的pod被驱离才可以被调度到N上,以下示例说明这个问题
Pod P准备调度到节点N上
pod Q们于和节点N同一区域的其它节点上
pod P和pod Q有区域级别的反亲和关系(topologyKey:
failure-domain.beta.kubernetes.io/zone
)pod P和同一区域内的其它pod没有反亲和关系
为了把pod P调度到节点N上,Pod Q可以被抢占,但是调度器不会执行跨节点抢占,因此pod P不会被调度到节点N上.
如果pod Q从它的节点上移除,这时候违反亲和关系也消失,此时pod P可能会被调度到节点N上
在未来的版本中如果能找到一个能保证性能的算法,我们可能会考虑增加跨节点驱离.但是目前我们什么都不能保证.
调度pod优先级和抢占
pod优先级和资源抢占的编排如果有bug的话则往往是导致节点调度中断的主要原因之一
pod优先级和资源抢占可能导致的问题
以下是如果pod优先级和资源抢占包含bug可能导致的问题的不完全罗列:
- pod被非必要地抢占
当集群出现资源压力时,调度器会移除优先级低的pod来为优先级高的pod腾出资源,如果用户错误地给分配给一些pod过高的优先权,这些无意分配的高优先权会导致集群抢占.像上面提到的,pod的优先权通过设置podSpec
字段的priorityClassName
来实现的,优先级的整数字段然被解析后传入到podSpec
字段的priority
字段里
为了解决这个问题,priorityClassName
字段必须改变到更小的优先级或者留空,priorityClassName
字段留空会被解析为0
当一个pod被抢占,则它会产生一条event记录来记录这个事件.仅当集群没有足够的资源时抢占才会发生.这种情况仅发生在(挂起)的pod的优先级高于受害pod.如果没有挂起的pod,则抢占事件一定不能发生.如果没有挂起pod,或者挂起pod的优先级等于或小于受害pod时发生抢占事件,则是系统bug,请提交一个issue给我们.
pod被抢占,但是抢占的pod并没有被调度
当pod被抢占,他们将接收到一个优雅停止的时间段,默认是30秒,但是也可以是任意在podSpec里指定的值.如果受害pod没有在指定的时段里停止,他们会被强行终止.当所有受害者都被移除,优先pod可以被调度.
当优先pod等待受害者被移除时,一个适合调度到这个节点上的更高优先级的pod被创建.这时候调度器会优先调度这个更高优先级的pod
高优先级的pod比优先级更低的pod被抢占
调度器会尽力寻找适合的节点来调度挂起的pod,如果找不一节点来调度,调度器会从一个包含低优先级的节点上移除pod来为挂起的pod腾出空间.如果有低优先级pod的节点不适合被调度,调度器可能会选择一个更高优先级的节点来抢占(这里说的更高是相对前面找到的低优先级的pod而言的,而不是对优先pod而言的).被抢占的pod仍然必须要比优先pod(指挂起的需要调度的pod)优先级别低
当有多个节点可以被抢占时,调度器会尝试选择有最低优先级pod的节点来调度.但是如果pod有PodDisruptionBudget
并且抢占可能会违反PodDisruptionBudget
时,调度器可能会选择一个更高优先级的pod来抢占.
当有多个节点可以被抢占并且没有出现以上情形,则调度器会选择优先级最低的pod来抢占,如果不是这样的,则意味着调度器本身存在bug.
pod优先级和Qos交互
pod优先级和QoS是两个正交的功能,几乎没有交叉.调度器的抢占逻辑当选择抢占对象时不会考虑QoS.抢占会考虑pod的优先级并选择出一系列低优先级抢占目标.只有当即便移除低优先级pod也不足以运行挂起的pod或者低优先级的pod被PodDisruptionBudget
保护时,调度器才会选择更高优先级的pod作为抢占对象.
仅有Kubelet的 out-of-resource eviction组件才会同时考虑pod优先级和QoS,kubelet首先会根据使用的资源是否超过请求的值来对要驱离的pod进行排序,然后根据优先级.Kubelet out-of-resource eviction 不会驱离使用资源低于请求资源的pod,如果一个低优先级的pod使用的资源没有超过它请求的,则它不会被驱离.其它的使用资源超过其申请资源的更高优先级的pod可能会被驱离.