Kubernetes高階排程- Taint和Toleration、Node Affinity分析

CCE_huawei發表於2019-04-10

此文分享了汙點和Node Affinity實際使用過程中的細節、坑和思維誤區。同時整理且回答了諸多細節問題,尤其那些在官方文件中不曾提及的細節。

閱讀提示:文中的節點指Node

(避免Pod和Node同時出現在一小段文字中,所以Node以節點漢字表述)

Taint和Toleration

汙點的理論支撐

1.1 汙點設定有哪些影響效果

使用效果(Effect):

  • PreferNoSchedule:排程器儘量避免把Pod排程到具有該汙點效果的節點上,如果不能避免(如其他節點資源不足),Pod也能排程到這個汙點節點上。

  • NoSchedule:不容忍該汙點效果的Pod永不會被排程到該節點上,透過kubelet管理的Pod(static Pod)不受限制;之前沒有設定汙點的Pod如果已執行在此節點(有汙點的節點)上,可以繼續執行。

  • NoExecute: 排程器不會把Pod排程到具有該汙點效果的節點上,同時會將節點上已存在的Pod驅逐出去。

汙點設定的第一前提是: 節點上的汙點key和Pod上的汙點容忍key相匹配。

1.2 設定汙點的效果實測


當Pod未設定汙點容忍而節點設定了汙點時

  • 當節點的汙點影響效果被設定為:PreferNoSchedule時,已存在於此節點上的Pod不會被驅逐;新增但未設定汙點容忍的Pod仍然可以被排程到此節點上。

  • 當節點的汙點影響效果被設定為:NoSchedule時,已存在於此節點上的Pod不會被驅逐;同時,新增的Pod不會被排程此節點上。

  • 當節點的汙點影響效果被設定為:NoExecute時,已存在於此節點上的Pod會發生驅逐(驅逐時間由tolerationSeconds欄位確定,小於等於0會立即驅逐);新增的Pod不會排程到此節點上。

當Node設定了汙點且Pod設定了對應的汙點容忍時,實測效果如下表:


汙點容忍設定, Exists和Equal這兩個運算子之間的區別是什麼?

在配置上:

  • Exists必須把值設定為空字串,而只關心key與節點的汙點key是否匹配。

  • Equal需要同時設定key和value來匹配汙點節點的Key和value。

兩者之間的理解加深:

  • 若一個節點存在多個汙點, Pod使用Exists只容忍了其中一個汙點, 仍然不能排程此節點, 原因在於Pod不容忍此節點的其他汙點。

  • 若一個節點存在多個汙點, Pod使用Equal只容忍了其中一個汙點, 仍然不能排程此節點, 原因在於Pod還是不容忍此節點的其他汙點。

  • 若想要一個Pod能夠排程到含有多個汙點的節點上, 那麼此Pod需要容忍此節點的所有汙點。

1.3 汙點容忍裡的一些小竅門:

  • 在汙點容忍設定時,若key,value是空字元且運算子是Exists 那麼能Pod容忍節點的所有汙點。(注意:仍然遵從於容忍效果的等級設定)。例如:一個Pod在設定汙點容忍時,key,value為空且運算子是Exists,容忍效果為:NoExecute,那麼該Pod不會排程到汙點效果為:NoSchedule的節點上。

  • 在設定汙點容忍時, 若Pod的容忍效果(effect)被設定為空字元,那麼Pod能匹配所有的容忍效果。

  • 在設定汙點容忍時, 若key,value為空、運算子是Exists且容忍效果(effect)也為空時,則等於沒有設定。

預設情況下,運算子是Equal。

如果節點的影響效果是NoExecute,且不想Pod被立即驅逐,那麼可以設定TolerationSeconds(延遲驅逐時間),若值是0或者負數會立即驅逐,若值大於0,則在此時間後開始驅逐。

從測試結果來看,只要節點設定了汙點且效果是:NoExecute,不管Pod是否容忍了該汙點都不能在對應節點上正常執行(一直處於刪除,重建的過程),原因是能被排程到節點上是排程器選擇的結果,Pod被殺掉是本地kubelet決策的結果,這是兩個元件分管不同工作產生的效果,下面這種配置除外。

tolerations:      
    - operator: Exists

#此Pod的汙點配置能夠容忍所有的汙點,所有的影響效果,所有能排程到所有的節點上(包括影響效果被設定為:NoExecute的Node).

1.4 認知誤區

1.4.1 當一個節點設定了汙點,那麼只要設定Pod對此汙點容忍就能排程上去且能正常執行。(錯)

當節點的一個汙點的影響效果被設定為:NoExecute,此時Pod對此汙點的容忍效果也是NoExecute時, Pod能排程上去,但是也會被Terminating,不斷的處於Terminating,ContainerCreating的過程。

對Node設定汙點:

kubectl taint nodes 1xx status=unavailable:NoExecute

Pod設定的汙點容忍:

tolerations:
     - effect: NoExecute
        key: status
        operator: Equal 
        tolerationSeconds: 0
         value: unavailable

效果:

tolerations:      
    - operator: Exists

#此Pod的汙點配置能夠容忍所有的汙點,所有的影響效果,所有能排程到所有的節點上(包括影響效果被設定為:
NoExecute的Node).

1.4.2  當一個節點設定了多個汙點,只要使用Exists運算子匹配到其中一個汙點,此Pod就能排程到對應的節點上。(錯)

原因在於Pod只能匹配到其中一個汙點,但是還是不能匹配到其他汙點。所以,不能排程上去。

1.4.3  在設定Pod容忍時,只要匹配到key和value就行了,不用關心容忍效果的設定。(錯)

容忍效果的設定和key/value的設定一樣重要,甚至更加重要。如果容忍效果不匹配。也會導致Pod排程不能到對應節點上。

1.4.4  如果Pod沒有設定任何的汙點容忍,Pod就不能排程到有汙點的節點上。(錯)

如果節點的汙點效果是: PreferNoSchedule, 沒有設定任何汙點容忍的Pod也能排程到此節點上。原因在於:PreferNoSchedule的意思是優先不排程,但是當沒有節點可用時,Pod仍然能排程到此節點。

Node Affinity

Node Affinity可以讓指定應用排程到指定的節點,這有利於應用的穩定性,減少重要業務和不重要業務之間相互搶佔資源的可能,同時也可以降低不重要業務對重要業務的影響,另一方面,也能夠進行多租戶之間的隔離。根據租戶需求為租戶提供特定的執行環境。

2.1 NodeAffinity配置要點

NodeAffinity配置分類兩大部分:

requiredDuringSchedulingIgnoredDuringExecution (強親和性)

preferredDuringSchedulingIgnoredDuringExecution (首選親和性)

但是,在真實的配置環節時,又會犯迷糊:

  • 強親和性到底多強算強?

  • 首選親和性中的首選體現在那些方面?

  • 強親和性配置時,有兩種配置方式,兩種的區別是什麼?

  • 首選親和性中的權重值到底是什麼規則? 值越大權重值越高麼?還是值越小越高(1最大)?

  • 首選親和性配置中, 如果Pod能匹配A節點的多個Label,也能匹配B節點的一個Label(A的Label權重之和等於B單個Label的權重),這時Pod會優先排程到A節點麼?

  • 縮容時,是先從低權重的節點上開始殺麼? 這些問題, 我們都不能全靠註釋和理解去揣測答案,必須經過實測得到真實答案,否則一旦上了生產再想修改就需要付出更大的成本。

  • 如果Pod是以強親和性的方式繫結在節點上且Pod已經正常執行在此節點上,此時刪除節點的標籤是否會導致Pod重啟發生漂移。

強親和性:

requiredDuringSchedulingIgnoredDuringExecution

例子Node Labels設定:

level: important(重要),general(一般),unimportant(不重要)

Pod與運算的配置:

注意: 強親和性的配置分為: 與運算、或運算兩部分

requiredDuringSchedulingIgnoredDuringExecution:
           nodeSelectorTerms:
              - matchExpressions:
              - key: level
                  operator: In
                  values:    
                   - important
               - key: app
                   operator: In
                   values:
                   - 1

在與運算的配置中,我們發現,在同一個matchExpressions中既需要匹配level=important的標籤也需要匹配app=1的標籤。也就是說:Pod只會選擇同時匹配這兩個Label的節點。

根據上面Pod的Node親和性設定,兩個Label求一個交集,只有同時滿足兩個Label的節點才會納入這個Pod的排程池,顯而易見,只有10.x.x.80這個節點。所以,此Pod只能排程到這個節點,如果這個節點資源不足,那麼此Pod排程失敗。

Pod或運算配置:

requiredDuringSchedulingIgnoredDuringExecution:
           nodeSelectorTerms:
           - matchExpressions:
              - key: level 
               operator: In
               values:
               - important
            - matchExpressions:
              - key: level 
               operator: In
               values:
               - unimportant

在或運算的配置中,我們發現有一個matchExpressions陣列,裡面的Label列表求並集。也就是說:Pod可以選擇只要匹配其中一個Label的節點就行,不用全匹配。

舉個例子:

節點的Label設定沿用上一個例子的。 節點的標籤只要能滿足Pod的其中一個標籤, 節點就能納入這個Pod的排程池,顯而易見,這個Pod可選的節點有:10.x.x.78, 10.x.x.79,10.x.x.80, 10.x.x.86, 10.x.x.87, 10.x.x.88。

首選親和性: 

preferredDuringSchedulingIgnoredDuringExecution

它的使用風格應該是:如果Pod能排程到指定Label的節點最好,如果不能,也不強求,Pod選擇其他的節點也行,即使這個節點根本沒有Label或者節點的Label和我完全不匹配。

Pod首選親和性設定:

preferredDuringSchedulingIgnoredDuringExecution:
         - preference:
              matchExpressions:
             - key: level 
               operator: In 
               values:
               - important
            weight: 5
         - preference: 
             matchExpressions:
             - key: app
                operator: In 
               values:
               - "1"
           weight: 4
         - preference:
              matchExpressions:
             - key: master
                operator: In
                values:
               - "1"
           weight: 10

示例: Node的Label設定沿用上一個例子的, 根據上面的配置,我們會看到:

如表所示, 最終Pod優先排程到10.x.x.85, 原因在於app=1的權重是4, level=important的權重是5, 所以:節點 10.x.x.80的權重是:9,但是仍然小於節點:10.x.x.85的權重。

2.2 問題總結

  1. 其實強親和性和首選親和性區別體現在:Pod對節點的選擇上。就強親和性而言,如果節點不能匹配Pod對Label的要求, Pod永遠不會排程到這類節點上,即使是Pod排程失敗(沒錯,就是頭鐵),就首選親和性來說,能排程到最優節點是一件非常值得開心的事情,如果不能排程到最優節點可以退而求其次,總有適合自己的。 (回答問題1)

  2. 首選親和性體現在PodLabel的權重值上,而與節點Label的匹配個數無關。(回答問題2)

  3. 在首選親和性配置中會多一個權重值的欄位(weight),這個值越大,權重越大,Pod排程到對應此Label的節點的機率越高。(回答問題4)

  4. 一個節點有多個Label且節點能滿足Pod所要求的所有Label,如果多個Label的權重值相加仍然小於某單個Label的節點,那麼Pod首選是權重值高的節點;如果Pod能匹配到A 節點的所有Label,同時也能匹配到B 節點某一個Label.但是,A節點 Label的權重之和剛好等於B 節點的單個Label的權重,這時,Pod優先選擇的A還是B這是隨機的(只針對親和性來說是隨機的,實際情況還要考慮其他情況)。而不會管Label的匹配個數。(回答問題5)

  5. 建立或擴容Pod時,優先選擇Label匹配權重值大的節點,若此節點的其他條件不滿足(比如記憶體不足),選擇次權重的,最後選擇Label不匹配或者根本沒有Label的節點。

  6. (回答問題6)縮容時,隨機選擇Pod殺掉,而不是我們預想的從低權重的節點開始殺,這點值得注意。

  7. (回答問題7)答案是不會,正在執行的Pod不會被排程到新的節點去, 當Pod因為某種原因重啟(指Pod名字改變,觸發重排程,名字不改變,意味著不觸發排程器排程,只是原地重啟)後,會自動排程到符合親和性選擇的節點上。

汙點和Node Affinity的使用總結

  1. 就汙點而言,它的使用通常是負向的, 也就說, 汙點常用在某Node不讓大多數Pod排程只讓少部分Pod排程時,又或者節點根本不參加工作負載時。比如:我們常見的master節點上不排程負載pod,保證master元件的穩定性;節點有特殊資源,大部分應用不需要而少部分應用需要,如GPU。

  2. 就Node Affinity來說,他的使用可以正向的,也就是說,我們想讓某個應用的Pod部署在指定的一堆節點上。當然,也可以是負向的,比如說我們常說的Node 反親和性,只需要把運算子設定為NotIn就能達成預期目標。

  3. 就汙點而言,如果節點設定的汙點效果是NoSchedule或者NoExecute,意味著沒有設定汙點容忍的Pod絕不可能排程到這些節點上。

  4. 就Node Affinity而言,如果節點設定了Label,但是Pod沒有任何的Node Affinity設定,那麼Pod是可以排程到這些節點上的。

相關服務請訪問:https://support.huaweicloud.com/cce/index.html?utm_content=cce_helpcenter_2019


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69908804/viewspace-2640966/,如需轉載,請註明出處,否則將追究法律責任。

相關文章