1. 程式人生 > >Kubernetes之Pod排程_Kubernetes中文社群

Kubernetes之Pod排程_Kubernetes中文社群

【編者的話】Kubernetes排程器根據特定的演算法與策略將pod排程到工作節點上。在預設情況下,Kubernetes排程器可以滿足絕大多數需求,例如排程pod到資源充足的節點上執行,或排程pod分散到不同節點使叢集節點資源均衡等。但一些特殊的場景,預設排程演算法策略並不能滿足實際需求,例如使用者期望按需將某些pod排程到特定硬體節點(資料庫服務部署到SSD硬碟機器、CPU/記憶體密集型服務部署到高配CPU/記憶體伺服器),或就近部署互動頻繁的pod(例如同一機器、同一機房、或同一網段等)。

Kubernetes中的排程策略主要分為全域性排程與執行時排程2種。其中全域性排程策略在排程器啟動時配置,而執行時排程策略主要包括選擇節點(nodeSelector),節點親和性(nodeAffinity),pod親和與反親和性(podAffinity與podAntiAffinity)。Node Affinity、podAffinity/AntiAffinity以及後文即將介紹的汙點(Taints)與容忍(tolerations)等特性,在Kuberntes1.6中均處於Beta階段。

本文著重介紹執行時排程策略。

設定節點label

Label是Kubernetes核心概念之一,其以key/value的形式附加到各種物件上,如Pod、Service、Deployment、Node等,達到識別這些物件,管理關聯關係等目的,如Node和Pod的關聯。
獲取當前叢集中的全部節點:

kubectl get nodes

為指定節點設定label:

kubectl label nodes <node-name> <label-key>=<label-value>

確認節點label是否設定成功:

kubectl get nodes -l ‘label_key=label_value’

選擇節點(nodeSelector)

nodeSelector是目前最為簡單的一種pod執行時排程限制,目前在Kubernetes1.7.x及以下版本可用。Pod.spec.nodeSelector通過kubernetes的label-selector機制選擇節點,由排程器排程策略匹配label,而後排程pod到目標節點,該匹配規則屬於強制約束。後文要講的nodeAffinity具備nodeSelector的全部功能,所以未來Kubernetes會將nodeSelector廢除。

nodeSelector舉例:

設定label

$ kubectl label nodes bjo-rpt-re-002.dev.fwmrm.net disktype=ssd
node "bjo-rpt-re-002.dev.fwmrm.net" labeled

檢視滿足非master節點且disktype型別為ssd的節點:

kubectl get nodes -l 'role!=master, disktype=ssd'
NAME                           STATUS    AGE       VERSION
bjo-rpt-re-002.dev.fwmrm.net   Ready     39d       v1.7.1

pod.yaml檔案內容:

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

建立pod:

kubectl create -f pod.yaml

檢視pod nginx被排程到預期節點執行:

$ kubectl get po nginx -o wide
NAME      READY     STATUS    RESTARTS   AGE       IP            NODE
nginx     1/1       Running   0          10s       10.244.3.13   bjo-rpt-re-002.dev.fwmrm.net

注:如果非預設namespace,需要指定具體namespace,例如:

kubectl -n kube-system get pods -o wide

內建節點label

Kubernetes自v1.4開始,節點有一些built-in label,羅列如下:

  • 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
built-in label舉例

yaml檔案內容:

apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
nodeSelector:
kubernetes.io/hostname: bjo-ep-svc-017.dev.fwmrm.net

建立pod,並檢查結果符合預期,pod被排程在預先設定的節點 bjo-ep-svc-017.dev.fwmrm.net:

$ kubectl get po nginx -o wide
NAME      READY     STATUS    RESTARTS   AGE       IP            NODE
nginx     1/1       Running   0          3m        10.244.1.58   bjo-ep-svc-017.dev.fwmrm.net

親和性(Affinity)與非親和性(anti-affinity)

前面提及的nodeSelector,其僅以一種非常簡單的方式、即label強制限制pod排程到指定節點。而親和性(Affinity)與非親和性(anti-affinity)則更加靈活的指定pod排程到預期節點上,相比nodeSelector,Affinity與anti-affinity優勢體現在:

  • 表述語法更加多樣化,不再僅受限於強制約束與匹配。
  • 排程規則不再是強制約束(hard),取而代之的是軟限(soft)或偏好(preference)。
  • 指定pod可以和哪些pod部署在同一個/不同拓撲結構下。

親和性主要分為3種類型:node affinity與inter-pod affinity/anti-affinity,下文會進行詳細說明。

節點親和性(Node affinity)

Node affinity在Kubernetes 1.2做為alpha引入,其涵蓋了nodeSelector功能,主要分為requiredDuringSchedulingIgnoredDuringExecution與preferredDuringSchedulingIgnoredDuringExecution 2種類型。前者可認為一種強制限制,如果 Node 的標籤發生了變化導致其沒有符合 Pod 的排程要求節點,那麼pod排程就會失敗。而後者可認為理解為軟限或偏好,同樣如果 Node 的標籤發生了變化導致其不再符合 pod 的排程要求,pod 依然會排程執行。

Node affinity舉例

設定節點label:

$ kubectl label nodes bjo-ep-dep-040.dev.fwmrm.net cpu=high
node "bjo-ep-dep-040.dev.fwmrm.net" labeled

$  kubectl label nodes bjo-ep-svc-017.dev.fwmrm.net cpu=mid
node "bjo-ep-svc-017.dev.fwmrm.net" labeled

$  kubectl label nodes bjo-rpt-re-002.dev.fwmrm.net cpu=low
node "bjo-rpt-re-002.dev.fwmrm.net" labeled

部署pod的預期是到非master節點(role!=master)、且CPU高配的機器上(cpu=high)。
檢視滿足條件節點:

$ kubectl get nodes -l 'cpu=high, role!=master'
NAME                           STATUS    AGE       VERSION
bjo-ep-dep-040.dev.fwmrm.net   Ready     41d       v1.7.1

pod.yaml檔案內容如下:

apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
affinity:
nodeAffinity:
  requiredDuringSchedulingIgnoredDuringExecution:
    nodeSelectorTerms:
    - matchExpressions:
      - key: role
        operator: NotIn
        values:
        - master
  preferredDuringSchedulingIgnoredDuringExecution:
  - weight: 1
    preference:
      matchExpressions:
      - key: cpu
        operator: In
        values:
        - high
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent

檢查結果符合預期,pod nginx成功部署到非master節點且CPU高配的機器上。

$ kubectl get po  nginx -o wide
NAME      READY     STATUS    RESTARTS   AGE       IP             NODE
nginx     1/1       Running   0          32s       10.244.2.185   bjo-ep-dep-040.dev.fwmrm.net

pod親和性(Inter-pod affinity)與反親和性(anti-affinity)

inter-pod affinity與anti-affinity由Kubernetes 1.4引入,當前處於beta階段,其中podAffinity用於排程pod可以和哪些pod部署在同一拓撲結構之下。而podAntiAffinity相反,其用於規定pod不可以和哪些pod部署在同一拓撲結構下。通過pod affinity與anti-affinity來解決pod和pod之間的關係。
與Node affinity類似,pod affinity與anti-affinity同樣分為requiredDuringSchedulingIgnoredDuringExecution and preferredDuringSchedulingIgnoredDuringExecution等2種類型,前者被認為是強制約束,而後者後者可認為理解軟限(soft)或偏好(preference)。

pod affinity與anti-affinity舉例

本示例中假設部署場景為:期望is服務與oltp服務就近部署,而不希望與solr服務部署同一拓撲結構上。
yaml檔案部分內容:

spec:
replicas: 1
template:
metadata:
  labels:
    app: is

spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: NotIn
            values:
            - solr
        topologyKey: kubernetes.io/hostname
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: app
              operator: In
              values:
              - oltp
          topologyKey: beta.kubernetes.io/os

檢視部署結果,is服務與oltp部署到了同一臺機器,而solr被部署在其他機器上。

$ kubectl get po -o wide
NAME                           READY     STATUS    RESTARTS   AGE       IP             NODE
is-3059482752-5s14t            0/1       Running   1          1m        10.244.1.60    bjo-ep-svc-017.dev.fwmrm.net
oltp-282283610-kdvnp           1/1       Running   0          1m        10.244.1.53    bjo-ep-svc-017.dev.fwmrm.net
solr-908150957-rswlm           1/1       Running   0          1m        10.244.3.5     bjo-rpt-re-002.dev.fwmrm.net

親和性/反親和性排程策略比較

排程策略         匹配標籤 操作符                拓撲域支援  排程目標
nodeAffinity    主機    In, NotIn, Exists,   否         pod到指定主機
                       DoesNotExist, Gt, Lt  
podAffinity     Pod    In, NotIn, Exists,   是         pod與指定pod同一拓撲域
                       DoesNotExist            
PodAntiAffinity Pod    In, NotIn, Exists,   是         pod與指定pod非同一拓撲域
                       DoesNotExist            

汙點(Taints)與容忍(tolerations)

對於Node affinity,無論是強制約束(hard)或偏好(preference)方式,都是排程pod到預期節點上,而Taints恰好與之相反,如果一個節點標記為 Taints ,除非 Pod也被標識為可以耐受汙點節點,否則該Taints節點不會被排程pod。Taints)與tolerations當前處於beta階段,
Taints節點應用場景比如使用者希望把Kubernetes Master節點保留給 Kubernetes 系統元件使用,或者把一組具有特殊資源預留給某些 pod。pod不會再被排程到taint標記過的節點。

taint標記節點舉例如下:
$ kubectl taint nodes bjo-ep-dep-039.dev.fwmrm.net key=value:NoSchedule
node "bjo-ep-dep-039.dev.fwmrm.net" tainted

如果仍然希望某個pod排程到taint節點上,則必須在 Spec 中做出Toleration 定義,才能排程到該節點,舉例如下:

tolerations:
- key: "key"
operator: "Equal"
value: "value"
effect: "NoSchedule"

effect 共有三個可選項,可按實際需求進行設定:

  • NoSchedule:pod不會被排程到標記為taints節點。
  • PreferNoSchedule:NoSchedule的“preference”或“soft”版本。
  •  NoExecute:該選項意味著一旦Taint 生效,如該節點內正在執行的 Pod 沒有對應 Tolerate 設定,會直接被逐出。

總結

使用者可根據實際需求,充分利用pod的相關高階排程策略,使Kubernetes更好的服務於我們的需求。

參考文件

歡迎轉載,請註明作者出處:張夏,FreeWheel Lead Engineer,Kubernetes中文社群