Table of Contents
Introduction
In Kubernetes, efficiently placing pods on nodes can significantly impact performance and resource utilization. Node affinity provides a powerful mechanism for controlling pod placement based on node attributes, enabling administrators to optimize workload distribution and enhance cluster efficiency. Let’s explore how node affinity strategies can be leveraged to achieve these goals effectively.
The goal is to deploy web application related pods on a non-SSD disk type worker node and run the DB server on an SSD-based worker node.
Creating Namespace
Create the necessary namespace to deploy the app and db pods.
$ kubectl create namespace web-app-ns
Labeling Nodes
Label the Nodes as per the requirement, here we are labeling worker1 as SSD node and worker2 as non SSD worker.
$ kubectl label nodes k8swor1.linuxsysadmins.lan ssd=true
$ kubectl label nodes k8swor2.linuxsysadmins.lan ssd=false
Verify the node labels
[ansible@k8smas1 ~]$ kubectl describe nodes k8swor1.linuxsysadmins.lan | grep -i ssd
ssd=true
[ansible@k8smas1 ~]$
[ansible@k8smas1 ~]$ kubectl describe nodes k8swor2.linuxsysadmins.lan | grep -i ssd
ssd=false
[ansible@k8smas1 ~]$
Type of Node Affinity
There are two types of Node Affinity
requiredDuringSchedulingIgnoredDuringExecution
preferredDuringSchedulingIgnoredDuringExecution
The requiredDuringSchedulingIgnoreDuringExecution scheduler can’t schedule the Pod unless the rule is met.
The preferredDuringShedulingIgnoreDuringExecution tries to find a node that meets the rule. If a matching node is not available, the scheduler still schedules the Pod.
If you need to know little description about the nodeaffinity run below command.
$ kubectl explain pod.spec.affinity.nodeAffinity
Generating Pod Content
Run the Imperative command to generate the required YAML content for the APP pod.
$ kubectl run web-app-pod --image nginx --namespace web-app-ns --port=80 --dry-run=client -o yaml > web-app-pod.yaml
Remove the unnecessary content similar to creation timestamp and much more to keep the YAML content clean.
apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: run: web-app-pod name: web-app-pod namespace: web-app-ns spec: containers: - image: nginx name: web-app-pod ports: - containerPort: 80 resources: {} dnsPolicy: ClusterFirst restartPolicy: Always status: {}
Add the node affinity under spec to run the web pods under the non SSD worker nodes.
apiVersion: v1 kind: Pod metadata: labels: name: web-app namespace: web-app-ns spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: ssd operator: In values: - 'false' containers: - image: nginx name: web-app ports: - containerPort: 80
Verify whether the web app pods are placed in non SSD worker nodes.
[ansible@k8smas1 ~]$ kubectl get nodes --show-labels | grep ssd=
k8swor1.linuxsysadmins.lan Ready <none> 11d v1.29.6 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8swor1.linuxsysadmins.lan,kubernetes.io/os=linux,ssd=true
k8swor2.linuxsysadmins.lan Ready <none> 11d v1.29.6 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8swor2.linuxsysadmins.lan,kubernetes.io/os=linux,ssd=false
[ansible@k8smas1 ~]$
[ansible@k8smas1 ~]$ kubectl get pods -n web-app-ns web-app -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-app 1/1 Running 0 121m 172.16.39.209 k8swor2.linuxsysadmins.lan <none> <none>
[ansible@k8smas1 ~]$
Run the Imperative command to generate the required YAML content for the DB pod.
$ kubectl run web-db-pod --image mysql --namespace web-app-ns --port=3306 --dry-run=client -o yaml > web-db.yaml
apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: run: web-db-pod name: web-db-pod namespace: web-app-ns spec: containers: - image: mysql name: web-db-pod ports: - containerPort: 3306 resources: {} dnsPolicy: ClusterFirst restartPolicy: Always status: {}
Do a clean up and add the necessary require/preferred node affinity to place the DB pods on a SSD based worker nodes.
apiVersion: v1 kind: Pod metadata: labels: name: web-db namespace: web-app-ns spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: ssd operator: In values: - 'false' affinity: nodeAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 1 preference: matchExpressions: - key: ssd operator: In values: - 'true' containers: - name: web-db image: mysql env: - name: MYSQL_ROOT_PASSWORD value: Xy20934hJ#4Z482jHD ports: - containerPort: 3306
Let’s verify where the DB node scheduled.
[ansible@k8smas1 ~]$ kubectl get nodes --show-labels | grep ssd=
k8swor1.linuxsysadmins.lan Ready <none> 11d v1.29.6 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8swor1.linuxsysadmins.lan,kubernetes.io/os=linux,ssd=true
k8swor2.linuxsysadmins.lan Ready <none> 11d v1.29.6 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8swor2.linuxsysadmins.lan,kubernetes.io/os=linux,ssd=false
[ansible@k8smas1 ~]$
[ansible@k8smas1 ~]$ kubectl get pods -n web-app-ns web-db -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-db 1/1 Running 0 3m43s 172.16.99.145 k8swor1.linuxsysadmins.lan <none> <none>
[ansible@k8smas1 ~]$
That’s it we could see the DB pods are placed on the SSD base worker nodes by using Node Affinity.