nodeSelectors and nodeAffinity
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:
InNotInExistsDoesNotExistGtLt
There are three types of node affinity:
-
requiredDuringSchedulingIgnoredDuringExecution:
- Scheduler places Pod only on a node matching the affinity rule.
- Similar to
nodeSelectorbut 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.
| Type | DuringScheduling | DuringExecution |
|---|---|---|
| 1 | Required | Ignored |
| 2 | Preferred | Ignored |
| 3 | Required | Required |
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:
---
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