Kubernetes之Taint 和 Toleration


  參考:https://kubernetes.io/zh/docs/concepts/configuration/taint-and-toleration/

  Taint 和 Toleration

  節點親和性(詳見這里),是 pod 的一種屬性(偏好或硬性要求),它使 pod 被吸引到一類特定的節點。Taint 則相反,它使 節點 能夠 排斥 一類特定的 pod。

Taint 和 toleration 相互配合,可以用來避免 pod 被分配到不合適的節點上。每個節點上都可以應用一個或多個 taint ,這表示對於那些不能容忍這些 taint 的 pod,是不會被該節點接受的。如果將 toleration 應用於 pod 上,則表示這些 pod 可以(但不要求)被調度到具有匹配 taint 的節點上。

  概念

  可以使用命令kubectl taint給節點增加一個taint。比如

kubectl taint nodes node1 key=value:NoSchedule

   給節點 node1 增加一個 taint,它的 key 是 key,value 是 value,effect 是 NoSchedule。這表示只有擁有和這個 taint 相匹配的 toleration 的 pod 才能夠被分配到 node1 這個節點。您可以在 PodSpec 中定義 pod 的 toleration。下面兩個 toleration 均與上面例子中使用 kubectl taint 命令創建的 taint 相匹配,因此如果一個 pod 擁有其中的任何一個 toleration 都能夠被分配到 node1 :

  想刪除上述命令添加的 taint ,您可以運行:

kubectl taint nodes node1 key:NoSchedule-

   設置一個taint

#給node節點設置taint key為key value為value effec值為NoSchedule代表永不調度
kubectl taint node 192.168.1.65 key=value:NoSchedule

  查看設置的污點

kubectl describe node 192.168.1.65

   PS:設置了taint的節點192.168.1.65因為effec的值為NoSchedule即永不調度除非是在Pod內設置了對應的tolerations

  測試一下設置的taint是否生效

  創建一個Deployment副本數為3

kubectl run nginx-deployment --image=nginx --replicas=3 

   查看Pod分配的node節點,因為node192.168.1.65設置了污點所以3個副本就分配到node192.168.1.66上了

# kubectl get pod -o wide
NAME                                    READY   STATUS    RESTARTS   AGE   IP            NODE           NOMINATED NODE   READINESS GATES
nginx-deployment-6c94df7599-6jr48       1/1     Running   0          83s   172.17.71.4   192.168.1.66   <none>           <none>
nginx-deployment-6c94df7599-7mkp2       1/1     Running   0          83s   172.17.71.9   192.168.1.66   <none>           <none>
nginx-deployment-6c94df7599-p86d6       1/1     Running   0          83s   172.17.71.3   192.168.1.66   <none>           <none>

   可以在PodSpec中為容器設定容忍標簽。以下兩個容忍標簽都與上面的 kubectl taint 創建的污點“匹配”, 因此具有任一容忍標簽的Pod都可以將其調度到“ node1”上:

tolerations:
- key: "key"
  operator: "Equal"
  value: "value"
  effect: "NoSchedule"

 

tolerations:
- key: "key"
  operator: "Exists"
  effect: "NoSchedule"

   測試創建一個Deployment

# cat nginx-deployment.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
      tolerations:
      - key: "key"
        operator: "Equal"
        value: "value"
        effect: "NoSchedule"

   應用

# kubectl apply -f nginx-deployment.yaml 
deployment.apps/nginx-deployment created

    查看Pod分配的node節點可以發現有Pod分配到node192.168.1.65上了

# kubectl get pod -o wide 
NAME                                    READY   STATUS    RESTARTS   AGE   IP            NODE           NOMINATED NODE   READINESS GATES
nginx-deployment-6cb65b4b8d-gkm4b       1/1     Running   0          42s   172.17.54.5   192.168.1.65   <none>           <none>
nginx-deployment-6cb65b4b8d-v52ll       1/1     Running   0          42s   172.17.54.4   192.168.1.65   <none>           <none>
nginx-deployment-6cb65b4b8d-zbg9m       1/1     Running   0          42s   172.17.71.3   192.168.1.66   <none>           <none>

   PS:設置tolerations代表對應Pod可以分配到設置了taint的node上,並不代表一定要分配到該node上,所以其他node也可以正常分配到Pod,需要設置多個副本才能看見分配效果。

  一個 toleration 和一個 taint 相“匹配”是指它們有一樣的 key 和 effect ,並且:

  • 如果 operator 是 Exists (此時 toleration 不能指定 value
  • 如果 operator 是 Equal ,則它們的 value 應該相等

  注意:

  存在兩種特殊情況

  如果一個 toleration 的 key 為空且 operator 為 Exists ,表示這個 toleration 與任意的 key 、 value 和 effect 都匹配,即這個 toleration 能容忍任意 taint。

tolerations:
- operator: "Exists"

 

   如果一個 toleration 的 effect 為空,則 key 值與之相同的相匹配 taint 的 effect 可以是任意值。

tolerations:
- key: "key"
operator: "Exists"

   上述例子使用到的 effect 的一個值 NoSchedule,您也可以使用另外一個值 PreferNoSchedule。這是“優化”或“軟”版本的 NoSchedule ——系統會 盡量 避免將 pod 調度到存在其不能容忍 taint 的節點上,但這不是強制的。effect 的值還可以設置為 NoExecute代表調度到該節點的Pod會立即驅逐。

  可以給一個節點添加多個 taint ,也可以給一個 pod 添加多個 toleration。Kubernetes 處理多個 taint 和 toleration 的過程就像一個過濾器:從一個節點的所有 taint 開始遍歷,過濾掉那些 pod 中存在與之相匹配的 toleration 的 taint。余下未被過濾的 taint 的 effect 值決定了 pod 是否會被分配到該節點,特別是以下情況:

  • 如果未被過濾的 taint 中存在一個以上 effect 值為 NoSchedule 的 taint,則 Kubernetes 不會將 pod 分配到該節點。
  • 如果未被過濾的 taint 中不存在 effect 值為 NoSchedule 的 taint,但是存在 effect 值為 PreferNoSchedule 的 taint,則 Kubernetes 會 嘗試 將 pod 分配到該節點。
  • 如果未被過濾的 taint 中存在一個以上 effect 值為 NoExecute 的 taint,則 Kubernetes 不會將 pod 分配到該節點(如果 pod 還未在節點上運行),或者將 pod 從該節點驅逐(如果 pod 已經在節點上運行)。

  例如,假設您給一個節點添加了如下的 taint

kubectl taint nodes node1 key1=value1:NoSchedule
kubectl taint nodes node1 key1=value1:NoExecute
kubectl taint nodes node1 key2=value2:NoSchedule

   然后存在一個 pod,它有兩個 toleration

tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoSchedule"
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoExecute"

   在這個例子中,上述 pod 不會被分配到上述節點,因為其沒有 toleration 和第三個 taint 相匹配。但是如果在給節點添加 上述 taint 之前,該 pod 已經在上述節點運行,那么它還可以繼續運行在該節點上,因為第三個 taint 是三個 taint 中唯一不能被這個 pod 容忍的。

  演示

  首先個node 192.168.1.65添加taint

kubectl taint node 192.168.1.65 key1=value1:NoSchedule
kubectl taint node 192.168.1.65 key1=value1:NoExecute
kubectl taint node 192.168.1.65 key2=value2:NoSchedule

   查看添加的taint

kubectl describe node 192.168.1.65

 

 

 

   設置一個Deployment

# cat nginx-deployment.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
      tolerations:
      - key: "key1"
        operator: "Equal"
        value: "value1"
        effect: "NoSchedule"
      - key: "key1"
        operator: "Equal"
        value: "value1"
        effect: "NoExecute"

   創建Deployment

kubectl apply -f nginx-deployment.yaml

   查看分配Pod的節點沒有分配到node192.168.1.65上

# kubectl get pod -o wide 
NAME                                    READY   STATUS    RESTARTS   AGE   IP            NODE           NOMINATED NODE   READINESS GATES
nginx-deployment-94d96bf84-lpn6c        1/1     Running   0          77s   172.17.71.9   192.168.1.66   <none>           <none>
nginx-deployment-94d96bf84-mkmkj        1/1     Running   0          77s   172.17.71.4   192.168.1.66   <none>           <none>
nginx-deployment-94d96bf84-wjssg        1/1     Running   0          77s   172.17.71.3   192.168.1.66   <none>           <none>

   分析:

  首先過濾掉那些與pod中存在相匹配的toleration和taint污點key1=value1:NoSchedule和key1=value1:NoExecute過濾掉了。余下未被過濾的taint key2=value2:NoSchedule的effcet值為NoSchedule不調度,所以創建的Pod不會分配到node 192.168.1.65上

  測試pod已運行后再添加taint的pod是否驅逐

  刪除taint創建Deployment后查看pod位置

# kubectl get pod -o wide
NAME                                    READY   STATUS    RESTARTS   AGE   IP            NODE           NOMINATED NODE   READINESS GATES
nginx-deployment-7cd7cc8786-dkk45       1/1     Running   0          54s   172.17.71.3   192.168.1.66   <none>           <none>
nginx-deployment-7cd7cc8786-qkl6p       1/1     Running   0          54s   172.17.54.3   192.168.1.65   <none>           <none>
nginx-deployment-7cd7cc8786-zwz77       1/1     Running   0          54s   172.17.54.2   192.168.1.65   <none>           <none>

   添加taint以后pod所在node位置未發生變化

kubectl taint node 192.168.1.65 key1=value1:NoSchedule
kubectl taint node 192.168.1.65 key1=value1:NoExecute
kubectl taint node 192.168.1.65 key2=value2:NoSchedule

  刪除Deployment重新創建后才會重新調度

  PS:如果新添加的taint的effect值是NoSchedule是代表不調度但是需要再重新調度的時候生效不會立即驅逐

  如果新添加的taint的effect值是NoNoExecute代表立即驅逐則會立即把node192.168.1.65節點上的Pod調度到其他節點

  通常情況下,如果給一個節點添加了一個 effect 值為 NoExecute 的 taint,則任何不能忍受這個 taint 的 pod 都會馬上被驅逐,任何可以忍受這個 taint 的 pod 都不會被驅逐。但是,如果 pod 存在一個 effect 值為 NoExecute 的 toleration 指定了可選屬性 tolerationSeconds 的值,則表示在給節點添加了上述 taint 之后,pod 還能繼續在節點上運行的時間。例如,

tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoExecute"
  tolerationSeconds: 3600

   這表示如果這個 pod 正在運行,然后一個匹配的 taint 被添加到其所在的節點,那么 pod 還將繼續在節點上運行 3600 秒,然后被驅逐。如果在此之前上述 taint 被刪除了,則 pod 不會被驅逐。

  使用例子  

  通過 taint 和 toleration ,可以靈活地讓 pod 避開 某些節點或者將 pod 從某些節點驅逐。下面是幾個使用例子:

  專用節點

  如果您想將某些節點專門分配給特定的一組用戶使用,您可以給這些節點添加一個 taint(即, kubectl taint nodes nodename dedicated=groupName:NoSchedule),然后給這組用戶的 pod 添加一個相對應的 toleration(通過編寫一個自定義的admission controller,很容易就能做到)。擁有上述 toleration 的 pod 就能夠被分配到上述專用節點,同時也能夠被分配到集群中的其它節點。如果您希望這些 pod 只能被分配到上述專用節點,那么您還需要給這些專用節點另外添加一個和上述 taint 類似的 label (例如:dedicated=groupName),同時 還要在上述 admission controller 中給 pod 增加節點親和性要求上述 pod 只能被分配到添加了 dedicated=groupName 標簽的節點上。

  配備了特殊硬件的節點

  在部分節點配備了特殊硬件(比如 GPU)的集群中,我們希望不需要這類硬件的 pod 不要被分配到這些特殊節點,以便為后繼需要這類硬件的 pod 保留資源。要達到這個目的,可以先給配備了特殊硬件的節點添加 taint(例如 kubectl taint nodes nodename special=true:NoSchedule or kubectl taint nodes nodename special=true:PreferNoSchedule),然后給使用了這類特殊硬件的 pod 添加一個相匹配的 toleration。和專用節點的例子類似,添加這個 toleration 的最簡單的方法是使用自定義 admission controller。比如,我們推薦使用 Extended Resources 來表示特殊硬件,給配置了特殊硬件的節點添加 taint 時包含 extended resource 名稱,然后運行一個 ExtendedResourceToleration admission controller。此時,因為節點已經被 taint 了,沒有對應 toleration 的 Pod 會被調度到這些節點。但當你創建一個使用了 extended resource 的 Pod 時,ExtendedResourceToleration admission controller 會自動給 Pod 加上正確的 toleration ,這樣 Pod 就會被自動調度到這些配置了特殊硬件件的節點上。這樣就能夠確保這些配置了特殊硬件的節點專門用於運行 需要使用這些硬件的 Pod,並且您無需手動給這些 Pod 添加 toleration。

  基於 taint 的驅逐 (beta 特性)

  基於 taint 的驅逐前文我們提到過 taint 的 effect 值 NoExecute ,它會影響已經在節點上運行的 pod

  • 如果 pod 不能忍受effect 值為 NoExecute 的 taint,那么 pod 將馬上被驅逐
  • 如果 pod 能夠忍受effect 值為 NoExecute 的 taint,但是在 toleration 定義中沒有指定 tolerationSeconds,則 pod 還會一直在這個節點上運行。
  • 如果 pod 能夠忍受effect 值為 NoExecute 的 taint,而且指定了 tolerationSeconds,則 pod 還能在這個節點上繼續運行這個指定的時間長度。此外,Kubernetes 1.6 已經支持(alpha階段)節點問題的表示。換句話說,當某種條件為真時,node controller會自動給節點添加一個 taint。當前內置的 taint 包括:
  • node.kubernetes.io/not-ready:節點未准備好。這相當於節點狀態 Ready 的值為 “False“。
  • node.kubernetes.io/unreachable:node controller 訪問不到節點. 這相當於節點狀態 Ready 的值為 “Unknown“。
  • node.kubernetes.io/out-of-disk:節點磁盤耗盡。
  • node.kubernetes.io/memory-pressure:節點存在內存壓力。
  • node.kubernetes.io/disk-pressure:節點存在磁盤壓力。
  • node.kubernetes.io/network-unavailable:節點網絡不可用。
  • node.kubernetes.io/unschedulable: 節點不可調度。
  • node.cloudprovider.kubernetes.io/uninitialized:如果 kubelet 啟動時指定了一個 “外部” cloud provider,它將給當前節點添加一個 taint 將其標志為不可用。在 cloud-controller-manager 的一個 controller 初始化這個節點后,kubelet 將刪除這個 taint。

  在版本1.13中,TaintBasedEvictions 功能已升級為Beta,並且默認啟用,因此污點會自動給節點添加這類 taint,上述基於節點狀態 Ready 對 pod 進行驅逐的邏輯會被禁用。

  使用這個 beta 功能特性,結合 tolerationSeconds ,pod 就可以指定當節點出現一個或全部上述問題時還將在這個節點上運行多長的時間。

比如,一個使用了很多本地狀態的應用程序在網絡斷開時,仍然希望停留在當前節點上運行一段較長的時間,願意等待網絡恢復以避免被驅逐。在這種情況下,pod 的 toleration 可能是下面這樣的:

tolerations:
- key: "node.kubernetes.io/unreachable"
  operator: "Exists"
  effect: "NoExecute"
  tolerationSeconds: 6000

   注意,Kubernetes 會自動給 pod 添加一個 key 為 node.kubernetes.io/not-ready 的 toleration 並配置 tolerationSeconds=300,除非用戶提供的 pod 配置中已經已存在了 key 為 node.kubernetes.io/not-ready 的 toleration。同樣,Kubernetes 會給 pod 添加一個 key 為 node.kubernetes.io/unreachable 的 toleration 並配置 tolerationSeconds=300,除非用戶提供的 pod 配置中已經已存在了 key 為 node.kubernetes.io/unreachable 的 toleration。

這種自動添加 toleration 機制保證了在其中一種問題被檢測到時 pod 默認能夠繼續停留在當前節點運行 5 分鍾。這兩個默認 toleration 是由 DefaultTolerationSeconds admission controller添加的。

  DaemonSet 中的 pod 被創建時,針對以下 taint 自動添加的 NoExecute 的 toleration 將不會指定 tolerationSeconds

  • node.kubernetes.io/unreachable
  • node.kubernetes.io/not-ready

  這保證了出現上述問題時 DaemonSet 中的 pod 永遠不會被驅逐

  基於節點狀態添加 taint

  Node 生命周期控制器會自動創建與 Node 條件相對應的污點。 同樣,調度器不檢查節點條件,而是檢查節點污點。這確保了節點條件不會影響調度到節點上的內容。用戶可以通過添加適當的 Pod 容忍度來選擇忽略某些 Node 的問題(表示為 Node 的調度條件)。 注意,TaintNodesByCondition 只會污染具有 NoSchedule 設定的節點。 NoExecute 效應由 TaintBasedEviction 控制, TaintBasedEviction 是 Beta 版功能,自 Kubernetes 1.13 起默認啟用。

  • node.kubernetes.io/memory-pressure
  • node.kubernetes.io/disk-pressure
  • node.kubernetes.io/out-of-disk (只適合 critical pod)
  • node.kubernetes.io/unschedulable (1.10 或更高版本)
  • node.kubernetes.io/network-unavailable (只適合 host network)

  添加上述 toleration 確保了向后兼容,您也可以選擇自由的向 DaemonSet 添加 toleration。



 


免責聲明!

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



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