Kubernetes中的親和性與反親和性

通常情況下,Pod分配到哪些Node是不需要管理員操心的,這個過程會由scheduler自動實現。但有時,我們需要指定一些調度的限制,例如某些應用應該跑在具有SSD存儲的節點上,有些應用應該跑在同一個節點上等等。

截止到Kubernetes 1.11版本,節點親和性的特性還是Beta階段。

nodeSelector

首先我們爲Node規劃標籤,然後在創建部署的時候,通過使用nodeSelector標籤來指定Pod運行在哪些節點上。

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    env: test
spec:
  containers:
  - name: nginx
    image: docker.io/nginx
    imagePullPolicy: IfNotPresent
  nodeSelector:
    disktype: ssd

nodeSelector 將會在後續的版本中廢除,還是建議大家使用使用親和性策略。

親和與反親和 Affinity and anti-affinity

nodeSelector的調度方式略顯簡單,通過親和和反親和配置,能夠爲調度提供更靈活的策略,主要有以下幾點增強:

  • 更多的表達式支持,不僅僅是ADD和精確匹配了
  • 可以設置soft/preference的調度策略,而不是剛性的要求
  • 可以通過Pod的標籤進行調度約束,不僅僅是Node的標籤

親和性特性包含兩種方式

節點親和性 Node affinity

Node affinity 是 Kubernetes 1.2版本後引入的新特性,類似於nodeSelector,允許我們指定一些Pod在Node間調度的約束。支持兩種形式:requiredDuringSchedulingIgnoredDuringExecutionpreferredDuringSchedulingIgnoredDuringExecution,可以認爲前一種是必須滿足,如果不滿足則不進行調度,後一種是傾向滿足,不滿足的情況下會調度的不符合條件的Node上。IgnoreDuringExecution表示如果在Pod運行期間Node的標籤發生變化,導致親和性策略不能滿足,則繼續運行當前的Pod。

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/e2e-az-name
            operator: In
            values:
            - e2e-az1
            - e2e-az2
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1               //取值範圍1-100
        preference:
          matchExpressions:
          - key: another-node-label-key
            operator: In
            values:
            - another-node-label-value
  containers:
  - name: nginx
    image: docker.io/nginx

標籤判斷的操作符除了使用In之外,還可以使用NotInExistsDoesNotExistGtLt。如果指定多個nodeSelectorTerms,則只要滿足其中一個條件,就會被調度到相應的節點上。如果指定多個matchExpressions,則所有的條件都必須滿足纔會調度到對應的節點。

Pod間的親和性與反親和性 inter-pod affinity/anti-affinity

這個特性是Kubernetes 1.4後增加的,允許用戶通過已經運行的Pod上的標籤來決定調度策略,用文字描述就是“如果Node X上運行了一個或多個滿足Y條件的Pod,那麼這個Pod在Node應該運行在Pod X”,因爲Node沒有命名空間,Pod有命名空間,這樣就允許管理員在配置的時候指定這個親和性策略適用於哪個命名空間,可以通過topologyKey來指定。topology是一個範圍的概念,可以是一個Node、一個機櫃、一個機房或者是一個區域(如北美、亞洲)等,實際上對應的還是Node上的標籤。

有兩種類型

  • requiredDuringSchedulingIgnoredDuringExecution,剛性要求,必須精確匹配
  • preferredDuringSchedulingIgnoredDuringExecution,軟性要求
apiVersion: v1
kind: Pod
metadata:
  name: with-pod-affinity
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: security
            operator: In
            values:
            - S1
        topologyKey: failure-domain.beta.kubernetes.io/zone
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: security
              operator: In
              values:
              - S2
          topologyKey: kubernetes.io/hostname
  containers:
  - name: with-pod-affinity
    image: k8s.gcr.io/pause:2.0

標籤的判斷操作支持InNotInExistsDoesNotExist。 原則上topologyKey可以是節點的合法標籤,但是有一些約束:

  • 對於親和性以及RequiredDuringScheduling的反親和性,topologyKey需要指定
  • 對於RequiredDuringScheduling的反親和性,LimitPodHardAntiAffinityTopology的准入控制限制topologyKey爲kubernetes.io/hostname,可以通過修改或者disable解除該約束
  • 對於PreferredDuringScheduling的反親和性,空的topologyKey表示kubernetes.io/hostname, failure-domain.beta.kubernetes.io/zone and failure-domain.beta.kubernetes.io/region的組合.
  • topologyKey在遵循其他約束的基礎上可以設置成其他的key.

本文來自 阿僕來耶 的CSDN 博客 ,全文地址請點擊:https://blog.csdn.net/jettery/article/details/79003562?utm_source=copy

Pod間的親和性策略要求可觀的計算量可能顯著降低集羣的性能,不建議在超過100臺節點的範圍內使用。 Pod間的反親和策略要求所有的Node都有一致的標籤,例如集羣中所有節點都應有匹配topologyKey的標籤,如果一些節點缺失這些標籤可能導致異常行爲。

常用場景

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

上面的例子中,創建了一個具有三個實例的部署,採用了Pod間的反親和策略,限制創建的實例的時候,如果節點上已經存在具有相同標籤的實例,則不進行部署,避免了一個節點上部署多個相同的實例。

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

再創建3個Web服務的實例,同上面Redis的配置,首先確保兩個Web不會部署到相同的節點,然後在應用Pod間親和策略,優先在有Redis服務的節點上部署Web。

參考資料

  1. Kubernetes中的親和性
  2. Assigning Pods to Nodes
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章