E-NO
Kubernetes Pod Priority and Preemption capacity planning 7 Min Read

Kubernetes Pod Priority and Preemption: Capacity Planning with Practical Examples

calendar_today Published: 2026-08-21
update Last Updated: 2026-08-21
analytics SEO Efficiency: 100%
Technical guide illustration for Kubernetes Pod Priority and Preemption: Capacity Planning with Practical Examples.

Intro

Kubernetes Pod Priority and Preemption is a scheduler feature that helps cluster operators protect critical workloads during resource shortages. When a cluster runs out of capacity, the scheduler can evict lower-priority Pods to make room for higher-priority ones. This mechanism is powerful, but it can cause unexpected disruptions if it is not planned carefully.

This article is written for developers, DevOps consultants, and technical startup teams who need to plan cluster capacity with priority and preemption in mind. It connects the core concepts of priority classes, preemption policies, resource requests, and node capacity to practical commands, expected outputs, failure signals, and recovery decisions. You will learn how to observe the current state before making changes, limit the blast radius of any intervention, verify the result, and document recovery paths.

The goal is operational safety. You should never apply a priority change without understanding which Pods might be evicted as a result. Use read-only inspection first, protect sensitive values with placeholders, change one scoped item at a time, and always verify that the expected state has been reached. This article provides a structured workflow that you can adapt to your own clusters.

Version and Environment Inventory

Before using priority and preemption, confirm which Kubernetes version you are running and whether the feature is enabled. Pod Priority and Preemption is stable and enabled by default in Kubernetes v1.14 and later. For older versions, you may need to enable the feature gate PodPriority on the API server and scheduler.

Check your cluster version with:

kubectl version --short

Expected output includes both client and server versions. If the server version is below v1.14, plan an upgrade or verify that the feature gate is explicitly enabled.

Next, check the current PriorityClasses in the cluster:

kubectl get priorityclass

A typical output looks like:

NAME                      VALUE        GLOBAL-DEFAULT   AGE
system-cluster-critical   2000000000   false            30d
system-node-critical      2000001000   false            30d

If no custom PriorityClasses exist, you will see only the two built-in system classes. These system classes are used by critical cluster components and should not be assigned to user workloads.

For capacity planning, you also need to know the total allocatable resources on your nodes:

kubectl describe nodes | grep -A 5 "Allocatable"

This shows CPU and memory available for Pods on each node. Compare these numbers with the total resource requests of running Pods:

kubectl get pods -A -o=jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.spec.containers[*].resources.requests}{"\n"}{end}'

This command prints the resource requests for every container. Sum them per namespace or per node to understand current utilization. For example, if three Pods on a node each request 500m CPU and the node allocatable CPU is 2000m, the node still has 500m available for new Pods.

When planning priority changes, identify which Deployments or StatefulSets might be affected. Inspect a specific workload with:

kubectl get deployment <name> -o yaml

Look for priorityClassName in the Pod template. If it is not set, the Pod gets the globalDefault PriorityClass if one exists, otherwise priority 0.

Keep your local test environment small. Before changing priorities on a production cluster, reproduce the scenario on a local cluster using kind or minikube. Apply one manifest at a time, inspect the generated resources, and verify that scheduling behaves as expected. Use kubectl port-forward to test services locally before moving to a cloud load balancer or ingress controller.

Quick check 1 of 2

What field in a Pod's specification determines its priority and can cause unnecessary preemption if set too high?

Priority is specified by setting the priorityClassName field in the Pod's specification. If set too high, it can cause unintended preemption.

Safe Configuration Path

A safe configuration path for priority and preemption starts with defining clear PriorityClasses that reflect your business tiers. Typical tiers are:

  • Critical infrastructure (value >= 1000000000): monitoring agents, logging forwarders, service mesh proxies that must run on every node.
  • Production applications (value around 100000 or 10000): user-facing services that must remain available but can tolerate brief eviction in favor of infrastructure.
  • Batch or development workloads (value 100 or less): optional jobs, test deployments, and background processing that can be evicted without impact.

The value is a 32-bit integer. Higher values mean higher priority. Only use values above 1 billion for system-critical components; user workloads should stay below that threshold.

Create a PriorityClass for production applications:

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: production-priority
value: 10000
globalDefault: false
description: "Priority for production applications"

Apply it:

kubectl apply -f production-priority.yaml

Verify it exists:

kubectl get priorityclass production-priority

Now assign this PriorityClass to a Deployment. Add priorityClassName: production-priority to the Pod template:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-frontend
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web-frontend
  template:
    metadata:
      labels:
        app: web-frontend
    spec:
      priorityClassName: production-priority
      containers:
      - name: nginx
        image: nginx:1.25
        resources:
          requests:
            cpu: "200m"
            memory: "256Mi"

Apply the Deployment and check that Pods are created with the priority set:

kubectl apply -f web-frontend.yaml
kubectl get pods -l app=web-frontend -o wide
kubectl describe pod <pod-name> | grep -i priority

The describe output should include a line like:

Priority: 10000

To test preemption without harming real workloads, create a low-priority filler Pod that consumes a large amount of resources, then attempt to schedule a high-priority Pod that requires those resources. For example, create a filler Pod that requests 1 CPU on a node with 2 allocatable CPUs. Then create a high-priority Pod requesting 1.5 CPUs. The scheduler should evict the filler Pod to place the high-priority one.

Here is a filler Pod with priority 0 (no explicit class):

apiVersion: v1
kind: Pod
metadata:
  name: filler
spec:
  containers:
  - name: stress
    image: polinux/stress
    resources:
      requests:
        cpu: "1000m"
        memory: "500Mi"
  nodeSelector:
    kubernetes.io/hostname: <your-node-name>

And a high-priority Pod:

apiVersion: v1
kind: Pod
metadata:
  name: important-job
spec:
  priorityClassName: production-priority
  containers:
  - name: app
    image: nginx
    resources:
      requests:
        cpu: "1500m"
        memory: "500Mi"
  nodeSelector:
    kubernetes.io/hostname: <your-node-name>

After applying the high-priority Pod, watch events:

kubectl get events --watch

You should see events indicating that the filler Pod was preempted:

Preempted: pod/filler

Now verify the high-priority Pod is scheduled and running, while the filler is terminated:

kubectl get pods

Always test in a dedicated namespace or cluster to avoid accidental eviction of important workloads.

Verification and Diagnostics

After applying priority configurations, you must verify that the scheduler is behaving as intended and diagnose any issues. Use the following commands to inspect state and events.

First, check the status of all Pods:

kubectl get pods -o wide

Look for Pods stuck in Pending state. A Pending Pod may indicate insufficient resources or preemption not occurring as expected.

Inspect a specific pending Pod:

kubectl describe pod <pod-name>

The events section will show why the Pod cannot be scheduled. Common messages include:

  • 0/3 nodes are available: 3 Insufficient cpu.
  • Preemption is not helpful for scheduling.

The second message appears when the scheduler cannot evict lower-priority Pods to make room, possibly because the pending Pod has a lower or equal priority than existing Pods, or because Pod Disruption Budgets prevent eviction.

Check the scheduler logs for preemption decisions. If you have access to the control plane:

kubectl logs -n kube-system <scheduler-pod-name> | grep -i preempt

Scheduler logs include entries like:

"Preempting" pod="namespace/name"
"Preemption succeeded"
"Preemption failed"

If preemption fails, check whether the Pod has a priorityClassName set and whether the PriorityClass value is higher than the victims. Also check if any Pod Disruption Budget (PDB) blocks the eviction:

kubectl get pdb -A

Verify resource requests and limits are correctly configured. Use:

kubectl get pod <pod-name> -o yaml | grep -A 5 resources

If requests are not set, the Pod is treated as requesting zero resources, which can lead to overcommitment and eviction. Always set requests for critical workloads.

For capacity planning, compare actual usage with requests using metrics-server (if installed):

kubectl top pods -A

This shows CPU and memory usage per Pod. If many Pods use far less than their requests, you may be over-requesting and causing unnecessary preemption. Adjust requests to realistic values.

Quick check 2 of 2

What happens when a Pod's priorityClassName is left empty?

An empty priorityClassName is resolved to zero by default.

Failure Modes and Recovery

Priority and preemption can fail in several ways. Understanding these failure modes and having a recovery plan is essential.

Failure Mode 1: High-priority Pod remains Pending

If a high-priority Pod is stuck in Pending, check the scheduler events:

kubectl describe pod <pod-name> | tail -20

Possible causes:

  • No lower-priority Pods on the nodes that satisfy the scheduling constraints.
  • Preemption is disabled by feature gate.
  • Pod Disruption Budget prevents eviction.
  • Node selectors or affinity rules restrict the Pod to nodes without enough resources.

Recovery: adjust the Pod's scheduling constraints, increase cluster capacity, or temporarily relax PDBs after assessing risk.

Failure Mode 2: Critical workload evicted unexpectedly

If a production Pod is evicted, you will see it in a Terminating state or a new Pod replacing it. Check the event history:

kubectl get events --sort-by=.lastTimestamp | grep -i preempt

To recover, ensure that the critical workload has a high enough PriorityClass. Create a new PriorityClass with a higher value and assign it. For example:

kubectl create priorityclass critical-app --value=100000 --global-default=false
kubectl patch deployment <deployment-name> -p '{"spec":{"template":{"spec":{"priorityClassName":"critical-app"}}}}'

Then verify the new Pods are running with the correct priority:

kubectl get pods -l app=<app-label> -o wide
kubectl describe pod <pod-name> | grep -i priority

Failure Mode 3: Preemption loops

Sometimes, two Deployments with equal priority may repeatedly preempt each other if they both request resources that the other holds. This can cause instability. To detect this, look at scheduler logs for repeated preemption events for the same Pods.

Prevent this by assigning different priorities to competing workloads or by using node affinity to separate them. Use a tool like:

kubectl logs -n kube-system <scheduler-pod-name> --since=1h | grep "Preemption"

Failure Mode 4: Preemption does not happen because PriorityClass is missing

If a Pod template references a non-existent PriorityClass, the Pod will not be created, and the Deployment will show an error:

kubectl describe deployment <deployment-name>

You will see events like:

Error creating: pods "<name>" is forbidden: no PriorityClass with name production-priority was found

Recovery: create the missing PriorityClass or fix the typo in the Deployment.

Always document the recovery steps for each failure mode before deploying priority changes to production. Use rollback mechanisms like kubectl rollout undo deployment/<name> if necessary.

Operations Checklist

Use this checklist before and after implementing priority and preemption changes.

Before change:

  • [ ] Record current cluster state: kubectl get nodes -o wide, kubectl get pods -A -o wide
  • [ ] Note existing PriorityClasses: kubectl get priorityclass
  • [ ] Identify all Deployments and Pods that might be affected.
  • [ ] Check resource requests and limits: kubectl get pods -A -o=jsonpath='{...}'
  • [ ] Review Pod Disruption Budgets: kubectl get pdb -A
  • [ ] Ensure you have a rollback plan (e.g., save current YAMLs).
  • [ ] Test the change in a non-production environment.

Apply change:

  • [ ] Apply new PriorityClass: kubectl apply -f priorityclass.yaml
  • [ ] Patch or apply Deployment with priorityClassName.
  • [ ] Use kubectl rollout status deployment/<name> to confirm rollout.

After change:

  • [ ] Verify Pods are running: kubectl get pods -o wide
  • [ ] Check priority of new Pods: kubectl describe pod <pod-name> | grep Priority
  • [ ] Watch events for unexpected preemption: kubectl get events --sort-by=.lastTimestamp
  • [ ] If using metrics-server, compare resource usage: kubectl top pods -A
  • [ ] Update documentation with observed behavior.

Recovery verification:

  • [ ] Simulate a failure by creating a low-priority Pod and a high-priority Pod in a test namespace. Confirm preemption works.
  • [ ] If preemption does not work as expected, check scheduler logs and PDBs.
  • [ ] Verify that rollback restores previous state: apply the saved YAMLs or kubectl rollout undo.

Store all commands in a runbook that your team can access. Use placeholders for sensitive values and keep secrets in Kubernetes Secrets or external secret managers.

Conclusion

Kubernetes Pod Priority and Preemption is a key tool for capacity planning, but it must be used with care. By defining clear PriorityClasses, setting proper resource requests, and testing preemption behavior in a controlled environment, you can ensure that critical workloads survive resource shortages while lower-priority workloads are evicted gracefully.

This article provided a practical workflow: start with version and environment inventory, move to safe configuration, verify behavior with diagnostics, understand failure modes, and follow an operations checklist. Each step includes concrete commands and expected outputs so you can replicate the examples in your own cluster.

As a next step, choose one low-risk verification from the article. For example, create two test Pods with different priorities in a dedicated namespace and observe the preemption events. Record the current state, run the documented commands, and compare the results. Then review your production Deployments for missing priorityClassName and resource requests.

A reliable operational workflow makes failure visible, protects sensitive values, limits changes to intended resources, and defines recovery verification before an incident occurs. With the principles and examples in this article, you can confidently plan capacity using Kubernetes Pod Priority and Preemption.

Related Research

Article Quality Score

Reader usefulness 100%
  • check_circle Reader-ready guide
  • check_circle Practical examples included
  • check_circle Clean SEO article URL