在 Kubernetes 集群运行过程中,节点可用资源并不是无限供应的。当多个工作负载同时申请 CPU 与内存,调度器必须决定先安排谁、驱逐谁。PriorityClass 作为集群级别的优先级定义对象,给 Pod 赋予一个整数值,数值越大代表优先级越高。高优先级 Pod 在资源不足时可以通过抢占机制驱逐低优先级 Pod 从而获得运行机会,而节点资源回收时也是低优先级先行退出。理解这套机制,是配置出稳定集群的第一步。

PriorityClass 的基础结构与创建方式
PriorityClass 是一个集群作用域的资源,不需要绑定命名空间。它的核心字段包括 value、globalDefault 与 preemptionPolicy。其中 value 是一个三十二位整数,系统预留了最高优先级 1000000000 给关键系统组件,用户自定义通常落在几到几十万之间。globalDefault 设为 true 时,任何没有显式声明 priorityClassName 的 Pod 都会采用该类的数值,这在统一兜底策略时非常有用,但要小心覆盖导致预期外的抢占。
下面是一个典型的高、中、低三层优先级类定义。我们将核心交易服务设为九十万,普通 API 服务设为五十万,离线批处理设为十万,并且把中等级别设为全局默认,避免遗留 Pod 落入零值被随意驱逐。
apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: critical-priority value: 900000 preemptionPolicy: PreemptLowerPriority globalDefault: false description: "核心链路业务使用" --- apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: normal-priority value: 500000 preemptionPolicy: PreemptLowerPriority globalDefault: true description: "普通在线服务默认" --- apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: batch-priority value: 100000 preemptionPolicy: Never globalDefault: false description: "离线任务不抢占"
需要注意 preemptionPolicy 字段。默认值是 PreemptLowerPriority,表示允许抢占。若设为 Never,则该优先级类只影响调度排序,不会主动驱逐他人,适合对时延不敏感但又不希望被误杀的批处理作业。很多团队忽略这个字段,结果批处理任务在高峰时段反过来挤掉在线服务,根源就在于这里配置成了允许抢占。
在 Pod 与控制器中引用优先级类
定义好 PriorityClass 之后,必须在工作负载中通过 priorityClassName 引用才会生效。对于 Deployment、StatefulSet 等控制器,应该写在 template 的 spec 里,而不是外层,否则不会传递给真正的 Pod。如果只改了 Deployment 元数据而没进 pod template,调度器依然按照全局默认或零值处理。
以下示例展示了一个核心服务的 Deployment 片段,它明确使用了前面定义的 critical-priority。这样当节点内存水位超过阈值,调度器会优先保留该 Pod,把同节点上的 batch-priority 任务驱逐掉以腾出空间。
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
spec:
replicas: 3
template:
metadata:
labels:
app: order
spec:
priorityClassName: critical-priority
containers:
- name: main
image: ipipp.com/order:1.2
resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "1"
memory: "1Gi"
对于已经运行且没设优先级的存量 Pod,直接修改 Deployment 并滚动更新即可,新建 Pod 会带上新类名。但如果某些第三方 Operator 生成的 Pod 不支持注入字段,就需要通过修改其上层 CRD 或 webhook 来补。另外,当 globalDefault 从 false 改为 true,存量未声明类名的 Pod 不会立刻变更优先级,只有重建后才生效,这一点在排障时经常被遗漏。
避免优先级反转与资源碎片的实践策略
优先级配置最典型的陷阱是优先级反转:低优先级 Pod 占着资源不释放,高优先级 Pod 反而 pending。造成这种现象往往不是因为 PriorityClass 数值写错,而是低优先级 Pod 设置了过高的资源 request,或者使用了 Never 抢占策略却长期占用大块内存。解决思路是给批处理任务加上合理的 resources.limits,并配合 Cluster Autoscaler 在抢占无效时扩容节点。
另一个容易被忽视的问题是资源碎片。假设节点剩余两核,但一个需要四核的高优先级 Pod 想调度进来,调度器会尝试驱逐几个一核的低优先级 Pod。如果低优先级 Pod 分布在不同节点且每节点只剩一核,就可能发生跨节点驱逐风暴。此时应在 PriorityClass 设计阶段就把大规格任务和中小规格任务分层,让批处理尽量以小而多的形式存在,降低单次抢占成本。
# 查看当前集群所有优先级类及数值 kubectl get priorityclasses.scheduling.k8s.io -o custom-columns=NAME:.metadata.name,VALUE:.value,GLOBAL:.globalDefault # 找出因为优先级原因处于 Pending 的 Pod kubectl get pods -A --field-selector=status.phase=Pending -o wide
最后建议在测试环境用混沌工具模拟节点压力,观察不同 PriorityClass 下的驱逐顺序是否符合设计。只有把关键链路、普通服务、离线任务三层的数值差距拉开,并且严格控制 globalDefault 的适用范围,集群才能在真实流量高峰中稳住核心业务,而不是盲目抢占导致雪崩。配置完成之后,还应把优先级类清单纳入版本库评审,避免后续有人随意新建更高数值的类破坏原有秩序。
KubernetesPriorityClass优先级调度修改时间:2026-08-16 18:44:28