DevOps/Kubernetes

[Kubernetes] Taint & Toleration

TTOII 2022. 6. 6. 13:29
728x90

🚀 Taint & Toleration

 

🚀 Taint

테인트(Taints)와 톨러레이션(Tolerations) | Kubernetes

  • Taint : 특정 노드에 역할을 부여
  • Toleration : Taint 노드에 스케줄링 허용

 vagrant@k8s-node1  ~/schedule/affinity  kubectl describe node node1

Taints:             <none>
 node-role.kubernetes.io/master:NoSchedule

현재 시스템에서는 node1이 컨트롤 플레인이자 워커 노드로 작동하고 있다.

컨트롤 플레인 시스템에는 다음과 같이 Taint key에 Effect가 세팅되어 있다.

워커 노드에는 파드를 배치할 수 있으므로 node1에도 파드가 배치될 수 있다.

만약 node1이 컨트롤 플레인 역할만을 한다면 Taint가 설정되어 있을 것이다.

 

Taint가 과연 무엇이길래 스케줄링이 되지 않는가 ?

 

 vagrant@k8s-node1  ~  kubectl explain pod.spec.tolerations

FIELDS:
   effect       <string>

   key  <string>

   operator     <string>

   tolerationSeconds    <integer>

   value        <string>
  • operator
    • Exists : 키만 존재
    • Equal(default) : 값까지 같아야 한다.
  • effect
    • NoSchedule
    • PreferNoSchedule : 스케줄링 될 때 가능하면 배치하지 않는다. 이미 실행되고 있는 것들에 대해서는 상관없다.
    • NoExecute : 현재 실행되고 있는 것들까지 포함한다.

 

tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoSchedule"
kubectl taint nodes node1 key1=value1:NoSchedule

다음 YAML 파일과 명령형 커맨드는 똑같이 동작한다.
이때 해당 tolerations값을 사용하는 파드는 node1에 배치될 수 있다.

파드를 만들 때 tolerations을 설정할 수 있는 tolerationstaint조건이 맞으면 파드는 해당 노드에 배치될 수 있다.

 

Taint는 특정 노드에 역할, 기능을 부여한다.
컨트롤 플레인 전용 노드에서는 node-role.kubernetes.io/master:NoSchedule이 설정되어 있었다.

 

지금까지 파드를 만들 때 tolerations을 설정한 적이 없었다. 그래서 파드가 컨트롤 플레인에 배치될 수 없었다.

node-role.kubernetes.io/master:NoSchedule의 의미는 마스터이므로 스케줄링 하지말라는 뜻이다.

 

그렇다면 Taint는 단순히 스케줄링을 막는 것인가 ?

1차원적으로는 그렇게 생각할 수 있지만 근본적으로 특정한 역할을 부여하는 것이다.

즉, 마스터에 배치하고 싶으면 node-role.kubernetes.io/master:NoSchedule tolerations을 세팅해야 한다.

 

kubectl taint nodes node1 key1=value1:NoSchedule-

다음 명령으로 taint를 제거할 수 있다.

 

🚀 실습

 vagrant@k8s-node1  ~/schedule/affinity  kubectl taint node node1 node-role.kubernetes.io/master:NoSchedule
node/node1 tainted

 vagrant@k8s-node1  ~/schedule/affinity  kubectl describe node node1 | grep -i taint
Taints:             node-role.kubernetes.io/master:NoSchedule

다음과 같이 taint 설정이 되어있는 것을 확인할 수 있다.

 

 vagrant@k8s-node1  ~/schedule/affinity  kubectl create -f myweb-a.yaml
replicaset.apps/myweb-a created
 vagrant@k8s-node1  ~/schedule/affinity  kubectl get po -o wide        
NAME                                      READY   STATUS    RESTARTS   AGE   IP              NODE     NOMINATED NODE   READINESS GATES
myweb-a-464bw                             0/1     Pending   0          4s    <none>          <none>   <none>           <none>
myweb-a-hn65z                             1/1     Running   0          4s    10.233.96.145   node2    <none>           <none>
myweb-a-szhkz                             1/1     Running   0          4s    10.233.92.165   node3    <none>           <none>
nfs-client-provisioner-758f8cd4d6-wpjbt   1/1     Running   0          3d    10.233.92.110   node3    <none>           <none>

Pending이 걸리고 배치가 되지 않는다.

노드 3개가 있고 anti-affinity에 의해 myweb-a는 모두 다른 노드에 배치되어야 한다.

따라서 node1에 배치되어야 하나 배치할 수 없다. 

 

 vagrant@k8s-node1  ~/schedule/affinity  kubectl describe po myweb-a-464bw

Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  52s   default-scheduler  0/3 nodes are available: 1 node(s) had taint {node-role.kubernetes.io/master: }, that the pod didn't tolerate, 2 node(s) didn't match pod anti-affinity rules.

1개의 node는 taint때문에 2개의 노드는 anti-affinity 때문에 안되며 tolerate가 없다고 출력한다.

 

 

myweb-a.yaml

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: myweb-a
spec:
  replicas: 3
  selector:
    matchLabels:
      app: a
  template:
    metadata:
      labels:
        app: a
    spec:
      tolerations: node-role.kubernetes.io/master:NoSchedule
      operator: Exists
      effect: NoSchedule
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 10
              preference:
                matchExpressions:
                  - key: gpu
                    operator: Exists
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                  matchLabels:
                    app: a
              topologyKey: "kubernetes.io/hostname"
      containers:
        - name: myweb
          image: ghcr.io/c1t1d0s7/go-myweb
 vagrant@k8s-node1  ~/schedule/taint  kubectl create -f myweb-a.yaml
replicaset.apps/myweb-a created
 vagrant@k8s-node1  ~/schedule/taint  kubectl get po -o wide        
NAME                                      READY   STATUS    RESTARTS   AGE   IP              NODE    NOMINATED NODE   READINESS GATES
myweb-a-bt8cv                             1/1     Running   0          2s    10.233.92.166   node3   <none>           <none>
myweb-a-jnk8w                             1/1     Running   0          2s    10.233.96.146   node2   <none>           <none>
myweb-a-wt829                             1/1     Running   0          2s    10.233.90.105   node1   <none>           <none>
nfs-client-provisioner-758f8cd4d6-wpjbt   1/1     Running   0          3d    10.233.92.110   node3   <none>           <none>

node1에도 정상적으로 배치된다.

 

🚀 Toleration

 vagrant@k8s-node1  ~/schedule/taint  kubectl describe node node1

Non-terminated Pods:          (12 in total)
  Namespace                   Name                               CPU Requests  CPU Limits  Memory Requests  Memory Limits  Age
  ---------                   ----                               ------------  ----------  ---------------  -------------  ---
  default                     myweb-a-wt829                      0 (0%)        0 (0%)      0 (0%)           0 (0%)         3m26s
  ingress-nginx               ingress-nginx-controller-cmzt4     0 (0%)        0 (0%)      0 (0%)           0 (0%)         5d12h
  kube-system                 calico-node-r257f                  150m (8%)     300m (16%)  64M (1%)         500M (14%)     10d
  kube-system                 coredns-8474476ff8-q7svm           100m (5%)     0 (0%)      70Mi (2%)        170Mi (5%)     10d
  kube-system                 dns-autoscaler-5ffdc7f89d-r45qt    20m (1%)      0 (0%)      10Mi (0%)        0 (0%)         10d
  kube-system                 kube-apiserver-node1               250m (13%)    0 (0%)      0 (0%)           0 (0%)         10d
  kube-system                 kube-controller-manager-node1      200m (11%)    0 (0%)      0 (0%)           0 (0%)         10d
  kube-system                 kube-proxy-m2xmr                   0 (0%)        0 (0%)      0 (0%)           0 (0%)         5d12h
  kube-system                 kube-scheduler-node1               100m (5%)     0 (0%)      0 (0%)           0 (0%)         10d
  kube-system                 metrics-server-c57c76cf4-x9nwj     100m (5%)     100m (5%)   200Mi (6%)       200Mi (6%)     5d12h
  kube-system                 nodelocaldns-qc6vf                 100m (5%)     0 (0%)      70Mi (2%)        170Mi (5%)     10d
  metallb-system              speaker-zstnm                      0 (0%)        0 (0%)      0 (0%)           0 (0%)         5d22h

컨트롤 플레인 역할을 하는 node1 파드들을 살펴보자

 

 vagrant@k8s-node1  ~/schedule/taint  kubectl describe po -n ingress-nginx ingress-nginx-controller-cmzt4

Tolerations:                 node.kubernetes.io/disk-pressure:NoSchedule op=Exists
                             node.kubernetes.io/memory-pressure:NoSchedule op=Exists
                             node.kubernetes.io/not-ready:NoExecute op=Exists
                             node.kubernetes.io/pid-pressure:NoSchedule op=Exists
                             node.kubernetes.io/unreachable:NoExecute op=Exists
                             node.kubernetes.io/unschedulable:NoSchedule op=Exists
 vagrant@k8s-node1  ~/schedule/taint  kubectl describe po -n kube-system kube-apiserver-node1
Tolerations:       :NoExecute op=Exists

Tolerations설정이 되어있다.

  • PreferNoSchedule
    • NoSchedule
      • NoExecute

다음과 같은 포함 관계를 갖는다 NoExecuteNoSchedule을 포함하고 NoSchedulePreferNoSchedule을 포함한다.

PreferNoSchedule가 가장 낮은 효과를 가지며 NoExecute가 가장 높은 효과를 가진다.

 

Tolerations:       :NoExecute op=Exists

따라서 해당 내용의 의미는 아무 키나 상관없이 NoExecute는 실행할 수 있다는 것이다.

쉽게 말하면 Taint가 걸려있어도 아무 상관이 없다는 뜻이다.

 

kube-apiserver는 static pod이기 때문에 반드시 node1에 배치되어야 한다.
node1에만 배치하려고 보니 컨트롤 플레인에는 Taint 설정이 되어있을 수 있는데 그 설정을 무력화 시킨다.

그래서 kube-apiserver가 배치될 수 있다.

 

 vagrant@k8s-node1  ~/schedule/taint  kubectl describe po -n metallb-system speaker-zstnm

Tolerations:                 node-role.kubernetes.io/control-plane:NoSchedule op=Exists
                             node-role.kubernetes.io/master:NoSchedule op=Exists
                             node.kubernetes.io/disk-pressure:NoSchedule op=Exists
                             node.kubernetes.io/memory-pressure:NoSchedule op=Exists
                             node.kubernetes.io/network-unavailable:NoSchedule op=Exists
                             node.kubernetes.io/not-ready:NoExecute op=Exists
                             node.kubernetes.io/pid-pressure:NoSchedule op=Exists
                             node.kubernetes.io/unreachable:NoExecute op=Exists
                             node.kubernetes.io/unschedulable:NoSchedule op=Exists

metallb-system에도 Tolerations가 설정되어 있다.

node-role.kubernetes.io/master:NoSchedule op=Exists에 의해 컨트폴 플레인 전용 노드에도 배치될 수 있는 것이다.

 

정리해보자면

특정 노드에 Taint를 건다고 하는 것은 특정 역할을 부여하는 것과 같다.

파드를 생성할 때 tolerations를 설정해서 해당되는 역할이 있는 노드에 배치되도록 스케줄링을 조정할 수 있다.

만약 tolerations가 없는 파드들은 Taint가 걸려있지 않은 나머지 파드들에만 배치될 수 있다.

그렇기 때문에 Taint의 목적은 노드에 역할을 부여하는 것이다.

 

 vagrant@k8s-node1  ~/schedule/taint  kubectl describe po -n kube-system coredns-8474476ff8-q7svm

Node-Selectors:              kubernetes.io/os=linux
Tolerations:                 node-role.kubernetes.io/control-plane:NoSchedule
                             node-role.kubernetes.io/master:NoSchedule
                             node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s

kubeadm으로 설치할 때 network 플러그인으로 Calico를 사용했는데 Calico 설치 전에는 Not Ready라고 되어있었다.

Not Ready가 되어있으면 쿠버네티스가 노드에 자동으로 Taint를 설정한다.

즉, Ready가 되지 않은 노드는 Taint가 설정되어 있다.

그러면 파드를 생성한다해도 tolerations를 설정하지 않으면 배치되지 않는다.

 

실제로 쿠버네티스가 설치된 이후에 Calico가 설치된다.

쿠버네티스가 설치된 직후에는 노드의 상태가 Not Ready 상태이다.

그때 Calico를 배치해야 Ready 상태가 되는데 Taint가 걸려있으면 Calico 파드를 배치할 수 없다.

 

그래서 Calico의 경우 node.kubernetes.io/not-ready:NoExecute op=Exists for 300snot-ready를 허용시켜준다. 그래야 배치될 수 있고 그래야 Ready가 될 수 있기 때문이다.

 

Calico는 DaemonSet이다.
1개의 노드에서 스케일링을 거쳐 1개의 노드를 추가한다면 DS에 의해서 Calico를 배치하려고 할 것이다.
그런데 Calico를 배치시키기 전에는 Not Ready이다.

Calico를 배치해야 Ready가 되는데 Taint가 걸려있어 파드를 배치할 수 없는 상태이다.

따라서 Calico에 Tolerations가 세팅되어 있는 이유는 컨트롤 플레인에 Taint가 걸려 있어도 파드를 강제로 배치시키기 위함이다.

728x90