Skip to content
DevOps AI ToolKit
All guides
AI for Automation By James Joyner IV · · 7 min read

Kubernetes Priority Classes: Why `Never` Pods Wait for SREs

Learn how Kubernetes priority classes affect scheduling, preemption, QoS, and eviction, with kubectl checks, copyable YAML, and pitfalls for SREs.

Kubernetes Priority Classes: Why `Never` Pods Wait for SREs

Kubernetes priority classes map a name to an integer, and the scheduler orders pending pods by that value, the highest first. A higher-value pod can also preempt lower-value pods unless its preemptionPolicy is Never. When scheduling surprises you, run kubectl get priorityclass and check priorityClassName on the pods involved before touching anything else.


TL;DR:

  • PriorityClass changes queue order and preemption rights, but it reserves no capacity; pods must still meet node resource and affinity constraints.
  • With preemptionPolicy set to Never, a pod can jump the queue without evicting others, but an unschedulable pod may back off as lower priority pods schedule.
  • Only one PriorityClass can be globalDefault; it applies to new pods without a named class, while existing pods retain their resolved priority.
  • QoS comes from resource requests and limits, not PriorityClass; the kubelet uses QoS during node pressure, while scheduler preemption ignores it.
  • Repeated preemption signals capacity or resilience problems; check pod events and compare controller priorityClassName values with available classes before adding another tier.

Table of Contents

How PriorityClass works: values, scope, and built-in classes

A PriorityClass is a cluster-scoped API object that maps a name to an integer. Pods reference that name through priorityClassName in their template, and the value gets resolved onto the pod at creation. The official docs describe the effect: a higher value puts the pod earlier in the scheduler queue and can trigger preemption when the cluster runs short on resources.

A few facts decide whether your values behave:

  • Built-in classes: system-node-critical is 2000001000 and system-cluster-critical is 2000000000. Both are reserved for Kubernetes internals.
  • Reserved prefix: names starting with system- are off limits for your own classes.
  • globalDefault: when set to true, new pods that omit priorityClassName get that class. Only one class can be the default, and existing pods keep the priority they already resolved.
  • Pods with no class: if no default exists, they run at priority zero.

Priority never overrides resource fit. Preemption runs in the scheduler’s PostFilter phase, so a high-priority pod still has to satisfy node affinity and capacity constraints. For deeper operational examples, see our PriorityClass and preemption explainer.

Preemption behavior and preemptionPolicy

Preemption is a last resort. The scheduler first tries to place a pod normally, and only when filtering finds no feasible node does it look for a node where evicting lower-priority pods would free enough room. Here is the sequence in practice:

  1. The pending pod fails the filter phase on every node.
  2. The scheduler searches for a node where removing lower-priority pods makes the pod fit.
  3. It picks victims, respecting PodDisruptionBudgets where it can.
  4. The victims terminate gracefully, and the preemptor is retried against the freed node.

preemptionPolicy defaults to PreemptLowerPriority. Setting it to Never gives you a pod that still jumps the queue but never forces anyone out. Per the Kubernetes docs, an unschedulable Never pod sits in the queue and is retried with back-off, which can let lower-priority pods schedule ahead of it.

The cost is pod churn. Maintainers advise using preemption sparingly because repeated eviction of lower-priority pods destabilizes clusters. PDBs can also collide with it, which is the territory of our guide to the disruption budget eviction error.

Pro Tip: Give batch and background jobs a non-preempting class with preemptionPolicy: Never, so they keep their queue position without ever evicting a serving pod.

Batch pod waits while serving pods keep running

How PriorityClass relates to QoS classes and kubelet eviction

These two mechanisms get conflated constantly, and they answer different questions. PriorityClass decides who schedules first and who may displace whom. QoS classes, derived from requests and limits, influence what the kubelet evicts when a node comes under pressure, as the scheduling and eviction docs lay out.

  • QoS classes: Guaranteed, Burstable, and BestEffort come from your requests and limits, not from any priority setting.
  • Scheduler preemption: victim selection follows priority values and PDBs, and QoS plays no part in it.
  • Kubelet eviction: node-pressure eviction is a separate path that runs on the node, with its own ordering.
  • No reservation: a PriorityClass reserves nothing. It changes queue order and eviction rights, never guaranteed capacity.

So a high-priority BestEffort pod is entirely possible, and it will be among the first the kubelet considers under memory pressure.

Create PriorityClass: kubectl commands and YAML you can copy

The kubectl reference covers --value, --global-default, --description, and --preemption-policy. Start with the imperative form:

kubectl create priorityclass high-priority --value=10000 --description="Customer-facing services"
kubectl create priorityclass batch-low --value=1000 --preemption-policy=Never

The declarative equivalent, plus a Deployment that uses it:

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 10000
globalDefault: false
description: "Customer-facing services"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  # Omit replicas to use the default
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
    spec:
      priorityClassName: high-priority
      containers:
        - name: api
          image: example/api:latest
  • Updating a class: pods already running keep their resolved priority. Only new pods pick up changes.
  • Deleting a class: existing pods are unaffected, but new pods naming it will be rejected.
  • Verification: kubectl get pod <name> -o jsonpath='{.spec.priority}' shows the resolved integer.

Pro Tip: Space your values far apart, such as 1000 and 10000, so you can slot in a new tier later without renumbering anything.

Best practices and common pitfalls

Priority is a blunt tool. Reach for capacity planning, node pools, and sane requests and limits first, and use priority to express genuine ordering, not to protect workloads from a cluster that is too small.

  • Skip the system- prefix. It is reserved for Kubernetes components.
  • Remember the scope. PriorityClass is cluster-scoped, so a class created for one team is visible and usable by every namespace.
  • Treat globalDefault as a cluster-wide change. Audit existing workload templates before enabling it.
  • Keep tiers few. A few classes are easier to reason about than many.

Frequent preemption signals a problem: Kubernetes maintainers advise using preemption sparingly, because repeated eviction of lower-priority pods leads to pod churn and cluster instability.

Debugging and troubleshooting preemption and pending pods

When pods vanish or sit pending, work through this order:

  1. Run kubectl describe pod <name> and read the Events section for preemption or scheduling failure messages.
  2. Run kubectl get events --sort-by=.lastTimestamp to see preemption and eviction events across the namespace.
  3. Compare kubectl get priorityclass against priorityClassName on your controllers to find unintended high-priority workloads.
  4. Check PodDisruptionBudgets and node pressure conditions, then scheduler and kubelet logs if the cause is still unclear.
  5. If the same pods keep getting displaced, lower or remove the class causing it.

Our quick check for evicted pods covers the eviction side, and the scheduler deep dive explains the phases behind these messages. If you inspect pods all day, a desktop tool like the Kubezilla pod shell workflow speeds up the loop.

When more priorities are the wrong fix

In my experience, clusters that preempt constantly are short on capacity or resilience, and adding another priority tier only moves the pain around. If preemption, repeated evictions, or recurring incident pages persist after you have tidied your classes, that is the point to get a Kubernetes Health Check instead of tuning further.

— James

A Kubernetes Health Check that fixes priority and preemption problems

We built our Kubernetes Health Check for exactly this situation: a cluster where scheduling and eviction behave in ways nobody can fully explain. It costs $300 as a fixed-price engagement, and you can start on our work with us page.

Devopsaitoolkit

  • What we review: PriorityClass usage, scheduler configuration, PDBs, and the sources of evictions.
  • What you get: details are on our work with us page.

Send us your cluster details and we will tell you where the churn is coming from.

FAQ

What is a PriorityClass in Kubernetes?

A PriorityClass is a cluster-scoped object that maps a name to an integer value. The scheduler uses that value to order pending pods and decide which pods may preempt others.

Does PriorityClass guarantee resources for a pod?

No. It only changes scheduling order and the ability to displace other pods under resource pressure. Capacity guarantees come from requests, limits, and node sizing, as the Kubernetes docs make clear.

How do I stop a pod from preempting others?

Set preemptionPolicy: Never on its PriorityClass. The pod keeps its queue position but will not evict running pods.

Is PriorityClass the same as QoS class?

No. QoS is derived from requests and limits and mainly guides kubelet eviction, while PriorityClass governs scheduling order and preemption.

Newsletter

Free: the DevOps AI Incident-Triage Cheat Sheet

Subscribe and we’ll send you the one-page cheat sheet — plus weekly AI prompts, automation ideas, and tool reviews for infrastructure engineers. One email a week. No spam, unsubscribe anytime.

  • AI Incident-Triage Cheat Sheet (PDF)
  • Access to 2,778 DevOps AI prompts
  • One practical workflow email per week
Free download · 368-page PDF

Get 500 Battle-Tested DevOps AI Prompts — Free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.