k8s--pod 調度、定向調度、親和性調度、污點和容忍


介紹

在默認情況下,一個 pod 在哪個 node 節點上運行,是由 Scheduler 組件采用相應的算法算出來的,這個過程是不受人工控制的。但是在實際使用中,這並不滿足需求,因為在很多情況下,我們想控制某些 pod 到達某些節點上,那么應該怎么做呢?這就涉及到 kubernetes 對 pod 的調度規則,kubernetes 提供了四大類調度方式

  • 自動調度:運行在哪個節點上完全由 Scheduler 經過一系列的算法計算得出
  • 定向調度:有兩種,根據節點名稱(NodeName)或者節點選擇器(NodeSelector)
  • 親和性調度:NodeAffinity、PodAffinity、PodAntiAffinity
  • 污點(容忍)調度:Taints、Toleration

默認就是自動調度,所以下面來看其他的幾種調度方式

定向調度

定向調度,指的是利用在 pod 上聲明 nodeName 或者 nodeSelector,以此將 pod 調度到期望的 node 節點上。注意,這里的調度是強制的,這就意味着即使要調度的目標 node 不存在,也會向上面進行調度,只不過 pod 運行失敗而已

NodeName

NodeName 用於強制將 pod 調度到指定的 name 的 node 節點上,這種方式,其實是直接跳過 Scheduler 的調度邏輯,直接將 pod 調度到指定名稱的節點

接下來,實驗一下:創建一個 pod-nodename.yaml 文件

apiVersion: v1
kind: Pod
metadata:
  name: pod-nodename
  namespace: zouzou
spec:
  containers:
  - name: nginx
    image: nginx:1.14
  nodeName: dce-10-6-215-190 # 指定調度到 dce-10-6-215-190 節點上

 如果你不知道 nodeName 的話,使用下面命令查看

kubectl get node

創建 pod,查看 pod

# 創建 pod
kubectl apply -f pod-nodename.yaml

查看 pod 的信息,可以看到 pod 已經分配給了 dce-10-6-215-190 的節點上

# 可以看到 pod 分配到了 dce-10-6-215-190 的節點上,有人說,可能是隨機分配的,那你也可以寫一個不存在的 node 地址試下
[root@dce-10-6-215-215 tmp]# kubectl get pod pod-nodename -n zouzou -o wide
NAME           READY   STATUS    RESTARTS   AGE   IP               NODE               NOMINATED NODE   READINESS GATES
pod-nodename   1/1     Running   0          89s   172.29.190.141   dce-10-6-215-190   <none>           <none>
NodeSelector

NodeSelector 用於將 pod 調度到添加了指定標簽的 node 節點上,它是通過 kubernetes 的 label-selector 機制實現的,也就是說,在 pod 創建之前,會由 scheduler 使用 MatchNodeSelector 調度策略進行 label 匹配,找出目標 node,然后將 pod 調度到目標節點,該匹配規則是強制約束。

接下來,實驗一下:首先查看下節點的 labels

[root@dce-10-6-215-215 tmp]# kubectl get node --show-labels
NAME               STATUS   ROLES             AGE    VERSION    LABELS
dce-10-6-215-190   Ready    <none>            7d3h   v1.18.20   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=dce-10-6-215-190,kubernetes.io/os=linux
dce-10-6-215-200   Ready    <none>            7d1h   v1.18.20   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=dce-10-6-215-200,kubernetes.io/os=linux
dce-10-6-215-215   Ready    master,registry   8d     v1.18.20   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=dce-10-6-215-215,kubernetes.io/os=linux,node-role.kubernetes.io/master=,node-role.kubernetes.io/registry=

上面有很多的標簽,為了測試方便,在此基礎上給兩個 node 節點添加兩個簡單的標簽

kubectl label node dce-10-6-215-190 nodeenv=pro
kubectl label node dce-10-6-215-200 nodeenv=test

在來查看下對應的標簽

這樣我們就給兩個節點打上了標簽

創建一個 pod-nodeselector.yaml 文件,並使用它創建 Pod

apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeselector
  namespace: zouzou
spec:
  containers:
  - name: nginx
    image: nginx:1.14
  nodeSelector: 
    nodeenv: pro # 指定調度到具有 nodeenv=pro 標簽的節點上

創建 pod 查看詳情,可以看到,pod 分配給了 nodeenv=pro 的標簽節點上

# 創建 pod
[root@dce-10-6-215-215 tmp]# kubectl apply -f pod-nodeselector.yaml
pod/pod-nodeselector created

# 查看 pod 在 dce-10-6-215-190 上了,你也可以寫個不存在的標簽測試是不是隨機分配的
[root@dce-10-6-215-215 tmp]# kubectl get pod pod-nodeselector -n zouzou -o wide
NAME               READY   STATUS    RESTARTS   AGE   IP               NODE               NOMINATED NODE   READINESS GATES
pod-nodeselector   1/1     Running   0          48s   172.29.190.142   dce-10-6-215-190   <none>           <none>

親和性調度

上面,介紹了兩種定向調度的方式,使用起來非常方便,但是也有一定的問題,那就是如果沒有滿足條件的 node,那么 pod 將不會被運行,即使在集群中還有可用 node 列表也不行,這就限制了它的使用場景

基於上面的問題,kubernetes 還提供了一種親和度(Affinity)調度。它在 NodeSelector 的基礎上進行了擴展,可以通過配置的形式,實現優先選擇滿足條件的 Node 進行調度,如果沒有,也可以調度到不滿足條件的節點上,使調度更加靈活

Affinity 主要分為三類

  • nodeAffinity(node 親和性):以 node 為目標,解決 pod 可以調度到哪些 node 上的問題
  • podAffinity(pod 親和性):以 pod 為目標,解決 pod 可以和哪些已存在的 pod 部署在同一個拓撲域中的問題
  • podAntiAffinity(pod 反親和性):以 pod 為目標,解決 pod 不能和哪些已存在 pod 部署在同一個拓撲域中的問題

關於親和性和反親和性使用場景的說明:

親和性:如果兩個應用頻繁交互,那就有必要利用親和性讓兩個應用盡可能的靠近,這樣可以減少因網絡通信而帶來的性能損耗,比如 web 應用和 mysql,要頻繁的從數據庫里查詢和新增數據,所以應該讓他們盡可能的在一起

反親和性:當應用采用多副本部署時,有必要采用反親和性讓各個應用實例打散分布在各個 node 上,這樣可以提高服務的高可用性,當一個服務器掛掉之后,其他的 pod 還可以提供服務

NodeAffinity

首先來看一下 NodeAffinity 的可配置項: 

pod.spec.affinity.nodeAffinity
  requiredDuringSchedulingIgnoredDuringExecution  # Node節點必須滿足指定的所有規則才可以,相當於硬限制
    nodeSelectorTerms  # 節點選擇列表
      matchFields   # 按節點字段列出的節點選擇器要求列表
      matchExpressions   # 按節點標簽列出的節點選擇器要求列表(推薦)
        key    #
        values #
        operat or # 關系符 支持Exists, DoesNotExist, In, NotIn, Gt, Lt
  preferredDuringSchedulingIgnoredDuringExecution # 優先調度到滿足指定的規則的 Node,相當於軟限制 (傾向)
    preference   # 一個節點選擇器項,與相應的權重相關聯
      matchFields  # 按節點字段列出的節點選擇器要求列表
      matchExpressions  # 按節點標簽列出的節點選擇器要求列表(推薦)
        key    #
        values #
        operator # 關系符 支持In, NotIn, Exists, DoesNotExist, Gt, Lt
    weight # 傾向權重,在范圍1-100。

關系符的說明

- matchExpressions:
  - key: nodeenv              # 匹配存在標簽的 key 為 nodeenv 的節點
    operator: Exists
  - key: nodeenv              # 匹配標簽的 key 為 nodeenv,且 value 是 "xxx" 或 "yyy" 的節點
    operator: In
    values: ["xxx","yyy"]
  - key: nodeenv              # 匹配標簽的 key 為 nodeenv,且 value 大於 "xxx" 的節點
    operator: Gt
    values: "xxx"

接下來首先演示一下 requiredDuringSchedulingIgnoredDuringExecution

創建 pod-nodeaffinity-required.yaml,內容如下

apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeaffinity-required
  namespace: zouzou
spec:
  containers:
  - name: nginx
    image: nginx:1.14
  affinity:  # 親和性設置
    nodeAffinity: # 設置 node 親和性
      requiredDuringSchedulingIgnoredDuringExecution: # 硬限制,沒有滿足就會失敗
        nodeSelectorTerms: # node 選擇器,可以有多個
        - matchExpressions: # 匹配標簽
          - key: nodeenv # 標簽的 key 要為 nodeenv
            operator: In  # 操作符,在里面
            values: ["xxx","yyy"] # 值在["xxx","yyy"]中的標簽

創建 pod

#  創建 pod
kubectl create -f pod-nodeaffinity-required.yaml

查看 pod 和 pod 的 event

# 查看 pod ,發現 pod 沒有調度到節點上,因為 nodeenv 的值沒有 xxx 或者 yyy,而且是硬限制
[root@dce-10-6-215-215 tmp]# kubectl get pod pod-nodeaffinity-required -n zouzou -o wide
NAME                        READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED NODE   READINESS GATES
pod-nodeaffinity-required   0/1     Pending   0          81s   <none>   <none>   <none>           <none>

# 從 event 可以看到,調度失敗,有三個 node 節點,但是沒有滿足標簽選擇器的 node
[root@dce-10-6-215-215 tmp]# kubectl describe pod pod-nodeaffinity-required -n zouzou
Name:         pod-nodeaffinity-required
Namespace:    zouzou
Priority:     0
Node:         <none>
Labels:       <none>
......
Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  104s  default-scheduler  0/3 nodes are available: 3 node(s) didn't match node selector.
  Warning  FailedScheduling  30s   default-scheduler  0/3 nodes are available: 3 node(s) didn't match node selector.

從上面我們可以看出,硬限制當沒有匹配的標簽時,會調度失敗。因為我們兩個 node 節點,只有 nodeenv=pro 和 nodeenv=test 的節點,沒有 nodeenv=xxx 或者 nodeenv=yyy 的節點

接下來,我們刪除 pod,把 yyy 改為 pro,因為 nodeenv=pro 是存在的

# 刪除 pod
kubectl delete -f pod-nodeaffinity-required.yaml

修改后在創建 pod

# 創建 pod
kubectl create -f pod-nodeaffinity-required.yaml

查看 pod

# 可以看到,pod 分配給了 dce-10-6-215-190 的節點上,並成功運行了
[root@dce-10-6-215-215 tmp]# kubectl get pod pod-nodeaffinity-required -n zouzou -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-nodeaffinity-required 1/1 Running 0 17s 172.29.190.143 dce-10-6-215-190 <none> <none> # 從 event 里,也可以看出來,是成功調度的 [root@dce-10-6-215-215 tmp]# kubectl describe pod pod-nodeaffinity-required -n zouzou Name: pod-nodeaffinity-required Namespace: zouzou...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 24s default-scheduler Successfully assigned zouzou/pod-nodeaffinity-required to dce-10-6-215-190 Normal Pulled 21s kubelet Container image "nginx:1.14" already present on machine Normal Created 21s kubelet Created container nginx Normal Started 20s kubelet Started container nginx

接下來再演示一下 requiredDuringSchedulingIgnoredDuringExecution

創建 pod-nodeaffinity-preferred.yaml,內容如下

apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeaffinity-preferred
  namespace: zouzou
spec:
  containers:
  - name: nginx
    image: nginx:1.14
  affinity:  # 親和性設置
    nodeAffinity: # 設置 node 親和性
      preferredDuringSchedulingIgnoredDuringExecution: # 軟限制,沒有匹配的標簽也會分配給某個 node
      - weight: 1 # 權重
        preference: # 一個節點選擇器項,與相應的權重相關聯
          matchExpressions:  # 匹配標簽
          - key: nodeenv # 標簽的 key 要為 nodeenv
            operator: In  # 操作符,在里面
            values: ["xxx","yyy"] # 匹配 env 的值在["xxx","yyy"]中的標簽(當前環境沒有)

創建 pod

kubectl create -f pod-nodeaffinity-preferred.yaml

查看 pod 和 pod event

# 可以看到,成功分配給了 dce-10-6-215-200 的節點上
[root@dce-10-6-215-215 tmp]# kubectl get pod pod-nodeaffinity-preferred -n zouzou -o wide
NAME                         READY   STATUS    RESTARTS   AGE   IP              NODE               NOMINATED NODE   READINESS GATES
pod-nodeaffinity-preferred   1/1     Running   0          53s   172.29.34.238   dce-10-6-215-200   <none>           <none>

# 從 event 中也可以看出,pod 是調度成功的
[root@dce-10-6-215-215 tmp]# kubectl describe pod pod-nodeaffinity-preferred -n zouzou
Name:         pod-nodeaffinity-preferred
Namespace:    zouzou
Priority:     0
Node:         dce-10-6-215-200/10.6.215.200
Start Time:   Sat, 16 Apr 2022 11:45:15 +0800
......
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  66s   default-scheduler  Successfully assigned zouzou/pod-nodeaffinity-preferred to dce-10-6-215-200
  Normal  Pulled     63s   kubelet            Container image "nginx:1.14" already present on machine
  Normal  Created    63s   kubelet            Created container nginx
  Normal  Started    62s   kubelet            Started container ngin

從上面的結果可以看出,軟限制,當沒有匹配到對應的標簽時,也不會調度失敗,會根據算法分配給合適的節點

NodeAffinity規則設置的注意事項:

  • 如果同時定義了 nodeSelector 和 nodeAffinity,那么必須兩個條件都得到滿足,Pod 才能運行在指定的 Node 上
  • 如果 nodeAffinity 指定了多個 nodeSelectorTerms,那么只需要其中一個能夠匹配成功即可
  • 如果一個 nodeSelectorTerms 中有多個 matchExpressions ,則一個節點必須滿足所有的才能匹配成功
  • 如果一個 pod 所在的 Node 在 Pod 運行期間其標簽發生了改變,不再符合該 Pod 的節點親和性需求,則系統將忽略此變化
PodAffinity

PodAffinity 主要實現以運行的 Pod 為參照,實現讓新創建的 Pod 跟參照 pod 在一個區域的功能。

首先來看一下 PodAffinity 的可配置項: 

pod.spec.affinity.podAffinity
  requiredDuringSchedulingIgnoredDuringExecution  # 硬限制
    namespaces       # 指定參照 pod 的 namespace
    topologyKey      # 指定調度作用域
    labelSelector    # 標簽選擇器
      matchExpressions  # 按節點標簽列出的節點選擇器要求列表(推薦)
        key    #
        values #
        operator # 關系符 支持 In, NotIn, Exists, DoesNotExist.
      matchLabels     # 指多個 matchExpressions 映射的內容
  preferredDuringSchedulingIgnoredDuringExecution # 軟限制
    podAffinityTerm   # 選項
      namespaces      
      topologyKey
      labelSelector
        matchExpressions  
          key     #
          values #
          operator
        matchLabels 
    weight # 傾向權重,在范圍 1-100

topologyKey 用於指定調度時作用域

  • 如果指定為 kubernetes.io/hostname,那就是以 Node 節點為區分范圍
  • 如果指定為 beta.kubernetes.io/os,則以 Node 節點的操作系統類型來區分

接下來,演示下 requiredDuringSchedulingIgnoredDuringExecution(硬限制)

首先創建一個參照 Pod,pod-podaffinity-target.yaml,內容如下

apiVersion: v1
kind: Pod
metadata:
  name: pod-podaffinity-target
  namespace: zouzou
  labels:
    podenv: pro # 給 pod 設置標簽
spec:
  containers:
  - name: nginx
    image: nginx:1.14
  nodeName: dce-10-6-215-200 # 將目標 pod 明確指定到 dce-10-6-215-200 上

創建 pod

kubectl apply -f pod-podaffinity-target.yaml

接下來創建 創建 pod-podaffinity-required.yaml,內容如下:

apiVersion: v1
kind: Pod
metadata:
  name: pod-podaffinity-required
  namespace: zouzou
spec:
  containers:
  - name: nginx
    image: nginx:1.14
  affinity:  # 親和性設置
    podAffinity: # 設置pod親和性
      requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
      - labelSelector:
          matchExpressions: # 匹配env的值在["xxx","yyy"]中的標簽
          - key: podenv # 對應的是 pod 的標簽,不是 node 的,上面創建參照 pod 的時候創建了一個 podenv=pro 的標簽
            operator: In
            values: ["xxx","yyy"] # 不存在 podenv=xxx 或者 podenv=yyy
        topologyKey: kubernetes.io/hostname # 以 node 節點為區分范圍

上面配置表達的意思是:新 Pod 必須要與擁有標簽 podenv=xxx 或者 podenv=yyy 的 pod 在同一 Node 上,顯然現在沒有這樣 pod,接下來,運行測試一下

# 創建 pod
kubectl create -f pod-podaffinity-required.yaml

查看 pod 和 pod event

# 查看 pod,發現 pod 未運行,也沒有分配到節點上
[root@dce-10-6-215-215 tmp]# kubectl get pods pod-podaffinity-required -n zouzou -o wide
NAME                       READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED NODE   READINESS GATES
pod-podaffinity-required   0/1     Pending   0          30s   <none>   <none>   <none>           <none>

# 查看 event,底下提示有三個節點,一個節點有污點(master),兩個節點(node)不滿足標簽規則
[root@dce-10-6-215-215 tmp]#
[root@dce-10-6-215-215 tmp]# kubectl describe pod pod-nodeaffinity-preferred -n zouzou
Name:         pod-nodeaffinity-preferred
Namespace:    zouzou
Priority:     0
Node:         dce-10-6-215-200/10.6.215.200
Start Time:   Sat, 16 Apr 2022 11:45:15 +0800
......
Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  51s   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 affinity rules, 2 node(s) didn't match pod affinity/anti-affinity.

接下來修改 values: ["xxx","yyy"]----->values:["pro","yyy"]

意思是:新 Pod 必須要與擁有標簽 podenv=xxx 或者 podenv=yyy 的 pod 在同一 Node 上

修改完之后重新創建 pod

# 創建 pod
kubectl create -f pod-podaffinity-required.yaml

查看 pod,是正常運行的

# 查看 pod,pod 是正常運行的
[root@dce-10-6-215-215 tmp]# kubectl get pods pod-podaffinity-required -n zouzou -o wide
NAME                       READY   STATUS    RESTARTS   AGE   IP              NODE               NOMINATED NODE   READINESS GATES
pod-podaffinity-required   1/1     Running   0          36s   172.29.34.240   dce-10-6-215-200   <none>           <none>

# 查看 event,正常
[root@dce-10-6-215-215 tmp]# kubectl describe pods pod-podaffinity-required -n zouzou
Name:         pod-podaffinity-required
Namespace:    zouzou
Priority:     0
Node:         dce-10-6-215-200/10.6.215.200
Start Time:   Sat, 16 Apr 2022 12:19:04 +0800
......
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  41s   default-scheduler  Successfully assigned zouzou/pod-podaffinity-required to dce-10-6-215-200
  Normal  Pulled     39s   kubelet            Container image "nginx:1.14" already present on machine
  Normal  Created    38s   kubelet            Created container nginx
  Normal  Started    38s   kubelet            Started container nginx

可以看到,我們的參考 pod 在 dce-10-6-215-200節點上,配置了 pod 親和性之后,也在 dce-10-6-215-200 節點上

關於 PodAffinity 的 preferredDuringSchedulingIgnoredDuringExecution,這里不再演示。

PodAntiAffinity

PodAntiAffinity 主要實現以運行的 Pod 為參照,讓新創建的 Pod 跟參照 pod 不在一個區域中的功能。

它的配置方式和選項跟 PodAffinty 是一樣的,這里不再做詳細解釋,直接做一個測試案例。

繼續使用上個案例中目標 pod,pod-podaffinity-target.yaml

創建 pod-podantiaffinity-required.yaml,內容如下:

apiVersion: v1
kind: Pod
metadata:
  name: pod-podantiaffinity-required
  namespace: zouzou
spec:
  containers:
  - name: nginx
    image: nginx:1.14
  affinity:  # 親和性設置
    podAntiAffinity: #設置 pod 反親和性
      requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
      - labelSelector:
          matchExpressions: # 匹配env的值在["xxx","yyy"]中的標簽
          - key: podenv # 對應的是 pod 的標簽,不是 node 的,上面創建參照 pod 的時候創建了一個 podenv=pro 的標簽
            operator: In
            values: ["pro"] # 反親和性,不在和 pod 的標簽 podenv=pro 的節點上
        topologyKey: kubernetes.io/hostname # 

創建 pod

 kubectl create -f pod-podantiaffinity-required.yaml

可以看到,因為我們設置了反親和性,創建的 pod 就沒有和 podenv=pro 標簽的 pod 在一台 node 機器上

污點和容忍

污點(Taints)

前面的調度方式都是站在 pod 的角度上,通過在 pod 上添加屬性,來確定 pod 是否要調度到指定的 node 上,其實我們也可以站在 node 的角度上,通過在 node 上添加污點屬性,來決定是否允許 pod 調度過來

node 被設置上污點之后就和 pod 之間存在了一種互斥的關系,進而拒絕 pod 調度進來,甚至可以將已經存在的 pod 驅逐出去

污點的格式為:key=value:effect,key 和 value 是污點的標簽,effect 描述污點的作用,支持如下三個選項

  • PreferNoSchedule:kubernetes 將盡量避免把 Pod 調度到具有該污點的 Node上,除非沒有其他節點可調度
  • NoSchedule:kubernetes 將不會把 Pod 調度到具有該污點的 Node 上,但不會影響當前 Node 上已存在的 Pod
  • NoExecute:kubernetes 將不會把 Pod 調度到具有該污點的 Node 上,同時也會將 Node 上已存在的 Pod 驅離

使用 kubectl 設置和去除污點的命令示例如下:

# 設置污點
kubectl taint nodes node1 key=value:effect

# 去除污點
kubectl taint nodes node1 key:effect-

# 去除所有污點
kubectl taint nodes node1 key-

接下來,演示下污點的效果

  1. 准備一個節點,為了演示效果更加明顯,只需要一個 master 和一個 worker 即可
  2. 為 node 節點設置一個污點:tag=hihi:PreferNoSchedule,然后創建 pod1
  3. 修改 node 節點的污點:tag=hihi:NoSchedule,然后創建 pod2
  4. 修改 node 節點的污點:tag=NoExecute,然后創建 pod3
# 為 node 設置污點(PreferNoSchedule)
kubectl taint node dce-10-6-215-190 tag=hihi:PreferNoSchedule

查看節點 dce-10-6-215-190 的污點,使用下面命令

# 查看 dce-10-6-215-190 節點的污點
kubectl describe node dce-10-6-215-190

創建 pod

# 創建 pod,名稱叫 demo1
[root@dce-10-6-215-215 tmp]# kubectl run demo1 --image=nginx:1.14 -n zouzou
[root@dce-10-6-215-215 tmp# kubectl get pods -n zouzou -o wide
NAME                      READY   STATUS    RESTARTS   AGE     IP           NODE   
demo1-7665f7fd85-574h4   1/1     Running   0          2m24s   10.244.1.59   dce-10-6-215-190

從結果可以看到,我們創建的 pod 運行在了 dce-10-6-215-190 的節點上,雖然 dce-10-6-215-190 我們添加了污點,但污點是 tag=hihi:PreferNoSchedule,也就是盡量避免不添加到有污點的節點上,但只有這一個 worker 節點,所以也就調度到了 dce-10-6-215-190 的節點上

刪除污點,創建一個新污點,不能修改

# 刪除污點 tag:PreferNoSchedule-
kubectl taint node dce-10-6-215-190 tag:PreferNoSchedule-

刪除后,在去查看已經沒有了

# 查看污點
kubectl describe node dce-10-6-215-190

設置 NoSchedule 污點

# 給 dce-10-6-215-190 節點設置污點 tag=hihi:NoSchedule
 kubectl taint node dce-10-6-215-190 tag=hihi:NoSchedule

查看污點

在來創建一個新 pod 查看是否可以成功創建

# 創建 pod,名稱為 demo2
[root@dce-10-6-215-215 tmp]# kubectl run demo2 --image=nginx:1.14 -n zouzou


[root@dce-10-6-215-215 tmp]# kubectl get pods -n zouzou -o wide
NAME                      READY   STATUS    RESTARTS   AGE     IP            NODE
demo1-7665f7fd85-574h4   1/1     Running   0          2m24s   10.244.1.59   dce-10-6-215-190
demo2-544694789-6zmlf    0/1     Pending   0          21s     <none>        <none>  

從上面可以看出,我們新創建的 pod demo2 沒有創建成功,但 demo1 還是正常運行的,因為我們創建的污點是 tag=hihi:NoSchedule(kubernetes 將不會把 Pod 調度到具有該污點的 Node 上,但不會影響當前 Node 上已存在的 Pod)

刪除污點,創建一個新污點,不能修改

# 刪除污點
kubectl taint node dce-10-6-215-190 tag:NoSchedule-

刪除后,在去查看已經沒有了

# 查看污點
kubectl describe node dce-10-6-215-190

設置 NoExecute 污點

# 給 dce-10-6-215-190 節點設置污點 tag=hihi:NoExecute
kubectl taint node dce-10-6-215-190 tag=hihi:NoExecute

查看污點,污點已經設置成功了

在來創建一個新 pod 查看是否可以成功創建

# 創建 pod,名稱叫 demo3
[root@dce-10-6-215-215 tmp]# kubectl run demo3 --image=nginx:1.14 -n zouzou
[root@dce-10-6-215-215 tmp]# kubectl get pods -n zouzou -o wide
NAME                      READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED 
demo1-7665f7fd85-htkmp   0/1     Pending   0          35s   <none>   <none>   <none>    
demo2-544694789-bn7wb    0/1     Pending   0          35s   <none>   <none>   <none>     
demo3-6d78dbd749-tktkq   0/1     Pending   0          6s    <none>   <none>   <none>    

從上面結果可以看出,pod demo3 沒有創建成功,而之前成功的 pod demo1 也被移除了,這是因為我們設置的污點是 tag=hihi:NoExecute(不會把 Pod 調度到具有該污點的 Node 上,同時也會將 Node 上已存在的 Pod 驅離)

使用 kubeadm 搭建的集群,默認就會給 master 節點添加一個污點標記,所以 pod 就不會調度到 master 節點上

容忍(Toleration)

上面介紹了污點的作用,我們可以在 node 上添加污點用於拒絕 pod 調度上來,但是如果就是想將一個 pod 調度到一個有污點的 node 上去,這時候應該怎么做呢?這就要使用到容忍

污點就是拒絕,容忍就是忽略,Node 通過污點拒絕 pod 調度上去,Pod 通過容忍忽略拒絕

下面先通過一個案例看下效果:

  • 上面,已經在 dce-10-6-215-190  節點上打上了 NoExecute 的污點,此時 pod 是調度不上去的
  • 可以通過給 pod 添加容忍,然后將其調度上去

創建 pod-toleration.yaml 內容如下,先創建個不添加容忍的,創建 pod 查看效果,在創建個添加了容忍的,創建 pod,查看效果

apiVersion: v1
kind: Pod
metadata:
  name: pod-toleration
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  tolerations:      # 添加容忍,下面的意思就是:tag=hihi:NoExecute
  - key: "tag"        # 要容忍的污點的key
    operator: "Equal" # 操作符,Equal 為等於
    value: "hihi"    # 容忍的污點的value
    effect: "NoExecute"   # 添加容忍的規則,這里必須和標記的污點規則相同
# 添加容忍之前的pod
[root@dce-10-6-215-215 tmp]# kubectl get pods -n zouzou -o wide
NAME             READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED 
pod-toleration   0/1     Pending   0          3s    <none>   <none>   <none>           

# 添加容忍之后的pod
[root@dce-10-6-215-215 tmp]# kubectl get pods -n zouzou -o wide
NAME             READY   STATUS    RESTARTS   AGE   IP            NODE    NOMINATED
pod-toleration   1/1     Running   0          3s    10.244.1.62   dce-10-6-215-190   <none>        

可以看到,添加了容忍之后,節點有 node,也可以創建成功

下面看一下容忍的詳細配置

[root@dce-10-6-215-215 tmp]# kubectl explain pod.spec.tolerations
......
FIELDS:
   key       # 對應着要容忍的污點的鍵,空意味着匹配所有的鍵
   value     # 對應着要容忍的污點的值
   operator  # key-value 的運算符,支持 Equal 和 Exists(默認),Exists 是存在的意思,只判斷 key,不需要寫 value,只要 key 存在就行
   effect    # 對應污點的effect,空意味着匹配所有影響
   tolerationSeconds   # 容忍時間, 當 effect 為 NoExecute 時生效,表示之前在你 node 節點上的 pod 的停留時間,超過了這個時間,node 就會將 pod 移除

刪除多個污點

上面我們 dce-10-6-215-190 已經有一個污點了,接下來在添加一個污點

 上面節點上已經有兩個污點了,可以使用下面命令刪除相同 key 的污點

# 刪除相同 key 的污點,這里刪除 key=tag 的污點
kubectl taint nodes dce-10-6-215-190 tag-

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM