Kubernetes的污點與容忍
寫在前面#
我們在使用k8s過程中經(jīng)常有這樣的需求:我的k8s集群有多臺服務器,配置不盡相同。我想把數(shù)據(jù)庫部署到CPU、內(nèi)存比較好的這幾臺機;我想把靜態(tài)承載服務部署到有固態(tài)硬盤的機器等;而這些需求,就是我們今天要講的k8s的調(diào)度:
在Kubernetes 中,調(diào)度 是指將 Pod 部署到合適的節(jié)點(node)上。
k8s的默認調(diào)度器是kube-scheduler,它執(zhí)行的是一個類似平均分配的原則,讓同一個service管控下的pod盡量分散在不同的節(jié)點。
那接下來分別說說k8s幾種不同的調(diào)度策略。
節(jié)點標簽#
在介紹調(diào)度策略之前,我們先提一句節(jié)點標簽;節(jié)點標簽關聯(lián)的指令是kubectl label
?,標簽是一種鍵值對,可以用來標識和選擇資源。例如,你需要給某個節(jié)點打個標記以便后面用得上,這個標記就叫標簽。
增加標簽
kubectl label node docker-desktop restype=strong-cpu
這里增加了一個restype=strong-cpu
的標簽,表示這個節(jié)點cpu很強;
查看標簽
kubectl get nodes --show-labelsNAME ? ? ? ? ? ? STATUS ? ROLES ? ?AGE ? ?VERSION ? LABELSdocker-desktop ? Ready ? ?<none> ? 328d ? v1.22.5 ? disktype=ssd
刪除標簽
kubectl label node docker-desktop restype-
nodeSelector-簡單的節(jié)點選擇器#
nodeSelector:在部署pod的時候告訴集群,我要部署到符合我要求的節(jié)點;
前面已經(jīng)看到我k8s的節(jié)點?docker-desktop
,已經(jīng)打了disktype=ssd
的標簽,那我們來部署一個測試的pod看看
創(chuàng)建文件:test-netcore6-dep.yaml
apiVersion: apps/v1kind: Deploymentmetadata: ?name: demoapi-net6 ?namespace: aspnetcore ?labels: ? ?name: demoapi-net6spec: ?replicas: 1 ?selector: ? ?matchLabels: ? ? ?name: demoapi-net6 ?template: ? ?metadata: ? ? ?labels: ? ? ? ?name: demoapi-net6 ? ?spec: ? ? ?containers: ? ? ?- name: demoapi-net6 ? ? ? ?image: gebiwangshushu/demoapi-net6 #這是個kong的webapi ? ? ?nodeSelector: ? ? ? ?restype: strong-cpu #我這里要求節(jié)點要有資源類型restype=strong-cpu的標簽
部署
kubectl apply -f .\test-netcore6-dep.yaml
查看pod狀態(tài)
確實處于pending狀態(tài)
kubectl get podsNAME ? ? ? ? ? ? ? ? ? ? ? ? ?READY ? STATUS ? ?RESTARTS ? AGEdemoapi-net6-c9c5cb85-rwqn2 ? 0/1 ? ? Pending ? 0 ? ? ? ? ?52m
describe一下
可以清楚看到pending原因是affinity/selector不匹配
kubectl describe pod demoapi-net6-c9c5cb85-rwqn2 ... ?Type ? ? Reason ? ? ? ? ? ?Age ? From ? ? ? ? ? ? ? Message ?---- ? ? ------ ? ? ? ? ? ?---- ?---- ? ? ? ? ? ? ? ------- ?Warning ?FailedScheduling ?32s ? default-scheduler ?0/1 nodes are available: 1 node(s) didn't match Pod's node affinity/selector.
?
給node加上strong-cpn
加上label看看
kubectl label node docker-desktop restype=strong-cpu
再看看
...Normal ? Scheduled ? ? ? ? 46s ? ?default-scheduler ?Successfully assigned aspnetcore/demoapi-net6-c9c5cb85-l7sdb to docker-desktop ?Normal ? Pulling ? ? ? ? ? 45s ? ?kubelet ? ? ? ? ? ?Pulling image "gebiwangshushu/demoapi-net6" ?#可以清楚看到已分配好node了,pod run起來了
nodeName-更粗暴的節(jié)點選擇器#
前面的nodeSelector是“我要部署到符合我要求的節(jié)點”;見名思意,nodeName是更粗暴的節(jié)點選擇器,意思是:我就要部署到這個節(jié)點!
寫法示例:
apiVersion: apps/v1kind: Deploymentmetadata: ?name: demoapi-net6 ?namespace: aspnetcore ?labels: ? ?name: demoapi-net6spec: ?replicas: 1 ?selector: ? ?matchLabels: ? ? ?name: demoapi-net6 ?template: ? ?metadata: ? ? ?labels: ? ? ? ?name: demoapi-net6 ? ?spec: ? ? ?containers: ? ? ?nodeName: docker-desktop #就要部署到這個
這種寫法簡單粗暴,一般用來測試和測試用途,一般不這么寫,因為存在比較多的局限性:
比如節(jié)點不存在或者節(jié)點名字寫錯了,部署失??;
指定的節(jié)點硬件資源不夠,比如cpu或者內(nèi)存不夠了,部署失??;
在云服務環(huán)境中,節(jié)點名字總是變化的,指定節(jié)點名沒什么意義;
affinity-節(jié)點親和性和pod反親和性#
節(jié)點親和性功能類似于?nodeSelector
?字段,但它的選擇表達能力更強,有各種各樣的規(guī)則,還有軟規(guī)則。甚至還可以有反親和性,拒絕/排斥部署到哪些節(jié)點;
nodeAffinity
--節(jié)點親和性#
節(jié)點親和性(nodeAffinity)分成兩種:
requiredDuringSchedulingIgnoredDuringExecution
: 硬策略。就是node你一定要滿足我的要求,才能執(zhí)行調(diào)度,不然pod就一直pending
;preferredDuringSchedulingIgnoredDuringExecution
: 軟策略。就是我更傾向于滿足我要去的node,如果沒有那就按默認規(guī)則調(diào)度。
示例
apiVersion: apps/v1kind: Deploymentmetadata: ?name: demoapi-net6 ?namespace: aspnetcore ?labels: ? ?name: demoapi-net6spec: ?replicas: 1 ?selector: ? ?matchLabels: ? ? ?name: demoapi-net6 ?template: ? ?metadata: ? ? ?labels: ? ? ? ?name: demoapi-net6 ? ?spec: ? ? ?containers: ? ? ?- name: demoapi-net6 ? ? ? ?image: gebiwangshushu/demoapi-net6 ? ? ?affinity: ? ? ? ?nodeAffinity: #親和性 ? ? ? ? ?requiredDuringSchedulingIgnoredDuringExecution: #硬策略 ? ? ? ? ? ?nodeSelectorTerms: ? ? ? ? ? ?- matchExpressions: #這里意思一定要restype=strong-cpu的節(jié)點 ? ? ? ? ? ? ?- key: restype ? ? ? ? ? ? ? ?operator: In ? ? ? ? ? ? ? ?values: ? ? ? ? ? ? ? ?- strong-cpu ? ? ? ? ?preferredDuringSchedulingIgnoredDuringExecution: #軟策略 ? ? ? ? ?- weight: 1 ? ? ? ? ? ?preference: ? ? ? ? ? ? ?matchExpressions: #這里意思傾向于部署到有ssd硬盤的節(jié)點 ? ? ? ? ? ? ?- key: disktype ? ? ? ? ? ? ? ?operator: In ? ? ? ? ? ? ? ?values: ? ? ? ? ? ? ? ?- ssd
affinity: 親和性
requiredDuringSchedulingIgnoredDuringExecution:硬策略
preferredDuringSchedulingIgnoredDuringExecution:軟策略
nodeSelectorTerms:節(jié)點選擇項,數(shù)組
matchExpressions:匹配表達式,數(shù)組
weight:?preferredDuringSchedulingIgnoredDuringExecution
?可設置的權重字段,值范圍是 1 到 100。 會計算到調(diào)度打分算法上,分數(shù)高的優(yōu)先級高;
operator:邏輯操作符,比如這里的in表示包含,一共有以下邏輯運算符;
?- In:label 的值在某個列表中 ?- NotIn:label 的值不在某個列表中 ?- Gt:label 的值大于某個值 ?- Lt:label 的值小于某個值 ?- Exists:某個 label 存在 ?- DoesNotExist:某個 label 不存在 ? ?#可用NotIn和DoesNotExist實現(xiàn)反親和性;
匹配規(guī)則:
如果你同時指定了?nodeSelector
?和?nodeAffinity
,兩者?必須都要滿足, 才能將 Pod 調(diào)度到候選節(jié)點上。
如果你在與 nodeAffinity 類型關聯(lián)的 nodeSelectorTerms 中指定多個條件, 只要其中一個?nodeSelectorTerms
?滿足,Pod 就可以被調(diào)度到節(jié)點上。
如果你在與?nodeSelectorTerms
的一個?matchExpressions
?中寫個表達式, 則只有當所有表達式都滿足,Pod 才能被調(diào)度到節(jié)點上。
pod間的親和反親和性#
前面的節(jié)點親和性是通過pod和節(jié)點之間的標簽進行匹配,選擇的;
pod的親和性和反親和性調(diào)度指:通過已在運行中的pod標簽進行選擇調(diào)度部署的節(jié)點;
pod的親和性調(diào)度:一個典型的使用場景就是在集群環(huán)境是有多數(shù)據(jù)中心的,那一個服務部署已經(jīng)部署到廣東了,那我跟他相關的需要大量通信的其他服務也盡量部署到廣東,降低彼此間的通信延遲;
pod的反親和性調(diào)度:一個典型的使用場景就是我的服務要盡可能分散到各個數(shù)據(jù)中心、區(qū)域,比如廣東、西安、上海、北京,都要有我的服務,避免某個數(shù)據(jù)中心故障服務全部宕機;
示例
apiVersion: apps/v1kind: Deploymentmetadata: ?name: demoapi-net6 ?namespace: aspnetcore ?labels: ? ?name: demoapi-net6spec: ?replicas: 1 ?selector: ? ?matchLabels: ? ? ?name: demoapi-net6 ?template: ? ?metadata: ? ? ?labels: ? ? ? ?name: demoapi-net6 ? ?spec: ? ? ?containers: ? ? ?- name: demoapi-net6 ? ? ? ?image: gebiwangshushu/demoapi-net6 ? ? ? ? ? ?affinity: ? ? ? ?podAffinity: #pod親和性 ? ? ? ? ?requiredDuringSchedulingIgnoredDuringExecution: ? ? ? ? ?- labelSelector: ? ? ? ? ? ? ?matchExpressions: ? ? ? ? ? ? ?- key: restype ? ? ? ? ? ? ? ?operator: In ? ? ? ? ? ? ? ?values: ? ? ? ? ? ? ? ?- strong-cpu ? ? ? ? ? ?topologyKey: topology.kubernetes.io/zone #topology.kubernetes.io/hostname 表示同一節(jié)點 ? ? ? ?podAntiAffinity: #pod間反親和性 ? ? ? ? ?preferredDuringSchedulingIgnoredDuringExecution: ? ? ? ? ?- weight: 100 ? ? ? ? ? ?podAffinityTerm: ? ? ? ? ? ? ?labelSelector: ? ? ? ? ? ? ? ?matchExpressions: ? ? ? ? ? ? ? ?- key: disktype ? ? ? ? ? ? ? ? ?operator: In ? ? ? ? ? ? ? ? ?values: ? ? ? ? ? ? ? ? ?- ssd ? ? ? ? ? ? ?topologyKey: topology.kubernetes.io/zone
親和性規(guī)則表示:當且僅當至少一個已運行且有?restype=strong-cpu
?的標簽的 Pod 處于同一區(qū)域時(topology.kubernetes.io/zone=GuangDong),才可以將該 Pod 調(diào)度到節(jié)點上。
反親和性規(guī)則表示:如果節(jié)點處于 Pod 所在的同一可用區(qū)(也是看topology.kubernetes.io/zone)且至少一個 Pod 具有?disktype=ssd
?標簽,則該 Pod 不應被調(diào)度到該節(jié)點上。
PS:Pod 間親和性和反親和性都需要一定的計算量,因此會在大規(guī)模集群中顯著降低調(diào)度速度(比如上百個節(jié)點上千上萬的pod),影響性能;
這塊我也用的不多,就寫到這里;
taint + tolerations -污點與容忍度調(diào)度#
nodeSelector/nodeName和節(jié)點親和性都是pod的一種屬性,它可以主動選擇某些節(jié)點。但如果Node想排他性地部署呢?答案就是污點+容忍的調(diào)度;
名稱理解#
taint-污點:污點是節(jié)點用來排斥pod的一組標簽,比如設置一個weak-cpu
的污點;當然你也可以設置strong-cpu
這種“污點”;
toleration-容忍:容忍是pod用來容忍,接收節(jié)點污點的,比如給pod一個weak-cpu
的容忍,這樣它就可以被調(diào)度到weak-cpu
的節(jié)點上了;
taint-污點#
新增污點#
語法
kubectl taint NODE NAME key1=value1:EFFECT(容忍的效果)
示例
kubectl taint nodes docker-desktop restype=strong-cpu:NoSchedule
EFFECT取值
PreferNoSchedule:?盡量不要調(diào)度。
NoSchedule:?一定不能被調(diào)度。
NoExecute:?不僅不會調(diào)度, 還會驅(qū)逐 Node 上已有的 Pod。
我們這時候再看看可以明顯看到pod是pending狀態(tài)
Warning ?FailedScheduling ?12s ? default-scheduler ?0/1 nodes are available: 1 node(s) had taint {restype: strong-cpu}, that the pod didn't tolerate.
查看污點#
kubectl describe ?node docker-desktop|grep Taints
刪除污點#
kubectl taint node restype-
tolerations-容忍#
apiVersion: apps/v1kind: Deploymentmetadata: ?name: demoapi-net6 ?namespace: aspnetcore ?labels: ? ?name: demoapi-net6spec: ? ?spec: ? ? ?containers: ? ? ?- name: demoapi-net6 ? ? ? ?image: gebiwangshushu/demoapi-net6 ? ? ? ? ? ?tolerations: #添加容忍 ? ? ?- key: "restype" ? ? ? ?operator: "Equal" ? ? ? ?value: "strong-cpu" ? ? ? ?effect: "NoSchedule"
這里表示容忍restype=strong-cpu
tolerations有兩種寫法#
寫法1、operator="Equal"
tolerations: - key: "restype" ?operator: "Equal" ?value: "strong-cpu" ?effect: "NoSchedule"
這種寫法時,key、value跟effect都要跟taint的一致;
寫法2、operator="Exists"
tolerations:- key: "restype" ?operator: "Exists" ?effect: "NoSchedule"
這種寫法時,key、effect 跟taint的要一致,且不能寫value的值;
tolerationSeconds-容忍時間#
容忍時間是指:以指定當節(jié)點失效時, Pod 依舊不被驅(qū)逐的時間。
示例
tolerations:- key: "node.kubernetes.io/unreachable" ?operator: "Exists" ?effect: "NoExecute" ?tolerationSeconds: 6000 #單位(秒)
node.kubernetes.io/unreachable
是k8s內(nèi)置的污點,功能是讓節(jié)點網(wǎng)絡不可用時pod自動驅(qū)逐;這里tolerationSeconds: 6000,意思是網(wǎng)絡不可用6000秒后,才開始驅(qū)逐;
說明
Kubernetes 會自動給 Pod 添加針對?node.kubernetes.io/not-ready
?和?node.kubernetes.io/unreachable
?的容忍度,且配置?tolerationSeconds=300
, 除非用戶自身或者某控制器顯式設置此容忍度。
這些自動添加的容忍度意味著 Pod 可以在檢測到對應的問題之一時,在 5 分鐘內(nèi)保持綁定在該節(jié)點上。
其他規(guī)則
DaemonSet?中的 Pod 被創(chuàng)建時, 針對以下污點自動添加的?NoExecute
?的容忍度將不會指定?tolerationSeconds
:
node.kubernetes.io/unreachable
node.kubernetes.io/not-ready
容忍規(guī)則#
1、operator="Exists"且key為空,表示這個容忍度與任意的 key、value 和 effect 都匹配,即這個容忍度能容忍任何污點。
tolerations:- operator: "Exists"
2、如果?effect
?為空,,那么將匹配所有與 key 相同的 effect。
tolerations:- key: "key" ?operator: "Exists"
3、一個 node 可以有多個污點,一個 pod 可以有多個容忍。
4、pod如果需要調(diào)度到某個node,需要容忍該node的所有污點;
5、pod如果需要調(diào)度到某個node,但沒有容忍該node的所有污點,且剩下的污點effect 均為?PreferNoSchedule
,那存在調(diào)度的可能;
6、如果 Node 上帶有污點 effect 為?NoExecute
,這個已經(jīng)在 Node 上運行的 、不容忍該污點的Pod 會從 Node 上驅(qū)逐掉(調(diào)度到其他node);
7、當集群只有一個 node 節(jié)點時,無法做到 Pod 遷移(主要是驅(qū)逐),因為 Pod 已經(jīng)無路可退了。
總結(jié)#
總的來說k8s中Node&Pod的調(diào)度策略還是比較實用,常用的需求,學學防身沒毛??;