Hello everyone! Okay since last article we’ve discuss some label and selector also service as a networking in Kubernetes. Now in this attempt we’re going to discuss Manual Scheduling, Taint & Toleration, Node Affinity and Resource Limit. It’s going to be more advance topic, and it takes time to understand it. Don’t give up to understand the concept, keep the learning up before you became a Kubernetes Administrator.

Let’s go !

1. Manual Scheduling

There are different ways to manually schedule a pod on a node, without the built in scheduler pod.

How scheduling works

Manual Scheduling Logic Scheme

Scheduler will inspect each node to check the nodeName field (assign automatically):

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx
    ports:
      - containerPort: 8080
  nodeName: node02

It then identifies the pod that doesn’t have a nodeName to became a candidate for which node that this pod should be by running scheduling algorithm. After being identified, it will fill the void value on a nodeName and then create a binding object. Here’s the example of binding manifest file look like:

apiVersion: v1
kind: Binding
metadata:
  name: nginx
target:
  apiVersion: v1
  kind: Node
  name: node02

And then send a post request to the pods binding API with the data set to the binding object in a JSON format:

curl --header "Content-Type:application/json" --request POST --data http://$SERVER/api/v1/namespaces/default/pods/$PODNAME/binding/

What happen if there is no scheduler?

The pod that you create will launch with a pending status. And to resolve that you just simply need to fill nodeName manually when at the creation time, not when the pod is already running, because Kubernetes won’t allow that.

2. Taint & Toleration

So simply taint is a rule that set to the node and toleration is a rule-tolerance that set to the pod.

How it really look like?

Taint is a rule that attach on a node while Toleration on a pod.

How to configure taints and tolerations?

Taints – Node

💡 kubectl taint nodes node-name key=value:taint-effect NoSchedule | PreferNoSchedule | NoExecute

taint-effect means What happens to PODs that do not tolerate this taint?

Here’s how to make node1 taint to some rule: kubectl taint nodes node1 app=myapp:NoExecute

Then the pod who stay after node is being tainted, will be killed.

Tolerations – Pods

For instance here use the manifest file to configure it based on example above. Like:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx
  tolerations:
  - key: "app"
    operator: "Equal"
    value: "myapp"
    effect: "NoExecute"

💡 Make the tolerations on the manifest file based on taint key value and effect.

Use Case on Master Node

Master node isn’t allowing any pod to deploy there, it use taints and tolerations concept. Use this command to check: kubectl describe node kubemaster | grep Taint

It’ll show: Taints: [node-role.kubernetes.io/master:NoSchedule](<http://node-role.kubernetes.io/master:NoSchedule>)

💡 You can untainted with addition “-” at the end of your command. The command is same as you tainted a node.

3. Node Selector & Node Affinity

Node can be labeled and selected with node selector. So the pod can be assign into the right node according to the workload.

How to label and select a node?

For instance her give the node a label first kubectl label nodes node01 performance=high, then select it under spec field.

...
nodeSelector:
  performance: high
...

But it has a limitation if we just use node selector, not every case can get in. Like OR || NOT case operation.

Node Affinity

Here’s how to configure it in file, Affinity location is under spec field. If in deployment file is under template field.

...
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
	- matchExpressions:
	  - key: size
	    operator: In
	    values:
            - Large
	    - Medium

It means the pod will assign into node that large OR medium, because it use In operator. There are exception operator like Not In, also other operator like Exists, etc.

What if Node Affinity can’t match a node with the given expression?

There are types of node affinity. We’ll classified it based on pod’s life cycle:

TypesDuringSchedulingDuringExecution
Type 1RequiredIgnored
Type 2PreferredIgnored
Type 3RequiredRequired
DuringScheduling is the state when pod doesn’t exist and just created for the first time. While DuringExecution is the state when a part of pod has been running and you make a change, like change the node’s label.
  • If During Scheduling = Required → Apply Node Affinities Rule in the first place → Not Match with given expression → Pod are not scheduled → for important pod.
  • If During Scheduling = Preferred → Apply Node Affinities Rule in the first place → Not Match with given expression → Put the pod anywhere → less important pod.
  • If During Execution = Ignored → Pod continue to run → changes won’t impact pod.
  • If During Execution = Required → Pod will be terminated → changes will impact pod.

Combining Taint & Toleration with Node Affinity

Combining NA and T&T Rules

In order to make each pod goes to the node that we want, we put the label to each node and use node affinity. Then to prevent other pod to get in to our node, we use taint and toleration.

4. Resource Request & Limit

Some set of rules to limit or request your node or pod resource. This is very important in production, because you won’t let a pod is built without a resource limit or request. So here’s how to configure it under the manifest file :

Resource Request

...
spec:
  containers:
  - name: 
    ...
    resources:
      requests:
        memory: "1Gi"
	cpu: 1

Resource Limits

...
spec:
  containers:
  - name: 
    ...
    resources:
      requests:
        memory: "1Gi"
	cpu: 1
      limits:
        memory: :"2Gi"
        cpu: 2

If the pod exceeding the limits, then it’ll be terminated.

How to change default resources?

“When a pod is created the containers are assigned a default CPU request of 0.5 and memory of 256Mi”.

For the POD to pick up those defaults you must have first set those as default values for request and limit by creating a Limit Range in that namespace.

apiVersion: v1
kind: LimitRange
metadata:
   name: mem-limit-range
spec:
   limits:
   - default:
       memory: 512Mi
     defaultRequest:
       memory: 256Mi
     type: Container
apiVersion: v1
kind: LimitRange
metadata:
   name: cpu-limit-range
spec:
   limits:
   - default:
       memory: 1
     defaultRequest:
       memory: 0.5
     type: Container

The status OOMKilled  indicates that it is failing because the pod ran out of memory. Identify the memory limit set on the POD.


I hope you guys can understand the concept. I suggest if you are haven’t attempt the hands-on, you need to immediately do it. Because soon you’ll be understand it while you’re doing it. You can read more on :

Resource Management for Pods and Containers

Kubernetes.io

Okay that’s all for now. See you!

Last modified: April 28, 2022

Author

Comments

Write a Reply or Comment

Your email address will not be published.