Pod优先级和抢占
FEATURESTATE:KuberNetesv1.14[stable]
Pod可以有优先级。优先级表示一个Pod相对于其他Pod的重要性。如果一个Pod无法被调度,调度程序会尝试抢占(驱逐)较低优先级的Pod,以使悬决Pod可以被调度。
如何使用优先级和抢占
要使用优先级和抢占:
PriorityClass
PriorityClass是一个无名称空间对象,它定义了从优先级类名称到优先级整数值的映射。名称在PriorityClass对象元数据的字段中指定。值在必填的字段中指定。值越大,优先级越高。PriorityClass对象的名称必须是有效的DNS子域名,并且它不能以为前缀。
PriorityClass对象可以设置任何小于或等于10亿的32位整数值。较大的数字是为通常不应被抢占或驱逐的关键的系统Pod所保留的。集群管理员应该为这类映射分别创建独立的PriorityClass对象。
PriorityClass还有两个可选字段:
gLOBalDefault
和
description
。
globalDefault
字段表示这个PriorityClass的值应该用于没有
priorityClassName
的Pod。系统中只能存在一个
globalDefault
设置为true的PriorityClass。如果不存在设置了
globalDefault
的PriorityClass,则没有
priorityClassName
的Pod的优先级为零。
description
字段是一个任意字符串。它用来告诉集群用户何时应该使用此PriorityClass。
关于PodPriority和现有集群的注意事项
PriorityClass示例
apiVersion: scheduling.k8s.io/v1kind: PriorityClassmetadata:name: high-priorityvalue: 1000000globalDefault: falsedescription: "此优先级类应仅用于 XYZ 服务 Pod。"
非抢占式PriorityClass
FEATURESTATE:Kubernetesv1.24[stable]
配置了
preemptionPolicy:Never
的Pod将被放置在调度队列中较低优先级Pod之前,但它们不能抢占其他Pod。等待调度的非抢占式Pod将留在调度队列中,直到有足够的可用资源,它才可以被调度。非抢占式Pod,像其他Pod一样,受调度程序回退的影响。这意味着如果调度程序尝试这些Pod并且无法调度它们,它们将以更低的频率被重试,从而允许其他优先级较低的Pod排在它们之前。
非抢占式Pod仍可能被其他高优先级Pod抢占。
preemptionPolicy
默认为
PreemptLowerPriority
,这将允许该PriorityClass的Pod抢占较低优先级的Pod(现有默认行为也是如此)。如果
preemptionPolicy
设置为,则该PriorityClass中的Pod将是非抢占式的。
数据科学工作负载是一个示例用例。用户可以提交他们希望优先于其他工作负载的作业,但不希望因为抢占运行中的Pod而导致现有工作被丢弃。设置为
preemptionPolicy:Never
的高优先级作业将在其他排队的Pod之前被调度,只要足够的集群资源“自然地”变得可用。
非抢占式PriorityClass示例
apiVersion: scheduling.k8s.io/v1kind: PriorityClassmetadata:name: high-priority-nonpreemptingvalue: 1000000preemptionPolicy: NeverglobalDefault: falsedescription: "This priority class will not cause other pods to be preempted."
Pod优先级
在你拥有一个或多个PriorityClass对象之后,你可以创建在其规约中指定这些PriorityClass名称之一的Pod。优先级准入控制器使用
priorityClassName
字段并填充优先级的整数值。如果未找到所指定的优先级类,则拒绝Pod。
以下YAML是Pod配置的示例,它使用在前面的示例中创建的PriorityClass。优先级准入控制器检查Pod规约并将其优先级解析为1000000。
apiVersion: v1kind: Podmetadata:name: nginxlabels:env: testspec:containers:- name: nginximage: nginximagePullPolicy: IfNotPresentpriorityClassName: high-priority
Pod优先级对调度顺序的影响
当启用Pod优先级时,调度程序会按优先级对悬决Pod进行排序,并且每个悬决的Pod会被放置在调度队列中其他优先级较低的悬决Pod之前。因此,如果满足调度要求,较高优先级的Pod可能会比具有较低优先级的Pod更早调度。如果无法调度此类Pod,调度程序将继续并尝试调度其他较低优先级的Pod。
抢占
Pod被创建后会进入队列等待调度。调度器从队列中挑选一个Pod并尝试将它调度到某个节点上。如果没有找到满足Pod的所指定的所有要求的节点,则触发对悬决Pod的抢占逻辑。让我们将悬决Pod称为P。抢占逻辑试图找到一个节点,在该节点中删除一个或多个优先级低于P的Pod,则可以将P调度到该节点上。如果找到这样的节点,一个或多个优先级较低的Pod会被从节点中驱逐。被驱逐的Pod消失后,P可以被调度到该节点上。
用户暴露的信息
当PodP抢占节点N上的一个或多个Pod时,PodP状态的
nominatednodeName
字段被设置为节点N的名称。该字段帮助调度程序跟踪为PodP保留的资源,并为用户提供有关其集群中抢占的信息。
请注意,PodP不一定会调度到“被提名的节点(NominatedNode)”。调度程序总是在迭代任何其他节点之前尝试“指定节点”。在Pod因抢占而牺牲时,它们将获得体面终止期。如果调度程序正在等待牺牲者Pod终止时另一个节点变得可用,则调度程序可以使用另一个节点来调度PodP。因此,Pod规约中的
nominatedNodeName
和并不总是相同。此外,如果调度程序抢占节点N上的Pod,但随后比PodP更高优先级的Pod到达,则调度程序可能会将节点N分配给新的更高优先级的Pod。在这种情况下,调度程序会清除PodP的
nominatedNodeName
。通过这样做,调度程序使PodP有资格抢占另一个节点上的Pod。
抢占的限制
被抢占牺牲者的体面终止
当Pod被抢占时,牺牲者会得到他们的体面终止期。它们可以在体面终止期内完成工作并退出。如果它们不这样做就会被杀死。这个体面终止期在调度程序抢占Pod的时间点和待处理的Pod(P)可以在节点(N)上调度的时间点之间划分出了一个时间跨度。同时,调度器会继续调度其他待处理的Pod。当牺牲者退出或被终止时,调度程序会尝试在待处理队列中调度Pod。因此,调度器抢占牺牲者的时间点与PodP被调度的时间点之间通常存在时间间隔。为了最小化这个差距,可以将低优先级Pod的体面终止时间设置为零或一个小数字。
支持PodDisruptionBudget,但不保证
PodDisruptionBudget(PDB)允许多副本应用程序的所有者限制因自愿性质的干扰而同时终止的Pod数量。Kubernetes在抢占Pod时支持PDB,但对PDB的支持是基于尽力而为原则的。调度器会尝试寻找不会因被抢占而违反PDB的牺牲者,但如果没有找到这样的牺牲者,抢占仍然会发生,并且即使违反了PDB约束也会删除优先级较低的Pod。
与低优先级Pod之间的Pod间亲和性
只有当这个问题的答案是肯定的时,才考虑在一个节点上执行抢占操作:“如果从此节点上删除优先级低于悬决Pod的所有Pod,悬决Pod是否可以在该节点上调度?”
如果悬决Pod与节点上的一个或多个较低优先级Pod具有Pod间亲和性,则在没有这些较低优先级Pod的情况下,无法满足Pod间亲和性规则。在这种情况下,调度程序不会抢占节点上的任何Pod。相反,它寻找另一个节点。调度程序可能会找到合适的节点,也可能不会。无法保证悬决Pod可以被调度。
我们针对此问题推荐的解决方案是仅针对同等或更高优先级的Pod设置Pod间亲和性。
跨节点抢占
假设正在考虑在一个节点N上执行抢占,以便可以在N上调度待处理的PodP。只有当另一个节点上的Pod被抢占时,P才可能在N上变得可行。下面是一个例子:
如果将PodQ从所在节点中移除,则不会违反Pod间反亲和性约束,并且PodP可能会被调度到节点N上。
如果有足够的需求,并且如果我们找到性能合理的算法,我们可能会考虑在未来版本中添加跨节点抢占。
故障排除
Pod优先级和抢占可能会产生不必要的副作用。以下是一些潜在问题的示例以及处理这些问题的方法。
Pod被不必要地抢占
抢占在资源压力较大时从集群中删除现有Pod,为更高优先级的悬决Pod腾出空间。如果你错误地为某些Pod设置了高优先级,这些无意的高优先级Pod可能会导致集群中出现抢占行为。Pod优先级是通过设置Pod规约中的
priorityClassName
字段来指定的。优先级的整数值然后被解析并填充到的字段。
为了解决这个问题,你可以将这些Pod的
priorityClassName
更改为使用较低优先级的类,或者将该字段留空。默认情况下,空的
priorityClassName
解析为零。
当Pod被抢占时,集群会为被抢占的Pod记录事件。只有当集群没有足够的资源用于Pod时,才会发生抢占。在这种情况下,只有当悬决Pod(抢占者)的优先级高于受害Pod时才会发生抢占。当没有悬决Pod,或者悬决Pod的优先级等于或低于牺牲者时,不得发生抢占。如果在这种情况下发生抢占,请提出问题。
有Pod被抢占,但抢占者并没有被调度
当Pod被抢占时,它们会收到请求的体面终止期,默认为30秒。如果受害Pod在此期限内没有终止,它们将被强制终止。一旦所有牺牲者都离开,就可以调度抢占者Pod。
在抢占者Pod等待牺牲者离开的同时,可能某个适合同一个节点的更高优先级的Pod被创建。在这种情况下,调度器将调度优先级更高的Pod而不是抢占者。
这是预期的行为:具有较高优先级的Pod应该取代具有较低优先级的Pod。

优先级较高的Pod在优先级较低的Pod之前被抢占
调度程序尝试查找可以运行悬决Pod的节点。如果没有找到这样的节点,调度程序会尝试从任意节点中删除优先级较低的Pod,以便为悬决Pod腾出空间。如果具有低优先级Pod的节点无法运行悬决Pod,调度器可能会选择另一个具有更高优先级Pod的节点(与其他节点上的Pod相比)进行抢占。牺牲者的优先级必须仍然低于抢占者Pod。
当有多个节点可供执行抢占操作时,调度器会尝试选择具有一组优先级最低的Pod的节点。但是,如果此类Pod具有PodDisruptionBudget,当它们被抢占时,则会违反PodDisruptionBudget,那么调度程序可能会选择另一个具有更高优先级Pod的节点。
当存在多个节点抢占且上述场景均不适用时,调度器会选择优先级最低的节点。
Pod优先级和服务质量之间的相互作用
Pod优先级和QoS类是两个正交特征,交互很少,并且对基于QoS类设置Pod的优先级没有默认限制。调度器的抢占逻辑在选择抢占目标时不考虑QoS。抢占会考虑Pod优先级并尝试选择一组优先级最低的目标。仅当移除优先级最低的Pod不足以让调度程序调度抢占式Pod,或者最低优先级的Pod受PodDisruptionBudget保护时,才会考虑优先级较高的Pod。
kubelet使用优先级来确定节点压力驱逐Pod的顺序。你可以使用QoS类来估计Pod最有可能被驱逐的顺序。kubelet根据以下因素对Pod进行驱逐排名:
当某Pod的资源用量未超过其请求时,kubelet节点压力驱逐不会驱逐该Pod。如果优先级较低的Pod没有超过其请求,则不会被驱逐。另一个优先级高于其请求的Pod可能会被驱逐。
发表评论