Skip to main content

nodeSelectors and nodeAffinity

Updated Apr 07, 2022 ·

nodeSelector

A nodeSelector is used to attract Pods to specific nodes based on labels. Unlike taints, which repel Pods, a nodeSelector filters nodes by their labels, and only the nodes with matching labels will be selected for Pod scheduling.

For example, if a label is set on a node, only Pods with a matching label will be scheduled on that node.

nodeAffinity

nodeAffinity is another way to attract Pods to certain nodes, offering more flexibility than nodeSelector. It allows Pods to be scheduled on nodes that meet specific conditions using Supported Operators:

  • In
  • NotIn
  • Exists
  • DoesNotExist
  • Gt
  • Lt

There are three types of node affinity:

  • requiredDuringSchedulingIgnoredDuringExecution:

    • Scheduler places Pod only on a node matching the affinity rule.
    • Similar to nodeSelector but more complex.
  • preferredDuringSchedulingIgnoredDuringExecution:

    • Scheduler prefers a node matching the rule.
    • Pod can still be scheduled on any available node.
  • requiredDuringSchedulingIgnoredDuringExecution (introduced recently):

    • Evicts running Pods if the node no longer matches the affinity rule.

Affinity Behavior

Affinity behavior depends on when the affinity rules are evaluated:

  • DuringScheduling: The Pod is being scheduled (first-time placement).
  • DuringExecution: The Pod is already running and a change occurs that could affect node affinity.
TypeDuringSchedulingDuringExecution
1RequiredIgnored
2PreferredIgnored
3RequiredRequired

IgnoredDuringExecution means that once a Pod is scheduled, changes to node affinity won't affect its running state.

Sample Lab: Using required node affinity

Create a Kubernetes cluster in Amazon EKS and use node affinity to schedule Pods based on node labels.

Step 1: Create the Cluster

Use the following manifest to create the cluster:

eksops.yml
---
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
version: "1.23"
name: eksops
region: ap-southeast-1
nodeGroups:
- name: ng-dover
instanceType: t3.large
minSize: 0
maxSize: 5
desiredCapacity: 3
ssh:
publicKeyName: "k8s-kp"

Create the cluster with the command:

kubectl apply -f eksops.yml

Check the nodes:

kubectl get nodes

Example output:

NAME                STATUS   ROLES    AGE   VERSION
ip-192-168-11-247 Ready <none> 8h v1.23.13-eks-fb459a0
ip-192-168-56-187 Ready <none> 8h v1.23.13-eks-fb459a0
ip-192-168-81-3 Ready <none> 8h v1.23.13-eks-fb459a0

Step 2: Label the First Node

Add the disktype=ssd label to the first node:

kubectl label nodes ip-192-168-11-247 disktype=ssd

Verify the label:

kubectl get nodes --show-labels | grep ssd

Example output:

ip-192-168-11-247   Ready    <none>   8h    v1.23.13-eks-fb459a0   ....disktype=ssd...

Step 3: Create a Pod with Required Node Affinity

Use the following manifest to create a Pod with requiredDuringSchedulingIgnoredDuringExecution node affinity. This will schedule the Pod only on a node with the disktype=ssd label.

apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent

Apply the manifest:

kubectl apply -f https://k8s.io/examples/pods/pod-nginx-required-affinity.yaml

Step 4: Verify the Pod

The Pod will be scheduled on the node with the matching label (disktype=ssd), which in this case is ip-192-168-11-247.

kubectl get pods -o wide

Example output:

NAME    READY   STATUS    RESTARTS   AGE   IP              NODE                                                NOMINATED NODE   READINESS GATES
nginx 1/1 Running 0 3s 192.168.8.176 ip-192-168-11-247 <none> <none>

Step 5: Delete the Pod

To delete the Pod, run:

kubectl delete -f https://k8s.io/examples/pods/pod-nginx-required-affinity.yaml

Sample Lab: Using preferred node affinity

In this example, use preferredDuringSchedulingIgnoredDuringExecution node affinity to launch a Pod that prefers nodes with the disktype=ssd label.

This is similar to required affinity, but with the added option to specify a weight for each preference. The scheduler considers this weight when making scheduling decisions.

apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent

Apply the manifest:

kubectl apply -f https://k8s.io/examples/pods/pod-nginx-preferred-affinity.yaml