Pod親和性調度

在K8S平臺上,我們很少會直接創建一個Pod,在大多數情況下會通過RC,Deployment,DaemonSet,Job等控制器完成一組Pod副本的創建,調度及全生命週期的自動控制任務。

在k8s 1.9以前,在RC等對象被刪除後,它們所創建的Pod副本都不會被刪除;在k8s 1.9以後,這些Pod副本會被一併刪除。

如果不希望這樣做,可以通過kubectl命令的“--cascade=false”參數來取消這一默認特性:

kubectl delete replicaset my-reset  --cascade=false

NodeSelector:定向調度

在一些情況下,我們需要將pod調度到指定的一些Node上,可以通過Node的標籤(Label)和Pod的nodeSelector屬性相匹配。

  1. 首先通過kubectl label 命令給目標Node打上一些標籤:

kubectl label nodes node-name label-key=label-vaule

kubectl  label nodes 172.20.103.2 test=jinguanhua

  1. 然後,在pod的定義中加上nodeSelector的設置:

kubectl create -f redis.yaml

apiVersion: v1

kind: deploy

metadata:

  name: redis-master

  labels:

    name: redis-master

spec:

  replicas: 1

  selector:

    name: redis-master

  template:

    metadata:

      labels:

        name: redis-master

    spec:

      containers:

      - name: master

        image: kubeguide/redis-master

        ports:

        - containerPort: 6379

      nodeSelector:

        test: jinguanhua

如果我們給多個node都定義了相同的標籤,則scheduler會根據調度算法從這組Node中挑選一個可用的Node進行Pod調度。

通過基於Node標籤的調度方式,我們可以把集羣中具有不同特點的Node都貼上不同的標籤,例如“role=test”,“role=backend”,“role=database”等標籤,在部署應用時就可以根據應用的需求設置NodeSelector來進行制定Node範圍的調度。

PS:如果我們指定了Pod的nodeSelector條件,但是在集羣中不存在包含相應標籤的Node,則即使在集羣中還有其他可供使用的node,這個pod也無法被成功調度。


親和性調度

親和性調度功能包括 節點親和性(NodeAffinity)和 Pod親和性(PodAffinity)兩個維度的設置。

節點親和性(NodeAffinity)

NodeAffinity是node親和性的調度策略,是用於替換NodeSelector的全新調度策略。目前有兩種節點親和性表達。

  1. RequiredDuringSchedulingIgnoredDuringExecution:必須滿足指定的規則纔可以調度pod到node上,相當於硬限制。

  2. PreferredDuringSchedulingIgnoredDuringExecution:強調優先滿足指定規則,調度器會嘗試調度pod到node上,但並不強求,相當於軟限制。多個優先級規則還可以設置權重(weight)值,以定義執行的先後順序。

IgnoredDuringExecution的意思是:如果一個pod所在的節點在pod運行期間標籤發生了變更,不再符合該pod的節點親和性需求,則系統將忽略node上label的變化,該pod能繼續在該節點運行。

apiVersion: v1

kind: Pod

metadata:

  name: with-node-affinity

spec:

  affinity:

    nodeAffinity:

      requiredDuringSchedulingIgnoredDuringExecution:

        nodeSelectorTerms:

        - matchExpressions:

          - key: kubernetes.io/arch

            operator: In

            values:

            - amd64

      preferredDuringSchedulingIgnoredDuringExecution:

      - weight: 1

        preference:

          matchExpressions:

          - key: disk-type

            operator: In

            values:

            - ssd

  containers:

  - name: with-node-affinity

    image: gcr.io/google_containers/pause:2.0

從上面的配置中可以看到In操作符,NodeAffinity語法支持的操作符包括In,NotIn,Exists,DoesNotExist,Gt,Lt。雖然沒有節點排斥功能,但是用NotIn和DoesNotExist就可以實現排斥的功能了。

NodeAffinity 規則設置的注意事項如下:

  • 如果同時定義了nodeSelector和nodeAffinity,那麼必須兩個條件都得到滿足,Pod才能最終運行到指定的Node上。

  • 如果nodeAffinity指定了多個nodeSelectorTerms,那麼其中一個能夠匹配成功即可。

  • 如果在nodeSelectorTerms中有多個matchExpressions,則一個節點必須滿足所有matchExpressions才能運行該Pod。


Pod親和性(PodAffinity)與互斥性(podAntiAffinity)調度策略

Pod間的親和與互斥從Kubernetes 1.4版本開始引入。這一功能讓用戶從另一個角度來限制Pod所能運行的節點:根據在節點上正在運行的Pod的標籤而不是節點的標籤進行判斷和調度,要求對節點和Pod兩個條件進行匹配。這種規則可以描述爲:如果在具有標籤X的Node上運行了一個或者多個符合條件Y的Pod,那麼Pod應該(如果是互斥的情況,那麼就變成拒絕)運行在這個Node上。

這裏X指的是一個集羣中的節點、區域(zone)和地域(region)等概念,通過Kubernetes內置節點標籤中的key來進行聲明。這個key的名字爲topologyKey,意爲表達節點所屬的topology範圍。

◎ kubernetes.io/hostname

◎ kubernetes.io/arch

◎ kubernetes.io/os

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

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

與節點不同的是,Pod是屬於某個命名空間的,所以條件Y表達的是一個或者全部命名空間中的一個Label Selector。

[root@iZ2ze7mealklhmaorgtx5jZ pro]# kubectl get no  cn-beijing.172.17.13.102 --show-labels

NAME                       STATUS   ROLES    AGE    VERSION            LABELS

cn-beijing.172.17.13.102   Ready    <none>   574d   v1.16.6-aliyun.1   alibabacloud.com/nodepool-id=np019605d02c37420a9e201a4eba2391c7,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=ecs.sn1ne.xlarge,beta.kubernetes.io/os=linux,env=product,failure-domain.beta.kubernetes.io/region=cn-beijing,failure-domain.beta.kubernetes.io/zone=cn-beijing-c,kubernetes.io/arch=amd64,kubernetes.io/hostname=cn-beijing.172.17.13.102,kubernetes.io/os=linux

爲了保證業務應用的高可用,有些客戶會要求關鍵應用部署到多個機房,一個機房一旦出問題,其他機房正常工作,從而讓應用保持不間斷連續運行。類似這樣的能力在雲上如何實現呢?阿里雲有Region(地域)和Zone(可用區)的概念。簡單點理解,Region對應城市,例如“華東1”爲杭州,“華北2”爲北京等。Zone爲Region下按照電力和網絡設備等相互獨立的的可用區,不同的可用區可能在一個物理機房中。同一個地域內的不同可用區之間內網是連通的,網絡延遲很小。

和節點親和相同,Pod親和與互斥的條件設置也是requiredDuringSchedulingIgnoredDuringExecution和preferredDuringSchedulingIgnoredDuringExecution。

pod的親和性被定義與PodSpec的affinity字段下的podAffinity子字段中

pod間的互斥性則被定義於同一層次的podAntiAffinity子字段中。

下面通過實例來說明pod間的親和性和互斥性策略設置

1.參照目標Pod

首先,創建一個名爲pod-flag的Pod,帶有標籤security=S1和app=nginx,後面的例子將使用pod-flag作爲Pod親和與互斥的目標Pod:

apiVersion: v1

kind: Pod

metadata:

  name: pod-flag

  labels:

    security: "S1"

    app: "nginx"

spec:

  containers:

  - name: nginx

    image: nginx

2.Pod的親和性調度

下面創建第2個Pod來說明Pod的親和性調度,這裏定義的親和標籤是security=S1,對應上面的Pod“pod-flag”,topologyKey的值被設置爲“kubernetes.io/hostname”:

apiVersion: v1

kind: Pod

metadata:

  name: pod-affinity

spec:

  affinity:

    podAffinity:

      requiredDuringSchedulingIgnoredDuringExecution:

      - labelSelector:

          matchExpressions:

          - key: security

            operator: In

            values:

            - S1

        topologyKey: kubernetes.io/hostname

  containers:

  - name: with-pod-affinity

    image: gcr.io/google_containers/pause:2.0

創建Pod之後,使用kubectl get pods -o wide命令可以看到,這兩個Pod在同一個Node上運行。有興趣的讀者還可以測試一下,在創建這個Pod之前,刪掉這個節點的kubernetes.io/hostname標籤,重複上面的創建步驟,將會發現Pod一直處於Pending狀態,這是因爲找不到滿足條件的Node了。

3.Pod的互斥性調度

創建第3個Pod,我們希望它不與目標Pod運行在同一個Node上:

apiVersion: v1

kind: Pod

metadata:

  name: anti-affinity

spec:

  affinity:

    podAffinity:

      requiredDuringSchedulingIgnoredDuringExecution:

      - labelSelector:

          matchExpressions:

          - key: security

            operator: In

            values:

            - S1

        topologyKey: failure-domain.beta.kubernetes.io/zone

    podAntiAffinity:

      requiredDuringSchedulingIgnoredDuringExecution:

      - labelSelector:

          matchExpressions:

          - key: app

            operator: In

            values:

            - nginx

        topologyKey: kubernetes.io/hostname

  containers:

  - name: anti-affinity

    image: gcr.io/google_containers/pause:2.0

這裏要求這個新Pod與security=S1的Pod爲同一個zone,但是不與app=nginx的Pod爲同一個Node。創建Pod之後,同樣用kubectl get pods -o wide來查看,會看到新的Pod被調度到了同一Zone內的不同Node上。

與節點親和性類似,Pod親和性的操作符也包括In、NotIn、Exists、DoesNotExist、Gt、Lt。

原則上,topologyKey可以使用任何合法的標籤Key賦值,但是出於性能和安全方面的考慮,對topologyKey有如下限制。

◎ 在Pod親和性和RequiredDuringScheduling的Pod互斥性的定義中,不允許使用空的topologyKey。

◎ 如果Admission controller包含了LimitPodHardAntiAffinityTopology,那麼針對RequiredDuringScheduling的Pod互斥性定義就被限制爲kubernetes.io/hostname,要使用自定義的topologyKey,就要改寫或禁用該控制器。

◎ 在PreferredDuringScheduling類型的Pod互斥性定義中,空的topologyKey會被解釋爲kubernetes.io/hostname、failuredomain.beta.kubernetes.io/zone及failuredomain.beta.kubernetes.io/region的組合。

◎ 如果不是上述情況,就可以採用任意合法的topologyKey了。

PodAffinity規則設置的注意事項如下。

◎ 除了設置Label Selector和topologyKey,用戶還可以指定Namespace列表來進行限制,同樣,使用Label Selector對Namespace進行選擇。Namespace的定義和Label Selector及topologyKey同級。省略Namespace的設置,表示使用定義了affinity/anti-affinity的Pod所在的Namespace。如果Namespace被設置爲空值(""),則表示所有Namespace。

◎ 在所有關聯requiredDuringSchedulingIgnoredDuringExecution的matchExpressions全都滿足之後,系統才能將Pod調度到某個Node上。

image.png

image.png


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章