Understanding Node Affinity in Kubernetes: A Detailed Guide
Node affinity is a powerful Kubernetes feature that allows you to control which nodes your pods are scheduled on. It enables you to specify rules about which nodes are eligible to host particular pods, based on labels assigned to nodes. This article covers everything you need to know about node affinity, including practical examples with implementation commands and outputs, aimed at both beginners and professionals.
1. What is Node Affinity?
Node affinity is a set of rules used by the Kubernetes scheduler to determine where a pod should be placed. These rules can either require that a pod be placed on a node that matches specific criteria (hard requirement) or prefer that a pod be placed on such a node (soft requirement). Node affinity is expressed using nodeAffinity
in the pod's spec
.
2. Types of Node Affinity
RequiredDuringSchedulingIgnoredDuringExecution
This type of node affinity rule is a hard requirement. If a pod can't be scheduled on a node that meets this condition, the pod won't be scheduled at all.
PreferredDuringSchedulingIgnoredDuringExecution
This type of node affinity rule is a soft requirement. The Kubernetes scheduler tries to place the pod on a node that matches the criteria, but if no suitable node is found, the pod is still scheduled on a non-preferred node.
3. Labeling Nodes
Before implementing node affinity, you need to label your nodes. Node labels are key-value pairs that are used by node affinity rules.
To label a node, use the following command:
kubectl label nodes <node-name> <label-key>=<label-value>
4. Example 1: Required Node Affinity
In this example, we'll create a pod that must be scheduled on a node with the label env=production
.
Here we have two nodes cluster named as "controlplane" and "node01" shown in image:
Step 1: Label a Node
kubectl label nodes node01 env=production
Output is shown in following image:
We can find the node based on labels with the following command:
kubectl get nodes -l key=value
Step 2: Define the Pod with Node Affinity
Create a YAML file named required-node-affinity.yaml
with the following content:
Step 3: Apply the Configuration
kubectl apply -f required-node-affinity.yaml
Step 4: Check Pod Placement
Verify that the pod is running on the correct node:
kubectl get pods -o wide
We should see that the pod nginx-required
is scheduled on the node with the env=production
label like below image.
5. Example 2: Preferred Node Affinity
Now, let's create a pod that prefers to be scheduled on a node with the label env=staging
, but it's not mandatory.
Step 1: Change the Node Label
kubectl label nodes <node-name> env=staging --overwrite
The above command is used for overwriting labels and the output is below in image.
Step 2: Define the Pod with Preferred Node Affinity
Create a YAML file named preferred-node-affinity.yaml
with the following content:
apiVersion: v1
kind: Pod
metadata:
name: nginx-preferred
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: env
operator: In
values:
- staging
containers:
- name: nginx
image: ngin
Step 3: Apply the Configuration.
kubectl apply -f preferred-node-affinity.yaml
Step 4: Check Pod Placement
kubectl get pods -o wide
You should see that the pod nginx-preferred
is scheduled on the node with the env=staging
label like below image, but if no such node is available, it will be scheduled on another node.
Let's check preferredDuringSchedulingIgnoredDuringExecution works or not:
Here we changed both node's labels which are not mapping to pod's matchExpressions.
kubectl label nodes <node-name> abc=xyz --overwrite
kubectl label nodes <node-name> name=abc
#we did't use --overwrite in second command because we did't lebel it
Now delete Example 2 pod re-apply Example 2 pod name as "nginx-preferred" by using below commands
kubectl delete pod <pod-name>
kubectl delete -f <pod-file.yaml>
Here we are using second command because we create pod by yaml but we can also use first command.The result is in below image
Now apply pod file again by using below command
kubectl apply -f preferred-node-affinity.yaml
Now display pods again by using given command:
kubectl get po -owide
Output should be like given image:
It scheduled the pod on any node because it didn't find any node for matching "matchExpressions:" because we mention "Affinity" "Preferred" in yaml file
6. Changing Node Labels Dynamically
In real-world scenarios, node labels might change dynamically. For instance, a node's environment label could switch from production
to staging
. Kubernetes does not reschedule pods based on changes in labels if you use IgnoredDuringExecution
, but you can use these changes in future deployments.
Dynamic Label Change Example
- Change the label:
kubectl label nodes <node-name> env=development --overwrite
You can see in the given image that pods are running on same nodes where they scheduled.
7. Conclusion
Node affinity is a versatile tool that provides fine-grained control over pod scheduling in Kubernetes. By using node affinity rules, you can ensure that your applications are hosted on appropriate nodes, improving performance and resource utilization. Whether you're a beginner or a professional, understanding and using node affinity can significantly enhance your Kubernetes deployments.
Subscribe to my newsletter
Read articles from Usama Aijaz directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by