Kubernetes之Pod排程

店家小二發表於2018-12-14

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更好的服務於我們的需求。

本文轉自中文社群-Kubernetes之Pod排程


相關文章