Understanding Node Affinity in Kubernetes: A Detailed Guide

Usama AijazUsama Aijaz
4 min read

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

  1. 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.

0
Subscribe to my newsletter

Read articles from Usama Aijaz directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Usama Aijaz
Usama Aijaz