污點(diǎn) 節(jié)點(diǎn)親和性 容忍度
污點(diǎn)是K8s高級(jí)調(diào)度的特性,用于限制哪些Pod可以被調(diào)度到某一個(gè)節(jié)點(diǎn)。在普通節(jié)點(diǎn)橫向時(shí)我們可以使用污點(diǎn)容忍度創(chuàng)建惡意pod來(lái)對(duì)主節(jié)點(diǎn)進(jìn)行橫向控制。
1、kube-scheduler調(diào)度
kube-scheduler是Kubernetes 集群的默認(rèn)調(diào)度器,并且是集群控制面(master)的一部分。對(duì)每一個(gè)新創(chuàng)建的Pod或者是未被調(diào)度的Pod,kube-scheduler會(huì)選擇一個(gè)最優(yōu)的Node去運(yùn)行這個(gè)Pod。
然而,Pod內(nèi)的每一個(gè)容器對(duì)資源都有不同的需求,而且Pod本身也有不同的資源需求。因此,Pod在被調(diào)度到Node上之前,根據(jù)這些特定的資源調(diào)度需求,需要對(duì)集群中的Node進(jìn)行一次過(guò)濾。
如下為在創(chuàng)建pod的流程中,調(diào)度器的作用:
當(dāng)創(chuàng)建pod時(shí)候,會(huì)首先把創(chuàng)建的命令請(qǐng)求提交給apiserver,通過(guò)一系列認(rèn)證授權(quán),apiserver把pod數(shù)據(jù)存儲(chǔ)到etcd,創(chuàng)建deployment資源并初始化。然后再是scheduler通過(guò)進(jìn)行l(wèi)ist-watch機(jī)制進(jìn)行監(jiān)測(cè),經(jīng)過(guò)調(diào)度算法把pod調(diào)度到某個(gè)node節(jié)點(diǎn)上,最后信息更新到etcd,再后面就是kubelet接受信息到創(chuàng)建容器。

2、哪些因素影響調(diào)度
1.pod資源限制
當(dāng)前調(diào)度器選擇適當(dāng)?shù)墓?jié)點(diǎn)時(shí),調(diào)度程序會(huì)檢查每個(gè)節(jié)點(diǎn)是否有足夠的資源滿足 Pod 調(diào)度,比如查看CPU和內(nèi)存限制是否滿足:

通過(guò)資源限制調(diào)度程序可確保由于過(guò)多 Pod 競(jìng)爭(zhēng)消耗節(jié)點(diǎn)所有可用資源,從而導(dǎo)致節(jié)點(diǎn)資源耗盡引起其他系統(tǒng)異常。
2.節(jié)點(diǎn)選擇器nodeSelector
在創(chuàng)建pod的時(shí)候,節(jié)點(diǎn)選擇器可以約束pod在特定節(jié)點(diǎn)上運(yùn)行。
nodeSelector 也是節(jié)點(diǎn)選擇約束的最簡(jiǎn)單推薦形式,nodeSelector 字段添加到 Pod 的規(guī)約中設(shè)置希望目標(biāo)節(jié)點(diǎn)所具有的節(jié)點(diǎn)標(biāo)簽。 K8s 只會(huì)將 Pod 調(diào)度到擁有你所指定的每個(gè)標(biāo)簽的節(jié)點(diǎn)上。

例子, 比如多個(gè)節(jié)點(diǎn)需要調(diào)度時(shí)候,通過(guò)給1,2節(jié)點(diǎn)打上標(biāo)簽,創(chuàng)建pod時(shí)候使用節(jié)點(diǎn)選擇器,那么pod會(huì)被按照節(jié)點(diǎn)選擇器希望的目標(biāo)在相應(yīng)節(jié)點(diǎn)調(diào)度。

為節(jié)點(diǎn)打上標(biāo)簽:
kubectl label node nodename env_role=env

查看節(jié)點(diǎn)的標(biāo)簽:
kubectl get nodes nodename --show-labels

3.節(jié)點(diǎn)親和性nodeAffinity
節(jié)點(diǎn)親和性概念上類似于 nodeSelector, 它使可以根據(jù)節(jié)點(diǎn)上的標(biāo)簽來(lái)約束 Pod 可以調(diào)度到哪些節(jié)點(diǎn)上,這種方法比上面的nodeSelector更加靈活,它可以進(jìn)行一些簡(jiǎn)單的邏輯組合了,不只是簡(jiǎn)單的相等匹配。

節(jié)點(diǎn)親和性和節(jié)點(diǎn)選擇器相比功能更強(qiáng)大,比如還是剛才的圖,如果我使用節(jié)點(diǎn)選擇器env_role:dev1的話是找不到相應(yīng)的節(jié)點(diǎn)的,就沒(méi)有辦法調(diào)度,會(huì)一直是一個(gè)等待的狀態(tài):

但我如果使用節(jié)點(diǎn)親和性,就算當(dāng)前沒(méi)有這個(gè)節(jié)點(diǎn),我還是可以根據(jù)調(diào)度調(diào)度策略進(jìn)行調(diào)度,不只是簡(jiǎn)單的相等匹配。
調(diào)度策略
調(diào)度可以分成軟策略(軟親和性)和硬策略(硬親和性)兩種方式:
軟親和性(
preferredDuringSchedulingIgnoredDuringExecution)就是如果你沒(méi)有滿足調(diào)度要求的節(jié)點(diǎn)的話,POD 就會(huì)忽略這條規(guī)則,繼續(xù)完成調(diào)度過(guò)程,說(shuō)白了就是滿足條件最好了,沒(méi)有的話也無(wú)所謂了的策略;硬親和性(
requiredDuringSchedulingIgnoredDuringExecution)表示當(dāng)前的條件必須滿足,如果沒(méi)有滿足條件的節(jié)點(diǎn)的話,就不斷重試直到滿足條件為止,簡(jiǎn)單說(shuō)就是你必須滿足我的要求,不然我就不干的策略。
如圖可以看到軟親和性和硬親和性的字段其實(shí)差不多,軟親和性多了一個(gè)weight字段,表權(quán)重:

親和性操作符
如上親和性還有一個(gè)字段是operator表匹配的邏輯操作符,可以使用descirbe命令查看具體的調(diào)度情況是否滿足我們的要求,K8s提供的操作符有下面的幾種:
- In:label 的值在某個(gè)列表中
- NotIn:label 的值不在某個(gè)列表中
- Gt:label 的值大于某個(gè)值
- Lt:label 的值小于某個(gè)值
- Exists:某個(gè) label 存在
- DoesNotExist:某個(gè) label 不存在
如果nodeSelectorTerms下面有多個(gè)選項(xiàng)的話,滿足任何一個(gè)條件就可以了;如果matchExpressions有多個(gè)選項(xiàng)的話,則必須同時(shí)滿足這些條件才能正常調(diào)度 POD。

污點(diǎn)(Taints)與容忍(tolerations)
容忍度(Toleration)是應(yīng)用于 Pod 上的,允許(但并不要求)Pod 調(diào)度到帶有與之匹配的污點(diǎn)的節(jié)點(diǎn)上。污點(diǎn)說(shuō)白了就是不做普通的調(diào)度。
對(duì)于節(jié)點(diǎn)親和性無(wú)論是軟親和性和硬親和性,都是調(diào)度 POD 到預(yù)期節(jié)點(diǎn)上,而污點(diǎn)(Taints)恰好與之相反,如果一個(gè)節(jié)點(diǎn)標(biāo)記為 Taints,除非 POD 也被標(biāo)識(shí)為可以容忍污點(diǎn)節(jié)點(diǎn),否則該 Taints 節(jié)點(diǎn)不會(huì)被調(diào)度pod。
污點(diǎn)(Taints)
查看污點(diǎn)情況:
kubectl describe node nodename | grep Taint

可以看到,默認(rèn)污點(diǎn)也只有master有。
污點(diǎn)里的值有三種:
-
NoSchedule:POD 不會(huì)被調(diào)度到標(biāo)記為 taints 節(jié)點(diǎn)。 -
PreferNoSchedule:NoSchedule 的軟策略版本。 -
NoExecute:該選項(xiàng)意味著一旦 Taint 生效,如該節(jié)點(diǎn)內(nèi)正在運(yùn)行的 POD 沒(méi)有對(duì)應(yīng) Tolerate 設(shè)置,會(huì)直接被逐出。
NoSchedule就是字面意思,不會(huì)被調(diào)度,PreferNoSchedule說(shuō)白了是盡量不被調(diào)度,NoExecute是不會(huì)調(diào)度并且還會(huì)驅(qū)逐node已有的pod。
創(chuàng)建一個(gè)pod:

如果不加污點(diǎn),可以看到這個(gè)pod會(huì)隨機(jī)調(diào)度到節(jié)點(diǎn)1或者節(jié)點(diǎn)2:

這時(shí)候把pod刪除了,重新創(chuàng)建pod并且給node加上污點(diǎn):
給節(jié)點(diǎn)打污點(diǎn):
kubectl taint node nodename key=value:NoSchedule

重新創(chuàng)建pod并且deployment多個(gè):

可以發(fā)現(xiàn)全部被調(diào)度在節(jié)點(diǎn)2上,節(jié)點(diǎn)1的污點(diǎn)NoSchedule起了作用。
刪除污點(diǎn):

污點(diǎn)容忍度(tolerations)
容忍度tolerations是定義在 Pod對(duì)象上的鍵值型屬性數(shù)據(jù),用于配置其可容忍的節(jié)點(diǎn)污點(diǎn),而且調(diào)度器僅能將Pod對(duì)象調(diào)度至其能夠容忍該節(jié)點(diǎn)污點(diǎn)的節(jié)點(diǎn)之上。
污點(diǎn)定義在節(jié)點(diǎn)的node Spec中,而容忍度則定義在Pod的podSpec中,它們都是鍵值型數(shù)據(jù)。
在Pod對(duì)象上定義容忍度時(shí),它支持兩種操作符:一種是等值比較Equal,表示容忍度與污點(diǎn)必須在key、value和effect三者之上完全匹配;另一種是存在性判斷Exists,表示二者的key和effect必須完全匹配,而容忍度中的value字段要使用空值。
這里的key和value對(duì)應(yīng)的值都是你自己設(shè)置的key和value:

說(shuō)白了就是:
- 如果
operator是Exists(此時(shí)容忍度不能指定 value) - 如果
operator是Equal,則它們的value應(yīng)該相等
而污點(diǎn)容忍的作用舉個(gè)例子,如果像上面污點(diǎn)一樣設(shè)置了NoSchedule污點(diǎn)的節(jié)點(diǎn),那么創(chuàng)建pod的時(shí)候是必不被調(diào)度到的,但是如果我使用污點(diǎn)容忍,那這個(gè)節(jié)點(diǎn)可以在設(shè)置NoSchedule污點(diǎn)的情況下可能又被調(diào)度,類似于親和性那種作用。
3、污點(diǎn)橫向滲透
污點(diǎn)和污點(diǎn)容忍度的作用也就是獲取主節(jié)點(diǎn)的shell,因?yàn)橄癯R?jiàn)或者節(jié)點(diǎn)shell的流程是創(chuàng)建pod--》分配到正常node---》通過(guò)常規(guī)掛載目錄拿到節(jié)點(diǎn)的shell,而默認(rèn)主節(jié)點(diǎn)是不被調(diào)度的,所以只有使用污點(diǎn)容忍度,創(chuàng)建一個(gè)能夠被調(diào)度到master節(jié)點(diǎn)的pod,然后通過(guò)掛載之類的手法來(lái)拿到主節(jié)點(diǎn)的shell。
通過(guò)創(chuàng)建一個(gè)具有node-role.kubernetes.io/master:NoSchedule的容忍度讓Pod被Kubernetes Master所調(diào)度。
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
tolerations:
- key: "node-role.kubernetes.io/master"
operator: "Exists"
effect: "NoSchedule"
如上的Pod中將宿主機(jī)的根目錄掛載到容器中(volumes與volumeMounts)即可逃逸至Kubernetes Master中接管集群。
查看節(jié)點(diǎn),當(dāng)前是在普通節(jié)點(diǎn):

多次創(chuàng)建可以發(fā)現(xiàn)在master節(jié)點(diǎn)上了:

可以通過(guò)掛載操作master節(jié)點(diǎn)母機(jī)shell:
