1.7. 在 pod 调度决策中纳入 pod 优先级
您可以在集群中启用 pod 优先级与抢占功能。Pod 优先级指明 pod 相对于其他 pod 的重要程度,并根据这个优先级对 pod 进行排队。Pod 抢占则允许集群驱除低优先级 pod 或与之争抢,从而在合适的节点上没有可用空间时能够调度优先级较高的 pod。pod 优先级也会影响 pod 的调度顺序以及节点上资源不足驱除顺序。
要使用优先级和抢占功能,您需要创建优先级类来定义 pod 的相对权重。然后,在 pod 规格中引用优先级类,以应用这个权重来进行调度。
抢占通过调度程序配置文件中的 disablePreemption
参数来进行控制,该参数默认设置为 false
。
1.7.1. 了解 pod 优先级
当您使用 pod 优先级与抢占功能时,调度程序会根据优先级来调度待处理 pod,而待处理 pod 会放在调度队列中优先级较低的其他待处理 pod 的前面。因此,如果达到调度要求,较高优先级的 pod 可能比低优先级的 pod 更早调度。如果 pod 无法调度,调度程序会继续调度其他较低优先级 pod。
1.7.1.1. Pod 优先级类
您可以为 pod 分配一个优先级类,它是一种非命名空间的对象,用于定义从名称到优先级整数值的映射。数值越大,优先级越高。
优先级类对象可以取小于或等于 1000000000(十亿)的 32 位整数值。对于不应被抢占或驱除的关键 pod,可保留大于十亿的数值。默认情况下,OpenShift Container Platform 有两个保留优先级类,用于需要保证调度的关键系统 pod。
$ oc get priorityclasses NAME CREATED AT cluster-logging 2019-03-13T14:45:12Z system-cluster-critical 2019-03-13T14:01:10Z system-node-critical 2019-03-13T14:01:10Z
system-node-critical - 此优先级类的值为 2000001000,用于所有不得从节点上驱除的 pod。具有此优先级类的 pod 示例有
sdn-ovs
和sdn
等。许多关键组件默认包括system-node-critical
优先级类,例如:- master-api
- master-controller
- master-etcd
- sdn
- sdn-ovs
- sync
system-cluster-critical - 此优先级类的值是 2000000000(二十亿),用于对集群而言很重要的 pod。在某些情况下,具有此优先级类的 Pod 可以从节点中驱除。例如,配置了
system-node-critical
优先级类的 pod 可以拥有优先权。不过,此优先级类确实能够保证调度。具有此优先级类的 pod 示例有 fluentd 以及 descheduler 这样的附加组件等。许多关键组件默认包括system-cluster-critical
优先级类,例如:- fluentd
- metrics-server
- descheduler
- cluster-logging - 此优先级类供 Fluentd 用于确保 Fluentd pod 优先于其他应用调度到节点上。
如果升级现有的集群,则现有 pod 的优先级相当于为零。不过,带有 scheduler.alpha.kubernetes.io/critical-pod
注解的现有 pod 会自动转换为 system-cluster-critical
类。带有该注解的 Fluentd 集群日志 pod 转换为 cluster-logging
优先级类。
1.7.1.2. Pod 优先级名称
拥有一个或多个优先级类后,您可以创建 pod,并在 pod 规格中指定优先级类名称。优先准入控制器使用优先级类名称字段来填充优先级的整数值。如果没有找到给定名称的优先级类,pod 将被拒绝。
1.7.2. 了解 pod 抢占
当开发人员创建 pod 时,pod 会排入某一队列。如果开发人员为 pod 配置了 pod 优先级或抢占,调度程序会从队列中选取 pod,并尝试将 pod 调度到某个节点上。如果调度程序无法在满足 pod 的所有指定要求的适当节点上找到空间,则会为待处理 pod 触发抢占逻辑。
当调度程序在节点上抢占一个或多个节点时,较高优先级 pod 规格的 nominatedNodeName
字段将设为该节点的名称,nodename
字段同样如此。调度程序使用 nominatedNodeName
字段来跟踪为 pod 保留的资源,同时也向用户提供与集群中抢占相关的信息。
在调度程序抢占了某一较低优先级 pod 后,调度程序会尊重该 pod 的安全终止期限。如果在调度程序等待较低优先级 pod 终止过程中另一节点变为可用,调度程序会将较高优先级 pod 调度到该节点上。因此,pod 规格的 nominatedNodeName
字段和 nodeName
字段可能会不同。
另外,如果调度程序在某一节点上抢占 pod 并正在等待终止,这时又有优先级比待处理 pod 高的 pod 需要调度,那么调度程序可以改为调度这个优先级更高的 pod。在这种情况下,调度程序会清除待处理 pod 的 nominatedNodeName
,使该 pod 有资格调度到其他节点上。
抢占不一定从节点中移除所有较低优先级 pod。调度程序可以通过移除一部分较低优先级 pod 调度待处理 pod。
只有待处理 pod 能够调度到节点时,调度程序才会对这个节点考虑 pod 抢占。
1.7.2.1. Pod 抢占和其他调度程序设置
如果启用 pod 优先级与抢占功能,请考虑其他的调度程序设置:
- pod 优先级和 pod 中断预算
- pod 中断预算指定某一时间必须保持在线的副本的最小数量或百分比。如果您指定了 pod 中断预算,OpenShift Container Platform 会在抢占 pod 时尽力尊重这些预算。调度程序会尝试在不违反 pod 中断预算的前提下抢占 pod。如果找不到这样的 pod,则可能会无视 pod 中断预算要求而抢占较低优先级 pod。
- pod 优先级和 pod 关联性
- pod 关联性要求将新 pod 调度到与具有同样标签的其他 pod 相同的节点上。
如果待处理 pod 与节点上的一个或多个低优先级 pod 具有 pod 间关联性,调度程序就不能在不违反关联要求的前提下抢占较低优先级 pod。这时,调度程序会寻找其他节点来调度待处理 pod。但是,不能保证调度程序能够找到合适的节点,因此可能无法调度待处理 pod。
要防止这种情况,请仔细配置优先级相同的 pod 的 pod 关联性。
1.7.2.2. 安全终止被抢占的 pod
在抢占 pod 时,调度程序会等待 pod 安全终止期限到期,使 pod 能够完成工作并退出。如果 pod 在到期后没有退出,调度程序会终止该 pod。此安全终止期限会在调度程序抢占该 pod 的时间和待处理 pod 调度到节点的时间之间造成一个时间差。
要尽量缩短这个时间差,可以为较低优先级 pod 配置较短的安全终止期限。
1.7.3. 配置优先级和抢占
通过创建优先级类对象并使用 pod 规格中的 priorityClassName
将 pod 与优先级关联,可以应用 pod 优先级与抢占。
优先级类对象示例
apiVersion: scheduling.k8s.io/v1beta1 kind: PriorityClass metadata: name: high-priority 1 value: 1000000 2 globalDefault: false 3 description: "This priority class should be used for XYZ service pods only." 4
流程
配置集群以使用优先级与抢占功能:
创建一个或多个优先级类:
- 指定优先级的名称和值。
-
(可选)指定优先级类的
globalDefault
字段和描述。
创建 pod 规格或编辑现有的 pod 使其包含优先级类的名称,如下所示:
带有优先级类名称的 pod 规格示例
apiVersion: v1 kind: Pod metadata: name: nginx labels: env: test spec: containers: - name: nginx image: nginx imagePullPolicy: IfNotPresent priorityClassName: high-priority 1
- 1
- 指定要用于此 pod 的优先级类。
创建 pod:
$ oc create -f <file-name>.yaml
您可以将优先级名称直接添加到 pod 配置或 pod 模板中。
1.7.4. 禁用优先级与抢占
您可以禁用 pod 优先级与抢占功能。
禁用该功能后,现有 pod 会保留其优先级字段,但会禁用抢占功能,而且也会忽略优先级字段。如果禁用该功能,您便无法在新 pod 中设置优先级类名称。
在集群面临资源压力时,关键 pod 依赖于调度程序抢占功能来进行调度。因此,红帽建议您不要禁用抢占。DaemonSet pod 由 DaemonSet 控制器调度,不受禁用抢占的影响。
流程
为集群禁用抢占:
编辑调度程序 Operator 自定义资源以添加
disablePreemption: true
参数:oc edit scheduler cluster
apiVersion: config.openshift.io/v1 kind: Scheduler metadata: creationTimestamp: '2019-03-12T01:45:02Z' generation: 1 name: example resourceVersion: '1882034' selfLink: /apis/config.openshift.io/v1/schedulers/example uid: 743701e9-4468-11e9-bd34-02a7fe1bf828 spec: disablePreemption: true