Kubernetes Node Affinity; A Love Story between Nodes and Pods
Tags: kubernetes, devops, aws, gcp
Published: 2023-08-31 19:33:35

## Introduction
In this article, we will discuss designing a one-to-one heartfelt relationship between a node and a Kubernetes object (pod/deployment). This article at its core is centered on intentional pod scheduling with Kubernetes with a focus on Node affinity. In this piece of art, we will explore the definition of Node Affinity, the reason we instruct certain nodes to be deployed on certain pods, why this form of pod scheduling is preferred, and finally how to set up Node Affinity for a set of nodes and some pods. To follow this body of work it is important you understand the basic concepts of Kubernetes, you have a cluster up and running and you genuinely have your heart open to a love story. 

## A Love Story
In this love story, we have two friends called Claire and Fiona. Claire and Fiona are looking to get married but they have specific requirements for a suitor. They both insist on marrying tall men while Fiona would like a tall man who has a beard (however she is not adamant about it). Both friends would rather not get married if they don't find tall men, However in a surplus of tall men, Fiona would like a man with a beard. Our task in this article is to design "Men" for both Claire and Fiona. 

## Understanding Node affinity
To understand Node affinity assume the two friends are pods and the Suitors (Men) are nodes. Some pods have `Hard` requirements (tall men) these requirements are compulsory and an absence of them would leave the pod unscheduled, while some pods have `Soft` requirements (bearded men), these requirements are optional and they just streamline the process of finding a suitable node.  

We deliberately place such requirements on pods to ensure that those pods are deployed on certain nodes, for example, pods that require a lot of compute/memory resources should be deployed on nodes with heavy compute/memory resources. The primary reason for such a design is for deliberate pod scheduling and to override the default scheduling mechanism of the kube-scheduler. We mask the properties of these nodes by using labels and then we design the pods to look for these labels.  Let's move on to designing nodes that will be suitable for both Claira and Fiona. 

## Finding a Node for Claire
For this article, it is assumed that we have two fresh nodes running. On the terminal, run the following command, to view the nodes:

```console
michael@monarene:~$ kubectl get nodes
``` 

![Nodes running in a cluster](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oz41mu1ygaxywigfwwnq.png)

Notice that we have two distinct nodes, one ending with 54 on the first sub-string of the node name and another ending in 197 on the first substring of the node name. 

To deploy the claire pod, save the following configuration into `claire.yaml`. 

```
apiVersion: v1
kind: Pod
metadata:
  name: claire
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: height
            operator: In
            values:
            - tall
  containers:
  - name: with-node-affinity
    image: k8s.gcr.io/pause:2.0
```

Take a keen look at `spec.affinity.nodeAffinity` , you will find a field called `requiredDuringSchedulingIgnoreDuringExecution`, `requiredDuringScheduling` means that for the pod to be assigned a node, it is a must that the expressions on the pod match the requirements. In this case the requirement is that one of the labels of the pod must be `height=tall` . `IgnoreDuringExecution`  means that after scheduling on the node,  ignore further changes to the labels on the nodes, in simpler terms even if the labels on the node change to  `height=short` the pod should still continue to be assigned to the node. 

To start the deployment, run the following command on the terminal. 

```console
michael@monarene:~$ kubectl apply -f claire.yaml 
``` 

After a few seconds, check the state of the pod by running the following command, 

```console
michael@monarene:~$ kubectl get pods 
``` 

![Deployment of pods](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/joc3exmnwn8pdx8bl1lg.png)

We see that claire is stuck in a pending phase, this is the case because none of the nodes have the label `height=tall` Hence claire will not be scheduled on any of the nodes as this is a `Hard` requirement for scheduling. 

To further verify that this is the case, run the following command, 

```console
michael@monarene:~$ kubectl describe pods claire 
``` 

![kubectl describe pods claire](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/14zemfmhxy13rdufpfly.png)

To fix this, assign the node that ends with 54 the label `height=tall` , we do this by running the following command:

```console
michael@monarene:~$ kubectl label nodes ip-172-31-15-54.us-east-2.compute.internal height=tall
``` 

Now let us check the status of the pod by running the following command:

```console
michael@monarene:~$ kubectl get pods
``` 

![kubectl get pods](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eplo1cnjbjbqhvmdes1y.png)

We can now see that the pod is running as expected, And claire has been paired with a Suitor 🥰. To further show that claire was scheduled to the node ending with 54, run the following command:

```console
michael@monarene:~$ kubectl describe pods claire
``` 

![kubectl describe pods claire](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4x0gt959x337lj4lrt90.png)


## Finding a Node for Fiona
To setup the pod definition for Fiona, save the following configuration into `fiona.yaml`

```
apiVersion: v1
kind: Pod
metadata:
  name: fiona
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: height
            operator: In
            values:
            - tall
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: beard
            operator: In
            values:
            - present
  containers:
  - name: with-node-affinity
    image: k8s.gcr.io/pause:2.0
```

As per the configuration, you can see that Fiona requires that her man be tall, but amongst tall men, she would also like a bearded man. This is illustrated in the `preferredDuringScheduling` field , this requirement is what we referred to as a  `Soft` requirement. To further illustrate this, we will assign the node that ends with 197 with the labels `height=tall` and `beard=present` .  We can do this by running the following command:

```console
michael@monarene:~$ kubectl label nodes ip-172-31-37-197.us-east-2.compute.internal height=tall && kubectl label nodes ip-172-31-37-197.us-east-2.compute.internal beard=present
``` 
Next, we deploy fiona and see what node she moves to, We do this by running the following command: 

```console
michael@monarene:~$ kubectt apply -f fiona.yaml
``` 

Next, we check to see if she is running as expected, 

![kubectl get pods](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ktwj82n4kjdym7z68e3v.png)

We can see that Fiona is running and has been successfully scheduled to a pod. Now to check the pod she has been scheduled to we run the following command: 

```console
michael@monarene:~$ kubectl get pods -o wide
``` 

![kubectl get pods -o wide](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dz8ujj6x5vdfq1citj9d.png)

We see that Fiona has been scheduled on the appropriate node, the Suitor that is tall and also has beards, and this is how we schedule pods to suitable nodes. 


## Conclusion
In this article we used an illustration of a courting process to describe the intentional pod scheduling using Node Affinity, We configured two nodes with appropriate labels, we deployed our pods to their respective suitors (Nodes) and finally, we showed how to assign labels to nodes and pods to labels. Feel free to like, share, and comment on this article. Don't forget to subscribe to receive notifications when I post new articles. Thank you!