DEV Community

Sina Tavakkol
Sina Tavakkol

Posted on

40 Days Of Kubernetes (14/40)

Day 14/40

Taints and Tolerations in Kubernetes

Video Link
@piyushsachdeva
Git Repository
My Git Repo

We're going to look at taint and toleration. While a node has a label it means it has taint for scheduling a workload with that specific label and doesn't tolerate other workloads to be scheduling on itself.

We taint node and tell a pod to tolerate that taint to be scheduled on that node.
Image description
(Photo from the video)

"Tolerations are applied to pods. Tolerations allow the scheduler to schedule pods with matching taints. Tolerations allow scheduling but don't guarantee scheduling: the scheduler also evaluates other parameters as part of its function.

Taints and tolerations work together to ensure that pods are not scheduled onto inappropriate nodes. One or more taints are applied to a node; this marks that the node should not accept any pods that do not tolerate the taints."
Note There are two special cases:

  • An empty key with operator Exists matches all keys, values and effects which means this will tolerate everything.

  • An empty effect matches all effects with key key1.

The allowed values for the effect field are:

  • NoExecute > for newer and existing pods
  • NoSchedule > for newer pods
  • PreferNoSchedule > No Guaranteed

source

A toleration is essentially the counter to a taint, allowing a pod to ignore taints applied to a node. A toleration is defined in the pod specification and must match the key, value, and effect of the taint it intends to tolerate.
Toleration Operators: While matching taints, tolerations can use operators like Equal and Exists.
The Equal operator requires an exact match of key, value, and effect , whereas the Exists operator matches a taint based on the key alone, disregarding the value.

For instance:

tolerations:
- key: "key"
  operator: "Equal"
  value: "value"
  effect: "NoSchedule"
Enter fullscreen mode Exit fullscreen mode

source


1. Taint the node

root@localhost:~# kubectl get nodes
NAME                       STATUS   ROLES           AGE   VERSION
lucky-luke-control-plane   Ready    control-plane   8d    v1.30.0
lucky-luke-worker          Ready    <none>          8d    v1.30.0
lucky-luke-worker2         Ready    <none>          8d    v1.30.0
root@localhost:~# kubectl taint node lucky-luke-worker gpu=true:NoSchedule
node/lucky-luke-worker tainted
root@localhost:~# kubectl taint node lucky-luke-worker2 gpu=true:NoSchedule
node/lucky-luke-worker2 tainted
root@localhost:~# kubectl describe node lucky-luke-worker | grep -i taints
Taints:             gpu=true:NoSchedule

Enter fullscreen mode Exit fullscreen mode
  • Let's schedule a pod
root@localhost:~# kubectl run nginx --image=nginx
pod/nginx created
root@localhost:~# kubectl get pods
NAME    READY   STATUS    RESTARTS   AGE
nginx   0/1     Pending   0          6s

Enter fullscreen mode Exit fullscreen mode

It says it's in Pending status, so let's see the error message of the pod:

root@localhost:~# kubectl describe pod nginx
Name:             nginx
Namespace:        default
Priority:         0
Service Account:  default
Node:             <none>
Labels:           run=nginx
Annotations:      <none>
Status:           Pending
IP:
IPs:              <none>
Containers:
  nginx:
    Image:        nginx
    Port:         <none>
    Host Port:    <none>
    Environment:  <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-4xh8p (ro)
Conditions:
  Type           Status
  PodScheduled   False
Volumes:
  kube-api-access-4xh8p:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  89s   default-scheduler  0/3 nodes are available: 1 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: }, 2 node(s) had untolerated taint {gpu: true}. preemption: 0/3 nodes are available: 3 Preemption is not helpful for scheduling.

Enter fullscreen mode Exit fullscreen mode

And the message is clear to us :)

0/3 nodes are available.
1 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: }
2 node(s) had untolerated taint {gpu: true}
0/3 nodes are available: 3 Preemption is not helpful for scheduling.
Enter fullscreen mode Exit fullscreen mode
  • We need create toleration on a pod to be scheduled
root@localhost:~# kubectl run redis --image=redis --dry-run=client -o yaml > redis_day14.yaml
root@localhost:~# vim redis_day14.yaml

Enter fullscreen mode Exit fullscreen mode

Adding tolerations to yaml file:

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: redis
  name: redis
spec:
  containers:
  - image: redis
    name: redis
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
  tolerations:
    - key: "gpu"
      operator: "Equal"
      value: "true"
      effect: "NoSchedule"
status: {}
Enter fullscreen mode Exit fullscreen mode

Apply the file:

root@localhost:~# kubectl apply -f redis_day14.yaml
pod/redis created
root@localhost:~# kubectl get pods
NAME    READY   STATUS    RESTARTS   AGE
nginx   0/1     Pending   0          10m
redis   1/1     Running   0          5s
root@localhost:~# kubectl get pods -o wide
NAME    READY   STATUS    RESTARTS   AGE   IP            NODE                 NOMINATED NODE   READINESS GATES
nginx   0/1     Pending   0          10m   <none>        <none>               <none>           <none>
redis   1/1     Running   0          17s   10.244.2.12   lucky-luke-worker2   <none>           <none>

Enter fullscreen mode Exit fullscreen mode

Let's delete the taint of one node and see what will happen to our pending pod:

root@localhost:~# kubectl taint node lucky-luke-worker gpu=true:NoSchedule-
node/lucky-luke-worker untainted
root@localhost:~# kubectl get pods -o wide
NAME    READY   STATUS    RESTARTS   AGE   IP            NODE                 NOMINATED NODE   READINESS GATES
nginx   1/1     Running   0          22m   10.244.1.14   lucky-luke-worker    <none>           <none>
redis   1/1     Running   0          11m   10.244.2.12   lucky-luke-worker2   <none>           <none>

Enter fullscreen mode Exit fullscreen mode
  • By default, the control-plane node has taint NoSchedule
root@localhost:~# kubectl get nodes
NAME                       STATUS   ROLES           AGE   VERSION
lucky-luke-control-plane   Ready    control-plane   8d    v1.30.0
lucky-luke-worker          Ready    <none>          8d    v1.30.0
lucky-luke-worker2         Ready    <none>          8d    v1.30.0
root@localhost:~# kubectl describe node lucky-luke-control-plane | grep Taint
Taints:             node-role.kubernetes.io/control-plane:NoSchedule
Enter fullscreen mode Exit fullscreen mode

Selector

Instead a node can decide which type pod to accept, it will give the decision to a pod to which node can deployed on.

  • Let's try:
root@localhost:~# kubectl run nginx2 --image=nginx --dry-run=client -o yaml > nginx2-day14.yaml
root@localhost:~# vim nginx2-day14.yaml
Enter fullscreen mode Exit fullscreen mode
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: nginx2
  name: nginx2
spec:
  containers:
  - image: nginx
    name: nginx2
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
  nodeSelector:
    gpu: "false"
status: {}
Enter fullscreen mode Exit fullscreen mode
root@localhost:~# kubectl apply -f nginx2-day14.yaml
pod/nginx2 created
root@localhost:~# kubectl get pods -o wide
NAME     READY   STATUS    RESTARTS   AGE   IP            NODE                 NOMINATED NODE   READINESS GATES
nginx    1/1     Running   0          46m   10.244.1.14   lucky-luke-worker    <none>           <none>
nginx2   0/1     Pending   0          8s    <none>        <none>               <none>           <none>
redis    1/1     Running   0          35m   10.244.2.12   lucky-luke-worker2   <none>           <none>

Enter fullscreen mode Exit fullscreen mode
  • Label one node and let's see what will happen:
root@localhost:~# kubectl label node lucky-luke-worker gpu="false"
node/lucky-luke-worker labeled
root@localhost:~# kubectl get pods -o wide
NAME     READY   STATUS    RESTARTS   AGE     IP            NODE                 NOMINATED NODE   READINESS GATES
nginx    1/1     Running   0          49m     10.244.1.14   lucky-luke-worker    <none>           <none>
nginx2   1/1     Running   0          3m21s   10.244.1.15   lucky-luke-worker    <none>           <none>
redis    1/1     Running   0          38m     10.244.2.12   lucky-luke-worker2   <none>           <none>
Enter fullscreen mode Exit fullscreen mode

Top comments (0)