What is Node Affinity in Kubernetes?
Node affinity in Kubernetes is a set of rules used to constrain which nodes a pod can be scheduled on, based on labels assigned to nodes. It allows for more expressive, complex scheduling logic than nodeSelector, supporting both soft rules and hard rules to place pods on specific, labeled hardware, such as SSDs or GPUs.
This feature is especially useful in multi-tenant, hybrid, or heterogeneous Kubernetes clusters, where workloads may have varying hardware or locality requirements. Node affinity allows you to optimize resource utilization, isolate sensitive workloads, and improve application performance by matching workloads to nodes with the most suitable characteristics.
Key types of node affinity:
- Hard rules (requiredDuringSchedulingIgnoredDuringExecution): The scheduler must find a matching node to place the pod; otherwise, it stays in a pending state.
- Soft rules (preferredDuringSchedulingIgnoredDuringExecution): The scheduler attempts to find a matching node, but if none are available, it will still schedule the pod elsewhere.
Example usage (YAML):
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
This is part of a series of articles about Kubernetes scheduling
In this article:
- How Node Affinity Works in Kubernetes
- Node Affinity YAML Syntax: Hard vs. Soft Rules
- Common Use Cases for Node Affinity
- Node Affinity vs. Node Selector vs. Pod Affinity
- Pro Tips for Effectively Using Node Affinity
How Node Affinity Works in Kubernetes
Here are the key technical elements behind node affinity.
Node Labels
Node labels are key-value pairs attached to Kubernetes nodes to describe their attributes. Labels are arbitrary and can represent characteristics such as instance type, region, availability zone, or custom metadata relevant to workload scheduling. For example, you might label nodes with disktype=ssd or gpu=true to identify nodes with SSD storage or GPU acceleration.
Labels are set by cluster administrators or automation scripts, either when nodes are added to the cluster or dynamically as infrastructure changes. Consistent and meaningful labeling is essential for effective node affinity, as affinity rules rely on these labels to select appropriate nodes for pod placement. Proper labeling ensures that the scheduler can correctly interpret and enforce your placement policies.
Node Affinity Operators
Node affinity rules use operators to define how pods should match node labels. The most common operators are In, NotIn, Exists, and DoesNotExist. The In and NotIn operators allow you to specify acceptable or unacceptable values for a given label, while Exists and DoesNotExist check for the presence or absence of a label key, regardless of its value.
These operators provide flexibility in expressing complex scheduling requirements. For example, you can require pods to run only on nodes where environment=production or avoid nodes with dedicated=backup. By combining different operators and label selectors, you can fine-tune pod placement to meet workload requirements and organizational policies.
Scheduler Behavior
The Kubernetes scheduler evaluates node affinity rules when deciding where to place a pod. It checks the labels of available nodes against the affinity criteria defined in the pod specification. If a node satisfies the required affinity rules, it becomes eligible for scheduling the pod; otherwise, the pod remains unscheduled until a suitable node is available.
There are two types of node affinity: required (hard) and preferred (soft). Required rules must be satisfied for the pod to be scheduled, while preferred rules influence the scheduler’s choice but do not prevent scheduling if no preferred nodes are available. This distinction allows for both strict and flexible placement strategies, balancing operational needs with resource availability.
Node Affinity YAML Syntax: Hard vs. Soft Rules
1. RequiredDuringSchedulingIgnoredDuringExecution
requiredDuringSchedulingIgnoredDuringExecution defines hard node affinity rules that must be met before a pod can be scheduled onto a node. The scheduler only considers nodes whose labels match all specified conditions. If no matching node is available, the pod remains in a Pending state until a suitable node appears.
This type of affinity is commonly used for workloads with strict infrastructure requirements. For example, a machine learning application may require nodes with GPUs, or a compliance-sensitive workload may need to run only in a specific region or availability zone.
The IgnoredDuringExecution part means Kubernetes does not evict the pod if node labels change after scheduling. If a node label is removed or modified later, the running pod continues operating on that node unless another mechanism triggers rescheduling.
Code example:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
In this example, the pod can only run on nodes labeled with disktype=ssd.
2. PreferredDuringSchedulingIgnoredDuringExecution
preferredDuringSchedulingIgnoredDuringExecution defines soft affinity rules that influence scheduling decisions without making them mandatory. The scheduler tries to place pods on nodes matching the preferred conditions, but it can still schedule the pod on other nodes if necessary.
Preferred affinity rules use a weighting system. Each preference is assigned a weight value between 1 and 100. Nodes matching higher-weighted preferences receive higher scores during scheduling, increasing their likelihood of being selected.
This approach is useful when placement preferences improve performance or cost efficiency but are not strictly required. For example, you may prefer workloads to run on SSD-backed nodes or within a certain zone to reduce latency, while still allowing scheduling elsewhere during resource shortages.
Code example:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 50
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
In this example, Kubernetes prefers nodes labeled with disktype=ssd, but the pod can still run on other nodes if no SSD-backed nodes are available.
Common Use Cases for Node Affinity
Run GPU Workloads on GPU Nodes
Node affinity is used when running GPU workloads in a Kubernetes cluster. By labeling GPU-enabled nodes with a key such as gpu=true, you can ensure that pods requiring GPU resources are scheduled only on compatible hardware. This prevents resource contention for GPU-dependent workloads.
Soft affinity can be used if fallback to CPU nodes is acceptable in noncritical scenarios.
Schedule Databases on SSD Nodes
Databases often require high I/O performance, which SSD-backed nodes can provide. By labeling nodes with disktype=ssd and setting required node affinity on database pods, you ensure high storage performance and lower latency for stateful workloads.
As new SSD nodes are added and labeled, database pods become eligible for scheduling on them.
Keep Workloads in a Specific Availability Zone
Running workloads in a specific availability zone can reduce latency, improve fault tolerance, or meet regulatory requirements. By labeling nodes with a zone identifier such as zone=us-west1-b and specifying node affinity in pod specs, you can control pod distribution across zones.
Using preferred affinity, you can guide the scheduler to place pods in the desired zone but allow fallback to other zones if resources are constrained.
Separate Production and Development Workloads
Separating production and development environments in a shared cluster is a common use case for node affinity. By labeling nodes as env=prod or env=dev, you can enforce placement policies that prevent development workloads from running on production nodes, and vice versa.
With required node affinity, you enforce strict separation, while preferred affinity allows flexibility in resource-constrained situations.
Node Affinity vs. Node Selector vs. Pod Affinity
Node affinity, node selectors, and pod affinity are all Kubernetes scheduling mechanisms, but they solve different placement problems and offer different levels of flexibility.
A node selector is the simplest option. It allows a pod to run only on nodes with specific labels. The configuration is straightforward, using exact key-value matches such as disktype=ssd. However, nodeSelector supports only simple equality checks and cannot express more advanced conditions like multiple values or exclusion rules.
Node affinity extends the capabilities of nodeSelector by supporting advanced matching operators such as In, NotIn, Exists, and DoesNotExist. It also supports both required and preferred scheduling rules, giving administrators more control over pod placement. Node affinity is typically used when workloads must target nodes with specific hardware, regions, or operational roles.
Pod affinity works differently because it focuses on relationships between pods rather than node labels. It allows pods to be scheduled close to other pods with specific labels, usually within the same node or availability zone. This is useful for reducing network latency between tightly coupled services. Kubernetes also supports pod anti-affinity, which spreads pods apart to improve availability and fault tolerance.
The following table summarizes the main differences:

Pro Tips for Effectively Using Node Affinity
1. Standardize Node Labels Before Writing Affinity Rules
Node affinity depends on node labels, so inconsistent labeling can lead to scheduling failures or unpredictable pod placement. Define a clear labeling strategy before creating affinity policies. Use consistent naming conventions for labels such as environment, hardware type, region, workload role, or storage class.
For example, standardize on labels such as env=prod, disktype=ssd, or workload=batch. Avoid creating multiple labels that represent the same concept, such as gpu=true and accelerator=gpu.
Automate label management where possible. Cloud providers and cluster provisioning tools often support automatic labeling for instance types, zones, and node pools. Automation reduces manual configuration errors and ensures that new nodes are compatible with existing affinity policies.
2. Prefer Soft Rules Unless Placement Is Mandatory
Hard affinity rules can make workloads unschedulable if matching nodes are unavailable. Overusing requiredDuringSchedulingIgnoredDuringExecution may reduce cluster flexibility during scaling events, maintenance windows, or node failures.
Preferred affinity rules provide more resilient scheduling behavior. They allow Kubernetes to prioritize ideal nodes while still placing workloads elsewhere when necessary.
Use hard affinity only when placement is mandatory, such as for GPU-dependent applications, workloads with licensing restrictions, compliance-sensitive systems, or applications that require specific hardware features.
3. Align Node Affinity with Node Autoscaling
Node affinity should align with cluster autoscaling policies. If workloads require nodes with specific labels, the autoscaler must be able to provision matching node groups. Otherwise, pods may remain stuck in a Pending state even when autoscaling is enabled.
For example, GPU workloads should target node pools dedicated to GPU instances, while storage-intensive workloads should align with SSD-backed node groups.
Verify that autoscaler limits support expected workload growth. If the autoscaler cannot create additional matching nodes because of quota limits or configuration constraints, affinity rules may block deployments.
4. Use Affinity with Workload Rightsizing
Node affinity is most effective when workloads are properly sized. Overprovisioned CPU or memory requests can limit scheduling options, even if suitable nodes match the affinity rules.
For example, a pod with strict affinity requirements and excessive memory requests may remain unscheduled even though matching nodes exist.
Review workload resource requests and limits alongside affinity policies. Monitoring tools and Kubernetes metrics can help identify workloads that consistently consume fewer resources than requested.
5. Review Affinity Policies as Workloads Evolve
Infrastructure and application requirements change over time, so node affinity policies should be reviewed regularly. Labels that were once meaningful may become outdated after cluster upgrades, migrations, or architectural changes.
Periodic reviews help identify unnecessary constraints, unused labels, or scheduling policies that reduce cluster efficiency.
Operational reviews should include both platform and application teams to ensure that affinity rules still match workload requirements without adding unnecessary scheduling complexity.
Optimize Node Placement and Resource Efficiency with PerfectScale
Node affinity gives you control over where workloads run, but even well-placed pods can waste capacity or trigger unnecessary node scaling if their resource requests and limits are off. Over-provisioned containers force the autoscaler to spin up more nodes than needed, under-provisioned containers cause OOM kills and evictions on the very nodes affinity rules carefully selected, and inefficient bin-packing leaves labeled nodes underutilized. PerfectScale enhances Kubernetes efficiency by autonomously right-sizing workloads and providing deep node-level visibility, so your affinity policies land pods on nodes that are already configured for peak efficiency.
Key capabilities of PerfectScale:
- Autonomous workload right-sizing: Continuously analyzes workloads and right-sizes CPU and memory requests and limits based on actual usage, ensuring pods scheduled through affinity rules use resources efficiently.
- Node-level visibility and optimization: Provides holistic visibility across your nodes and node pools, validates node affinities and taints against actual workload scheduling patterns, and helps you select optimal node types for each workload.
- Proactive configuration fixes: Identifies configuration errors — such as CPU Request Not Set, Memory Request Not Set, and Memory Limit Not Set — that cause evictions, node over-commitment, and inefficient scheduling on your carefully labeled nodes.
- Autoscaling efficiency: Fine-tunes workload configurations so autoscalers like Karpenter and Cluster Autoscaler provision the right node types and sizes, keeping affinity-driven placement predictable and cost-efficient.
Ready to make sure your affinity-driven scheduling lands on efficient, right-sized nodes?
.jpg)





