1. 程式人生 > 其它 >8.k8s叢集排程

8.k8s叢集排程

一、節點親和性

pod_spec.nodeAffinity

  • preferredDuringSchedulingIgnoredDuringExecution: 軟策略
  • requiredDuringSchedulingIgnoredDuringExecution: 硬策略

requiredDuringSchedulingIgnoredDuringExecution

apiVersion: v1
kind: Pod
metadata:
  name: affinity
  labels:
    app: node-affinity-pod
spec:
  containers:
  - name: with-node-affinity
    image: nginx
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/hostname
            operator: NotIn
            values:
            - k8s-node2

preferredDuringSchedulinglgnoredDuringExecution

apiVersion: v1
kind: Pod
metadata:
  name: affinity1
  labels:
    app: node-affinity-pod
spec:
  containers:
  - name: with-node-affinity
    image: nginx
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: source
            operator: In
            values:
            - k8s-node1
  

合體

apiVersion: v1
kind: Pod
metadata:
  name: affinity
  labels:
    app: node-affinity-pod
spec:
  containers:
  - name: with-node-affinity
    image: nginx
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: kunernetes.io/hostname
            operator; NotIn
            values:
            - k8s-node2
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: source
            operator: In
            values:
            - qikqiak

鍵值運算關係

  • In:label 的值在某個列表中
  • NotIn:label的值不在某個列表中
  • Gt:label的值大於某個值
  • It:label的值小於某個值
  • Exists: 某個label存在
  • DoesNotExist: 某個label不存在

注意:如果nodeSelectorTerms下面有多個選項的話,滿足任何一個條件就可以了; 如果matchExpressions有多個選項的話,則必須同時滿足這些條件才能正常排程 POD

Pod親和性

pod.spec.affinity.podAffinity/podAntiAffinity

  • preferredDuringSchedulingIgnoredDuringExecution: 軟策略
  • requiredDuringSchedulingIgnoredDuringExecution: 硬策略
apiVersion: v1
kind: Pod
metadata:
  name: pod-3
  labels:
    app: pod-3
spec:
  containers:
  - name: pod-3
    image: nginx
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - pod-1
        topologyKey: kubernetes.io/hostname
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: app
              perator: In
              values:
              - pod-2
        topologyKey: kubernetes.io/hostname
      

親和性、反親和性排程策略比較如下:

排程策略 匹配標籤 操作符 拓撲域支援 排程目標
nodeAffinity 主機 In,NotIn,Exists,DoesNotExist,Gt,Lt 指定主機
podAffinity POD In,NotIn,Exists,DoesNotExist POD與指定POD同一拓撲域
podAnitAffinity POD In,NotIn,Exists,DoesNotExist POD與指定POD不在同一拓撲域

二、汙點和容忍

Taint和Toleration

節點親和性,是pod的一種屬(偏好或硬性要求),它邊pod被吸引到一類特定的節點。Taint則相反,它便節點 能夠排斥一類特定的pod

Taint和toeration相互配合 , 可以用來避免pod被分配到不合適的節點上, 每個節點上都可以應用一個或多個taint, 這表示對於那些不能容忍這些taint的pod , 是不會被該節點接受的 , 如果將toleration應用於pod上, 則表示這些pod可以(但不要求)被排程到具有匹配taint的節點上

如果你能容忍這個汙點,代表你兩能發生故事 。

汙點(Taint)

1.汙點(Taint)的組成

使用kubectl taint 命令可以給某個Node節點設定汙點, Node被設定上汙點之後就和Pod之間存在了一種相斥的關係 , 可以讓Node拒絕Pod的排程執行 , 甚至將Node已經存在的Pod驅逐出去

每個汙點的組成如下:

key=value:effect

每個汙點有一個key和value作為汙點的標籤, 其中value可以為空, effect描述汙點的作用 。當前taint effect支援如下三個選項

  • NoSchedule: 表示k8s將不會將Pod排程到具有該汙點的Node上
  • PreferNoSchedule: 表示k8s將盡量避免將Pod排程到具有該汙點的Node上
  • NoExecute: 表示k8s將不會將Pod排程到具有該汙點的Node上, 同時會將Node上已經存在的Pod驅逐出去 。

2.汙點的設定, 檢視和去除

#設定汙點
kubectl taint nodes node1 key1=value1:NoSchedule
kubectl taint nodes k8s-master03 check=haha:NoExecute

#節點說明中, 查詢Taints欄位
#檢視汙點
kubectl describe nodes 節點名稱
kubectl describe nodes k8s-master03

#去除汙點
kubectl taint nodes node1 key1:NoSchedule-
kubectl taint nodes k8s-master03 check:NoExecute-

容忍(Tolerations)

設定了汙點的Node將根據taint的effect: NoSchedule, PreferNoSchedule, NoExecute和Pod之間產生互斥的關係 , Pod將在一定程度上不會被排程到Node上 。 但我們可以在Pod上設定容忍(Toleration),意思是設定了容忍的Pod將可以容忍汙點的存在 , 可以排程到存在汙點的Node上

pod.spec.tolerations

tolerations:
- key: "key1"
  operator: "Equa1"
  value: "value1"
  effect: "NoSchedule"
  tolerationSeconds: 3600
- key: "key1"
  operator: "Equa1"
  value: "value1"
  effect: "NoExecute"
- key: "key2"
  operator: "Exists"
  effect: "NoSchedule"
  • 其中key,value,effect要與Node上設定的taint保持一致
  • operator的值為Exists將會忽略value值
  • tolerationSeconds用於描述當Pod需要被驅逐時可以在Pod上繼續保留執行的時間

1.當不指定key值時 , 表示容忍所有的汙點key:

tolerations:
- operator: "Exists"

2.當不指定effect值時 , 表示容忍所有的汙點作用

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

3.有多個Master存在時 , 防止資源浪費, 可以如下設定

kubectl taint nodes Node-Name node-role.kubernetes.io/master=:PreferNoSchedule

三、固定節點排程

1.Pod.spec.nodeName將Pod直接排程到指定的Node節點上, 會跳過Scheduler的排程策略, 該匹配規則是強制匹配

apiVersion:  apps/v1
kind: Deployment
metadata:
  name: myweb
spec:
  replicas: 7
  selector:
        matchLabels:
          app: myweb
  template:
    metadata:
      labels:
        app: myweb
    spec:
      nodeName: k8s-master01
      containers:
      - name: myweb
        image: nginx
        ports:
        - containerPort: 80

2.Pod.spec.nodeSelector: 通過kubernetes的label-selector機制選擇節點, 由排程器排程策略匹配label, 而後排程pod到目標節點, 該匹配規則屬於強制約束

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: myweb
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: myweb
    spec:
      nodeSelector
        disk: ssd
      containers:
      - name: myweb
        image: nginx
        ports:
        - containerPort: 80

打標籤在k8s-master02上打標籤

kubectl label node k8s-master02 disk=ssd
kubectl get nodes --show-labels 

為k8s-master01增加標籤

kubectl label node k8s-master01 disk=ssd

修改deployment副本數

kubectl edit deployment myweb

四、排程過程說明

簡介

Scheduler是kubernetes的排程器 , 主要的任務是把定義的pod分配到叢集的節點上 , 聽起來非常簡單 ,但有很多要考慮的問題:

  • 公平: 如何保證每個節點都能被分配資源
  • 資源高效利用:叢集所有資源最大化被使用
  • 效率:排程的效能要好, 能夠儘快地對大批量的pod完成排程工作
  • 靈活:允許使用者根據自己的需求控制排程的邏輯

Sheduler是作為單獨的程式執行的 , 啟動之後會一直堅挺API Server, 獲取PodSpec.NodeName為空的pod,對每個pod都會建立一個binding,表明該pod應該放到哪個節點上

排程過程

排程分為幾個部分: 首先是過濾不滿足條件的節點, 這個過程稱為predicate;然後對通過的節點按照優先順序排序, 這個是priority;最後從中選擇優先順序最高的節點。 如果中間任何一步驟有錯誤, 就直接返回錯誤

Predicate有一系列的演算法可以使用:

  • PodFitsResources: 節點上剩餘的資源是否大於pod請求的資源
  • PodFitsHost: 如果pod指定了NodeName, 檢查節點名稱是否和NodeName匹配
  • PodFitsHostPorts:節點上已經使用的port是否和pod申請的port衝突
  • PodSelectorMatches:過濾掉和pod指定的label不匹配的節點
  • NoDiskConflict:已經mount的volume和pod指定的volume不衝突, 除非它們都是隻讀

如果在predicate過程中沒有合適的節點, pod會一直在pending狀態, 不斷重試排程, 直到有節點滿足掉件。 經過這個步驟, 如果有多個節點滿足條件, 就繼續priorities過程;按照優先順序大小對節點排序

優先順序由一系列鍵值對組成, 鍵是該優先順序頂的名稱, 值是它的權重(該項的重要性)。 這些優先順序選項包括:

  • LeastRequestedPriority: 通過計算CPU和Memory的使用率來決定權重, 使用率越低權重越高。 換句話說, 這個優先順序指標傾向於資源使用比例更低的節點
  • BalancedResourceAllocation:節點上CPU和Memory使用率越接近, 權重越高 。 這個應該和上面的一起使用, 不應該單獨使用。
  • ImageLocalityPriority:傾向於已經有要使用映象的節點, 映象總大小值越大, 權重越高通過演算法對所有的優先順序專案和權重進行計算, 得出最終的結果

自定義排程器

除了kubernetes自帶的排程器, 你也可以編寫自己的排程器 。 通過spec:schedlername引數指定排程器的名字, 可以為pod選擇某個排程器進行排程。 比如下面的pod選擇my-scheduler進行排程, 而不是預設的default-scheduler:

apiVersion: v1
kind: Pod
metadata:
  name: annotation-second-scheduler
  labels:
    name: multischeduler-example
spec:
  schedulername: my-scheduler
  containers:
  - name: pod-with-second-annotation-container
    image: nginx