kubernetes排程之汙點(taint)和容忍(toleration)

周國通發表於2019-06-15

系列目錄

節點親和性(affinity),是節點的一種屬性,讓符合條件的pod親附於它(傾向於或者硬性要求).汙點是一種相反的行為,它會使pod抗拒此節點(即pod排程的時候不被排程到此節點)

汙點和容易結合在一起以確保pod不會被排程到不適合的節點上.當一個或者多個汙點新增到某個節點上,則意味著此節點不會接受任何不容忍這些汙點的pod.Tolerations作用於pod上,允許(但不是必須)pod被排程到有符合的汙點(taint)的節點上

概念

可以使用kubectl taint為一個節點(node)新增汙點(taint),例如:

kubectl taint nodes node1 key=value:NoSchedule

這樣就把鍵為key,值為value,效果為NoSchedule的汙點新增到了節點node1上.這樣除非pod有符合的容忍(toleration),否則不會被排程到此節點上

可以通過以下命令刪除剛新增的taint

kubectl taint nodes node1 key:NoSchedule-

你可以在建立pod的yml裡指定一個關於toleration的PodSpec,以下兩個容忍都會匹配前面建立的taint,因此它們中的任意一個建立的pod都會被排程到節點node1

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

只有pod的keyeffect都和某一個汙點的key與effect匹配,才被認為是匹配,並且要符合以下情形:

  • operatorExists(這種情況下value不應當指定)
  • operatorEqual 並且value相同

如果operator沒有指定,則預設是Equal

以下兩種情況為特殊情況:

1) 如果key是空(是指key沒有指定,而不是指key為空字串),operatorExists則匹配所有的key,valueeffect,也即匹配任何node,

tolerations:
- operator: "Exists"

2) 空的effect匹配所有effect

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

以上會匹配所有key為key的所有taint節點

前面的示例中使用了NoSchedule型別的effect.此外,也可以使用PreferNoSchedule型別的effect,這是一個優先選擇或者軟性版本的NoSchedule,排程系統會盡量避免排程不容忍這種汙點的pod到帶有此汙點的節點上,但是並不是硬性要求.第三種effect型別:NoExecute會在晚些時候講到

你可以為一個節點(node)新增多個汙點,也可以為一個pod新增多個容忍(toleration).kubernetes處理多個汙點(taint)或者多個容忍(toleration)類似於過濾器:起初包含所有汙點,然後忽略掉pod匹配的汙點,剩下不可被忽略的汙點決定此節點對pod的效果,特別地:

1) 如果至少有一個不可忽略的NoSchedule型別的效果(effect),kubernetes不會排程pod到此節點上來.

2) 如果沒有不可忽略的NoSchedule型別的效果(effect),但是至少有一個PreferNoSchedule型別的效果,則kubernetes會嘗試排程pod到此節點上

3) 如果至少有一個NoExecute型別的效果(effect),則此pod會被驅離此節點(當然,前提此pod在此節點上),並且如果pod不在此節點上,也不會被排程到此節點上

所謂驅離是指pod被從此節點上移除,排程到其它節點上

示例,假如你有一個以下型別的節點

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

和以下型別的pod

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

這種情況下,pod不會被排程到node1上,因為沒有容忍(toleration)來匹配第三個taint.但是如果它執行在此節點上,它仍然可以繼續執行在此節點上,因為它僅僅不匹配第三個taint.(而第三個taint的效果是NoSchedule,指示不要被排程到此節點)

通常情況下,一個效果型別為NoExecutetaint被新增到一個節點上後,所有不容忍此taint的pod會被馬上驅離,容忍的永遠不會被驅離.但是效果型別NoExecute可以指定一個tolerationSeconds欄位來指示當NoExecute效果型別的汙點被新增到節點以後,pod仍然可以繼續在在指定時間內留存在此節點上.

例如:

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

它意味著如果pod執行在一個可以容忍的節點上,則它可以繼續執行3600秒,然後被驅離,在此段時間內如果汙點被移除,則pod不會被驅離.

以上可以理解為有條件容忍,即便匹配也不能一直執行在此節點上,只能在符合條件的時段內執行在此節點上.

例項:

tainttoleration可以非常靈活地把指示pod不要排程到不合適的節點或者把已經存在的pod驅離節點,以下列舉出一些用例:

  • 專用節點 假如你想讓某些節點供特定的使用者專用,你可以為這些節點新增汙點,例如:(kubectl taint nodes nodename dedicated=groupName:NoSchedule),然後給專用這些節點的pod新增容忍(toleration),容忍節點汙點的pod被允許排程到節點上,當然也可以排程到叢集中的其它節點上(沒有taint的節點,有taint的必須容忍).如果你想要pod僅被排程到專用的節點,則需要新增標籤(使用前面講到過的親和屬性)

pod的親和性是以pod為中心的,而節點的汙點則是以節點為中心.想要使pod被排程到指定節點,需要親和屬性,想要節點排斥非專用pod,則需要使用taint,同時使用親和性和汙點可以保證專用節點被特定pod專用,特定pod僅使用專用節點

  • 配有特殊硬體的節點 在一個叢集中,有部分節點包含特殊硬體(例如特殊GPU),理想的情況是把讓不需要特殊硬體的pod不被排程到這些節點上以便為可能需要特殊硬體的節點留存空間,這種情況下就可以用給指定節點新增汙點(taint)的方法來實現效果.(例如kubectl taint nodes nodename special=true:NoSchedule or kubectl taint nodes nodename special=true:PreferNoSchedule),然後給需要使用特殊硬體的pod新增符合的容忍(toleration).

  • 基於taint的驅離策略(測試功能),當節點出現問題時,把不容忍的pod驅離.

基於taint的驅離策略

前面我們提到過NoExecute效果型別的taint,它將對已經存在於此節點上的pod產生效果:

  • 不容忍此taint的pod會被馬上驅離

  • 容忍此taint但是沒有指定tolerationSeconds的pod將會永遠執行在此節點

  • 容忍此taint但是包含tolerationSeconds屬性的節點將會在此節點上留存指定時間(雖然容忍,但是是有條件的,僅在一段時間內容忍)

第三點的言外之意即為即便容忍,但是超過容忍時間後仍然會被驅離

此外,kubernetes 1.6引入了對節點問題的展示.也就是說當滿足了特定條件,節點控制器會自動為符合條件的節點新增taint,以下是一些內建的taint

  • node.kubernetes.io/not-ready,節點還沒有準備好,對應節點狀態Ready值為false

  • node.kubernetes.io/unreachable,節點控制器無法觸及節點,對應節點狀態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

在kubernetes 1.13版本,基於汙點的驅離策略提升到beta級別並且預設開啟,因此汙點被node控制器(kubelete)自動新增,並且普通的以節點的Ready狀態為基礎的驅離策略被禁用.

這項beta功能,加上tolerationSeconds,允許節點來指定仍然可以留存長時間即便節目有一種或者多種匹配的問題

例如:一個包含多種本地狀態的應用在節點發生網路分裂情況時希望仍然可以留存一點時間,期望在指定的時段內網路能恢復正常以避免被驅離.這種情況下容忍此節點的pod編排如下

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

請注意,如果使用者沒有在pod的配置中指定node.kubernetes.io/not-ready,則kubernetes會自動為pod配置加上node.kubernetes.io/not-ready tolerationSeconds=300屬性.同樣地,如果沒有配置,則自動新增node.kubernetes.io/unreachable tolerationSeconds=300

DaemonSet型別的pod建立時自動為以下兩種型別的taint新增NoExecute效果型別並且沒有tolerationSeconds

  • node.kubernetes.io/unreachable

  • node.kubernetes.io/not-ready

這確保即便節點出現問題,DaemonSet也不會被驅離.

有條件節點taint

在kubernetes 1.12版,有條件為節點新增taint(TaintNodesByCondition)特徵被提升為beta級別,節點生命週期控制器會自動根據節點的狀態為節點新增taint.同樣地排程器不檢測node的狀態,而是檢測node 的汙點(taint).這確保node的狀態不影響哪些pod可以排程到此node上,使用者可以選擇通過新增相應的容忍(toleration)來忽略node的指定的問題(通過node的狀態體現).注意TaintNodesByCondition僅新增NoSchedule型別的汙點.NoExecute效果型別由TaintBasedEviction控制(此功能為1.13版本的beta功能)

從kubernetes 1.8開始,DaemonSet controller自動以下型別的為所有的daemon新增NoSchedule效果型別的容忍(toleration),來防止DeamonSet分裂

  • node.kubernetes.io/memory-pressure

  • node.kubernetes.io/disk-pressure

  • node.kubernetes.io/out-of-disk (only for critical pods)

  • node.kubernetes.io/unschedulable (1.10 or later)

  • node.kubernetes.io/network-unavailable (host network only)

新增了這些型別的容忍是為了向後相容,你可以為DaemonSet新增任意型別的容忍

相關文章