Kubernetes Placement Boundary
Kubernetes Placement Boundary defines where workloads are scheduled across nodes, ensuring optimal resource use and compliance with architectural constraints.
Kubernetes Placement Boundary is the line separating what Kubernetes' placement mechanisms — node affinity, pod affinity/anti-affinity, topology spread constraints, taints and tolerations — can actually guarantee from what they merely influence once, at a single moment in time, without ongoing enforcement. The recurring, easily misunderstood theme across nearly every placement mechanism is captured in the qualifier IgnoredDuringExecution attached to affinity rules: these constraints are evaluated exclusively at scheduling time, and Kubernetes makes no continuous promise that a Pod's placement remains compliant with its original constraints for the rest of that Pod's lifetime.
Understanding this temporal boundary — placement as a one-time decision rather than a continuously enforced invariant — resolves much of the confusion that arises when node labels, taints, or the surrounding Pod population change after a Pod has already been placed.
The Scheduling-Time vs. Runtime Boundary
What Placement Constraints Actually Promise
Every node affinity, pod affinity, and pod anti-affinity rule is evaluated once, at the moment a Pod is being scheduled. Once binding succeeds, Kubernetes does not re-evaluate that Pod's continued compliance with its own placement rules — a node's labels can change, a co-located Pod that satisfied an affinity rule can be deleted, or a formerly satisfied anti-affinity relationship can be violated by a later, independently scheduled Pod, and none of this triggers any automatic corrective action on the already-placed Pod.
Where Continuous Enforcement Does Exist
The one placement mechanism with a genuinely continuous enforcement dimension is NoExecute taints, which actively evict already-running Pods that do not tolerate them — this stands in contrast to every affinity-based mechanism, which is purely a one-time scheduling-time filter or preference with no analogous runtime eviction behavior of its own.
Consequences of the Boundary
Stale Affinity After Label Changes
A Pod scheduled onto a node because it matched a required node affinity rule at the time remains running there even if that node's labels are later changed to no longer match — the Pod is not evicted, and its continued placement, while now technically inconsistent with its own declared affinity rule, is simply outside what Kubernetes tracks or acts on after the fact.
Anti-Affinity Drift Over Time
Two Pods placed on different nodes to satisfy a required anti-affinity rule can end up violating that same rule later if one Pod is deleted and its controller creates a replacement that, due to changed cluster conditions, happens to land on the same node as the other — anti-affinity is enforced at each individual scheduling decision, not as an ongoing cluster-wide invariant continuously reconciled against.
Topology Spread Skew Can Re-Emerge
Similarly, a topology spread constraint satisfied at the moment every replica was originally placed can drift out of balance over time as individual Pods are replaced (due to node failures, rolling updates) and rescheduled under different cluster conditions — Kubernetes does not proactively rebalance already-running Pods to restore ideal skew; it only applies the constraint to each new scheduling decision as it happens.
What Restores Compliance
Only New Scheduling Events Re-Evaluate Constraints
Placement constraints are only re-applied when a Pod is newly created — meaning drift is only corrected, incidentally, the next time a Pod happens to be deleted and recreated (through a rolling update, a node failure, manual intervention), not through any dedicated background reconciliation process specifically targeting constraint compliance.
Tools That Actively Rebalance
For workloads that need genuinely continuous rebalancing rather than a one-time scheduling decision, dedicated descheduling tools (such as the Kubernetes Descheduler project) exist specifically to identify Pods that no longer satisfy their original placement intent and evict them, triggering their controller to recreate them — allowing the ordinary scheduling-time constraints to re-apply and restore intended placement, since Kubernetes' built-in scheduler and controllers do not perform this rebalancing on their own.
kubectl get pods -o json | jq -r '.items[] | select(.spec.affinity != null) | .metadata.name'
A periodic audit identifying Pods with affinity or topology constraints, cross-referenced against current node labels and sibling Pod placement, is a manual approximation of what a descheduler automates.
Designing Around the Boundary
Accepting the Boundary for Most Workloads
For the majority of workloads, occasional drift between original placement intent and current reality is an acceptable tradeoff against the operational cost of continuous, active rebalancing — most placement constraints exist to bias the initial and replacement scheduling decisions favorably, not to guarantee an invariant that holds at every instant.
When to Introduce Active Rebalancing
Workloads with strict, continuously required placement guarantees (regulatory data residency requirements, hard fault-domain isolation for compliance reasons) are the primary candidates for pairing scheduling-time constraints with an active descheduling tool, specifically because the scheduling-time boundary alone is insufficient to guarantee their requirement holds indefinitely.
Example
apiVersion: apps/v1
kind: Deployment
metadata:
name: codartium-boundary-example
spec:
replicas: 3
selector:
matchLabels:
app: codartium-api
template:
metadata:
labels:
app: codartium-api
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: codartium-api
topologyKey: "kubernetes.io/hostname"
containers:
- name: api
image: codartium/api:latest