k8s學習筆記-調度之Affinity


Kubernetes中的調度策略可以大致分為兩種

一種是全局的調度策略,要在啟動調度器時配置,包括kubernetes調度器自帶的各種predicates和priorities算法,具體可以參看上一篇文章;

另一種是運行時調度策略,包括nodeAffinity(主機親和性),podAffinity(POD親和性)以及podAntiAffinity(POD反親和性)。

nodeAffinity 主要解決POD要部署在哪些主機,以及POD不能部署在哪些主機上的問題,處理的是POD和主機之間的關系。

podAffinity 主要解決POD可以和哪些POD部署在同一個拓撲域中的問題(拓撲域用主機標簽實現,可以是單個主機,也可以是多個主機組成的cluster、zone等。)

podAntiAffinity主要解決POD不能和哪些POD部署在同一個拓撲域中的問題。它們處理的是Kubernetes集群內部POD和POD之間的關系。

三種親和性和反親和性策略的比較如下表所示:

策略名稱 匹配目標 支持的操作符 支持拓撲域 設計目標
nodeAffinity 主機標簽 In,NotIn,Exists,DoesNotExist,Gt,Lt 不支持 決定Pod可以部署在哪些主機上
podAffinity Pod標簽 In,NotIn,Exists,DoesNotExist 支持 決定Pod可以和哪些Pod部署在同一拓撲域
PodAntiAffinity Pod標簽 In,NotIn,Exists,DoesNotExist 支持 決定Pod不可以和哪些Pod部署在同一拓撲域

親和性:應用A與應用B兩個應用頻繁交互,所以有必要利用親和性讓兩個應用的盡可能的靠近,甚至在一個node上,以減少因網絡通信而帶來的性能損耗。

反親和性:當應用的采用多副本部署時,有必要采用反親和性讓各個應用實例打散分布在各個node上,以提高HA。

主要介紹kubernetes的中調度算法中的Node affinity和Pod affinity用法

實際上是對前文提到的優選策略中的NodeAffinityPriority策略和InterPodAffinityPriority策略的具體應用。

kubectl explain pods.spec.affinity 

親和性策略(Affinity)能夠提供比NodeSelector或者Taints更靈活豐富的調度方式,例如:

豐富的匹配表達式(In, NotIn, Exists, DoesNotExist. Gt, and Lt)
軟約束和硬約束(Required/Preferred)
以節點上的其他Pod作為參照物進行調度計算
親和性策略分為NodeAffinityPriority策略和InterPodAffinityPriority策略。

先回顧一下之前的節點選擇器

節點選擇器: nodeSelector nodeName
創建一個Pod 節點選擇器標簽
nodeSelector:
   disktype: ssd

默認節點沒這個標簽:所以會調度失敗

[root@k8s-master schedule]# kubectl get node --show-labels|egrep disktype
[root@k8s-master schedule]# kubectl get pods
NAME          READY      STATUS      RESTARTS  AGE
pod-demo        0/1        Pending           0          11s
[root@k8s-master schedule]# kubectl describe pod pod-demo
Warning FailedScheduling 28s (x2 over 28s) default-scheduler 0/3 nodes are available: 3 node(s) didn't match node selector.

給一個節點打上標簽:
[root@k8s-master schedule]# kubectl label nodes k8s-node2 disktype=ssd
node/k8s-node2 labeled

[root@k8s-master schedule]# kubectl get node --show-labels|egrep disktype
k8s-node2 Ready <none> 63d v1.14.1 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node2,kubernetes.io/os=linux

[root@k8s-master schedule]# kubectl get pods -o wide
NAME          READY          STATUS         RESTARTS AGE     IP             NODE            NOMINATED NODE  READINESS GATES
pod-demo       1/1               Running             0          45s  10.244.1.14   k8s-node2                 <none>              <none>

Node affinity(節點親和性)

kubectl explain pods.spec.affinity.nodeAffinity 

據官方說法未來NodeSeletor策略會被廢棄,由NodeAffinityPriority策略中requiredDuringSchedulingIgnoredDuringExecution替代。

NodeAffinityPriority策略和NodeSelector一樣,通過Node節點的Label標簽進行匹配,匹配的表達式有:In, NotIn, Exists, DoesNotExist. Gt, and Lt。

定義節點親和性規則有2種:硬親和性(require)和軟親和性(preferred)

硬親和性:requiredDuringSchedulingIgnoredDuringExecution
軟親和性:preferredDuringSchedulingIgnoredDuringExecution

  • 硬親和性:實現的是強制性規則,是Pod調度時必須滿足的規則,否則Pod對象的狀態會一直是Pending
  • 軟親和性:實現的是一種柔性調度限制,在Pod調度時可以盡量滿足其規則,在無法滿足規則時,可以調度到一個不匹配規則的節點之上。

需要注意的是preferredrequired后半段字符串IgnoredDuringExecution表示:

在Pod資源基於節點親和性規則調度到某個節點之后,如果節點的標簽發生了改變,調度器不會講Pod對象從該節點上移除,因為該規則僅對新建的Pod對象有效。

硬親和性

kubectl explain pods.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution

apiVersion: v1
kind: Pod
metadata:
    name: nodeaffinity-required 
spec:

   containers:
  -  name: myapp
      image: ikubernetes/myapp:v1
   affinity:
     nodeAffinity:
        requiredDuringSchedulingIgnoredDuringExecution:
          nodeSelectorTerms:
          -  matchExpressions:
         #   -  {key: zone,operator: In,values: ["ssd","hard"]}    

              -  key: disktype
                 operator: In
                 values:
                 -  ssd

                 -  hard

[root@k8s-master schedule]# kubectl get pod -o wide
NAME                        READY         STATUS              RESTARTS      AGE      IP               NODE             NOMINATED NODE    READINESS GATES
pod-affinity-required     1/1               Running                  0               7s    10.244.1.16     k8s-node2              <none>                   <none>

發現和上面定義的節點選擇器效果一樣,未來是要取代節點選擇器的。

注意:

nodeSelectorTerms可以定義多條約束,只需滿足其中一條。
    matchExpressions可以定義多條約束,必須滿足全部約束

如下配置清單,必須存在滿足標簽zone=foo和ssd=true的節點才能夠調度成功
affinity:
   nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
         nodeSelectorTerms:
         -  matchExpressions:
             -  {key: zone, operator: In, values: ["foo"]}
             -  {key: ssd, operator: Exists, values: []} #增加一個規則

[root@k8s-master ~]# kubectl get pods pod-affinity-required
NAME                           READY       STATUS     RESTARTS    AGE
pod-affinity-required       0/1            Pending          0             16s
[root@k8s-master ~]# kubectl label node k8s-node1 ssd=true

[root@k8s-master ~]# kubectl get pods  pod-affinity-required 
NAME                             READY         STATUS       RESTARTS AGE
 pod-affinity-required         1/1              Running           0          2m

軟親和性

kubectl explain pods.spec.affinity.nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution

affinity:
  nodeAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
    -  weight:  60
        preference:
          matchExpressions:
          -  {key: zone, operator: In, values: ["foo"]}
    -  weight:  30
        preference:
          matchExpressions:
          -  {key: ssd, operator: Exists, values: []}

總結:

  • 同時指定nodeSelector and nodeAffinity,pod必須都滿足
  • nodeAffinity有多個nodeSelectorTerms ,pod只需滿足一個
  • nodeSelectorTerms多個matchExpressions ,pod必須都滿足
  • 由於IgnoredDuringExecution,所以改變labels不會影響已經運行pod

總的來說,node親和性與nodeSelector類似,是它的擴展,節點是否配置合乎需求的標簽,或者Pod對象定義合理的標簽選擇器,這樣才能夠基於標簽選擇出期望的目標節點

Pod affinity(Pod 親和性)

kubectl explain pods.spec.affinity.podAffinity

在出於高效通信的需求,有時需要將一些Pod調度到相近甚至是同一區域位置(比如同一節點、機房、區域)等等,比如業務的前端Pod和后端Pod,

此時這些Pod對象之間的關系可以叫做親和性。同時出於安全性的考慮,也會把一些Pod之間進行隔離,此時這些Pod對象之間的關系叫做反親和性。

調度器把第一個Pod放到任意位置,然后和該Pod有親和或反親和關系的Pod根據該動態完成位置編排,這就是Pod親和性和反親和性調度的作用。

Pod的親和性定義也存在硬親和性和軟親和性的區別,其約束的意義和節點親和性類似。

requiredDuringSchedulingIgnoredDuringExecution, 硬約束,一定要滿足,Pod的親和性調度必須要滿足后續定義的約束條件。
preferredDuringSchedulingIgnoredDuringExecution,軟約束,不一定滿足,Pod的親和性調度會盡量滿足后續定義的約束條件。

Pod的親和性調度要求各相關的Pod對象運行在同一位置,而反親和性則要求它們不能運行在同一位置。這里的位置實際上取決於節點的位置拓撲,拓撲的方式不同,Pod是否在同一位置的判定結果也會有所不同。

如果基於各個節點的kubernetes.io/hostname標簽作為評判標准,那么會根據節點的hostname去判定是否在同一位置區域。

根據節點上正在運行的pod的標簽來調度,而非node的標簽,要求對節點和Pod兩個條件進行匹配,其規則為:如果在具有標簽X的Node上運行了一個或多個符合條件Y的Pod,那么Pod應該運行在此Node上,

如果是互斥,則拒絕運行在此Node上。 也就是說根據某個已存在的pod,來決定要不要和此pod在一個Node上,在一起就需要設置親和性,不和它在一起就設置互斥性。

Pod親和性調度請使用:podAffinity,非親和性調度請使用:podAntiAffinity。

InterPodAffinityPriority策略有podAffinity和podAntiAffinity兩種配置方式。

InterPodAffinityPriority是干嘛的呢?簡單來說,就說根據Node上運行的Pod的Label來進行調度匹配的規則,匹配的表達式有:In, NotIn, Exists, DoesNotExist,通過該策略,可以更靈活地對Pod進行調度。

例如:將多實例的Pod分散到不通的Node、盡量調度A-Pod到有B-Pod運行的Node節點上等等。另外與Node-affinity不同的是:該策略是依據Pod的Label進行調度,所以會受到namespace約束。

硬親和性

通過Kubernetes內置節點標簽中的key來進行聲明,這個key的名字為topologyKey,用來表達節點所屬的拓朴結構之下

pod的親和性表達方式與Node親和性是一樣的表達方式。

kubectl explain pods.spec.affinity.podAffinity.requiredDuringSchedulingIgnoredDuringExecution

參數配置說明

kubectl -get nodes --show-labels

  kubernetes內置標簽:

        ○ kubernetes.io/hostname

        ○ failure-domain.beta.kubernetes.io/zone

        ○ failure-domain.beta.kubernetes.io/region

        ○ beta.kubernetes.io/instance-type

        ○ beta.kubernetes.io/os

        ○ beta.kubernetes.io/arch

topologyKey:

  1. 對於親和性和軟反親和性,不允許空topologyKey;
  2. 對於硬反親和性,LimitPodHardAntiAffinityTopology控制器用於限制topologyKey只能是kubernetes.io/hostname;
  3. 對於軟反親和性,空topologyKey被解讀成kubernetes.io/hostname, failure-domain.beta.kubernetes.io/zone and failure-domain.beta.kubernetes.io/region的組合;
  4. kubernetes.io/hostname標簽是Kubernetes集群節點的內建標簽,它的值為當前節點的主機名,對於各個節點來說都是不同的

1:創建參照Pod

#查看調度到哪個Node之上:
kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
pod-flag 1/1 Running 0 4m 10.244.1.16 k8s-node1

2:創建一個pod的硬親和性

# 因為pod是屬於某個命名空間的,所以設置符合條件的目標Pod時,還可以指定哪個命名空間或全部命名空間里的Pod,
# namespace的定義與labelSelector同級,如果不指定命名空間,則與此處創建的pod在一個namespace之中
kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
with-pod-affinity 1/1 Running 0 11s 10.244.1.16 k8s-node1
pod-flag 1/1 Running 0 1h 10.244.1.17 k8s-node1
的確是在同一個Node上。
如果在創建時,pod狀態一直處於Pending狀態,很有可能是因為找不到滿足條件的Node
基於單一節點的Pod親和性相對來說使用的情況會比較少,通常使用的是基於同一地區、區域、機架等拓撲位置約束。

比如部署應用程序(myapp)和數據庫(db)服務相關的Pod時,這兩種Pod應該部署在同一區域上,可以加速通信的速度

3:創建一個pod的反硬親和性

kubectl explain pods.spec.affinity.podAntiAffinity.requiredDuringSchedulingIgnoredDuringExecution

kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
pod-flag 1/1 Running 0 1h 10.244.1.16 k8s-node1
with-pod-affinity 1/1 Running 0 1h 10.244.1.17 k8s-node1
with-pod-antiffinity 1/1 Running 0 1m 10.244.2.11 k8s-node2
#可以看到與參照pod不在同一個node之上,達到了互斥的作用

實例:

1.借助反硬特性我們可以部署3個redis實例,並且為了提升HA,部署在不同的節點:

apiVersion: apps/v1 kind: Deployment metadata:  name: redis-cache spec:  selector:  matchLabels:  app: store  replicas: 3  template:  metadata:  labels:  app: store  spec:  affinity:  podAntiAffinity:  requiredDuringSchedulingIgnoredDuringExecution:  - labelSelector:  matchExpressions:  - key: app  operator: In  values:  - store  topologyKey: "kubernetes.io/hostname"  containers:  - name: redis-server  image: redis:3.2-alpine

2:部署三個web實例,為了提升HA,都不在一個node;並且為了方便與redis交互,盡量與redis在同一個node(硬特性和反硬特性的結合應用)。

apiVersion: apps/v1 kind: Deployment metadata:  name: web-server spec:  selector:  matchLabels:  app: web-store  replicas: 3  template:  metadata:  labels:  app: web-store  spec:  affinity:  podAntiAffinity: #反親和性  requiredDuringSchedulingIgnoredDuringExecution:  - labelSelector:  matchExpressions:  - key: app  operator: In  values:  - web-store  topologyKey: "kubernetes.io/hostname"  podAffinity: #親和性  requiredDuringSchedulingIgnoredDuringExecution:  - labelSelector:  matchExpressions:  - key: app  operator: In  values:  - store  topologyKey: "kubernetes.io/hostname"  containers:  - name: web-app  image: nginx:1.12-alpine

軟親和性

kubectl explain pods.spec.affinity.podAffinity.preferredDuringSchedulingIgnoredDuringExecution

上述的清單配置當中,pod的軟親和調度需要將Pod調度到標簽為app=cache並在區域zone當中,或者調度到app=db標簽節點上的,但是我們的節點上並沒有類似的標簽,

所以調度器會根據軟親和調度進行隨機調度到k8s-node1節點之上。如下:

[root@k8s-master ~]# kubectl get pods -o wide |grep myapp-with-preferred-pod-affinity

myapp-with-preferred-pod-affinity-5c44649f58-cwgcd 1/1 Running 0 1m 10.244.1.40 k8s-node01

myapp-with-preferred-pod-affinity-5c44649f58-hdk8q 1/1 Running 0 1m 10.244.1.42 k8s-node01

myapp-with-preferred-pod-affinity-5c44649f58-kg7cx 1/1 Running 0 1m 10.244.1.41 k8s-node01

pod的反軟親和度:

kubectl explain pods.spec.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution

podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: security operator: In values: - S2 topologyKey: kubernetes.io/hostname
如果該節點已經運行着具有“security=S2”標簽的pod,將不會優先調度到該節點。
如果 topologyKeyfailure-domain.beta.kubernetes.io/zone,該pod也不會被優先調度到具有“security=S2”標簽的節點所在的zone
 
實例:

使用該配置模板創建三個pod,可以發現pod依舊分配到了不同的節點上。當創建第四個pod時,第四個pod能夠被順利創建

說明preferredDuringScheduling在podAntiAnffinity下也是不嚴格匹配規則,如果是硬約束,會有一個處於 Pending 

對稱性
考慮一個場景,兩個應用S1和S2。現在嚴格要求S1 pod不能與S2 pod運行在一個node,
如果僅設置S1的hard反親和性是不夠的,必須同時給S2設置對應的hard反親和性。
即調度S1 pod時,考慮node沒有S2 pod,同時需要在調度S2 pod時,考慮node上沒有S1 pod。考慮下面兩種情況:
1.先調度S2,后調度S1,可以滿足反親和性,
2.先調度S1,后調度S2,違反S1的反親和性規則,因為S2沒有反親和性規則,所以在schedule-time可以與S1調度在一個拓撲下。
這就是對稱性,即S1設置了與S2相關的hard反親和性規則,就必須對稱地給S2設置與S1相關的hard反親和性規則,以達到調度預期。

反親和性(soft/hard)具備對稱性,上面已經舉過例子了
hard親和性不具備對稱性,例如期望test1、test2親和,那么調度test2的時候沒有必要node上一定要有test1,但是有一個隱含規則,node上有test1更好
soft親和性具備對稱性,不是很理解,遺留

總結:

1.Pod間的親和性和反親和性需要大量的處理,需要消耗大量計算資源,會增加調度時間,這會顯着減慢大型集群中的調度。 我們不建議在大於幾百個節點的群集中使用它們。

2.Pod反親和性要求Node一致地標記,集群中的每個節點必須具有匹配topologyKey的標簽,Pod反親和性需要制定topologyKey如果某些或所有節點缺少指定的topologyKey標簽,則可能導致意外行為。

3.在反親和性中,空的selector表示不與任何pod親和。

4.由於hard規則在預選階段處理,所以如果只有一個node滿足hard親和性,但是這個node又不滿足其他預選判斷,比如資源不足,那么就無法調度。所以何時用hard,何時用soft需要根據業務考量。

5.如果所有node上都沒有符合親和性規則的target pod,那么pod調度可以忽略親和性

6.如果labelSelector和topologyKey同級,還可以定義namespaces列表,表示匹配哪些namespace里面的pod,默認情況下,會匹配定義的pod所在的namespace,如果定義了這個字段,但是它的值為空,則匹配所有的namespaces。

7.所有關聯requiredDuringSchedulingIgnoredDuringExecution的matchExpressions全都滿足之后,系統才能將pod調度到某個node上。

 

 

 

 

 

 


免責聲明!

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



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