網(wǎng)站服務(wù)器提供商北京seo顧問(wèn)推推蛙
文章目錄
- 計(jì)算機(jī)系統(tǒng)
- 5G云計(jì)算
- 第三章 LINUX Kubernetes 集群調(diào)度
- 一、調(diào)度約束
- 1.調(diào)度過(guò)程
- 2.指定調(diào)度節(jié)點(diǎn)
- 3.親和性
- 1)節(jié)點(diǎn)親和性
- 2)Pod 親和性
- 3)鍵值運(yùn)算關(guān)系
- 4.污點(diǎn)(Taint) 和 容忍(Tolerations)
- 1)污點(diǎn)(Taint)
- 2)容忍(Tolerations)
- 3)Pod啟動(dòng)階段(相位 phase)
計(jì)算機(jī)系統(tǒng)
5G云計(jì)算
第三章 LINUX Kubernetes 集群調(diào)度
一、調(diào)度約束
當(dāng)定義 Pod 時(shí)可以選擇性地為每個(gè)容器設(shè)定所需要的資源數(shù)量。 最常見(jiàn)的可設(shè)定資源是 Kubernetes 是通過(guò) List-Watch 的機(jī)制進(jìn)行每個(gè)組件的協(xié)作,保持?jǐn)?shù)據(jù)同步的,每個(gè)組件之間的設(shè)計(jì)實(shí)現(xiàn)了解耦。
用戶是通過(guò) kubectl 根據(jù)配置文件,向 APIServer 發(fā)送命令,在 Node 節(jié)點(diǎn)上面建立 Pod 和 Container。
APIServer 經(jīng)過(guò) API 調(diào)用,權(quán)限控制,調(diào)用資源和存儲(chǔ)資源的過(guò)程,實(shí)際上還沒(méi)有真正開(kāi)始部署應(yīng)用。這里 需要 Controller Manager、Scheduler 和 kubelet 的協(xié)助才能完成整個(gè)部署過(guò)程。
在 Kubernetes 中,所有部署的信息都會(huì)寫到 etcd 中保存。實(shí)際上 etcd 在存儲(chǔ)部署信息的時(shí)候,會(huì)發(fā)送 Create 事件給 APIServer,而 APIServer 會(huì)通過(guò)監(jiān)聽(tīng)(Watch)etcd 發(fā)過(guò)來(lái)的事件。其他組件也會(huì)監(jiān)聽(tīng)(Watch)APIServer 發(fā)出來(lái)的事件
Pod 是 Kubernetes 的基礎(chǔ)單元,Pod 啟動(dòng)典型創(chuàng)建過(guò)程如下
(1)這里有三個(gè) List-Watch,分別是 Controller Manager(運(yùn)行在 Master),Scheduler(運(yùn)行在 Master),kubelet(運(yùn)行在 Node)。 他們?cè)谶M(jìn)程已啟動(dòng)就會(huì)監(jiān)聽(tīng)(Watch)APIServer 發(fā)出來(lái)的事件
(2)用戶通過(guò) kubectl 或其他 API 客戶端提交請(qǐng)求給 APIServer 來(lái)建立一個(gè) Pod 對(duì)象副本
(3)APIServer 嘗試著將 Pod 對(duì)象的相關(guān)元信息存入 etcd 中,待寫入操作執(zhí)行完成,APIServer 即會(huì)返回確認(rèn)信息至客戶端
(4)當(dāng) etcd 接受創(chuàng)建 Pod 信息以后,會(huì)發(fā)送一個(gè) Create 事件給 APIServer
(5)由于 Controller Manager 一直在監(jiān)聽(tīng)(Watch,通過(guò)https的6443端口)APIServer 中的事件。此時(shí) APIServer 接受到了 Create 事件,又會(huì)發(fā)送給 Controller Manager
(6)Controller Manager 在接到 Create 事件以后,調(diào)用其中的 Replication Controller 來(lái)保證 Node 上面需要?jiǎng)?chuàng)建的副本數(shù)量。一旦副本數(shù)量少于 RC 中定義的數(shù)量,RC 會(huì)自動(dòng)創(chuàng)建副本。總之它是保證副本數(shù)量的 Controller(PS:擴(kuò)容縮容的擔(dān)當(dāng))
(7)在 Controller Manager 創(chuàng)建 Pod 副本以后,APIServer 會(huì)在 etcd 中記錄這個(gè) Pod 的詳細(xì)信息。例如 Pod 的副本數(shù),Container 的內(nèi)容是什么
(8)同樣的 etcd 會(huì)將創(chuàng)建 Pod 的信息通過(guò)事件發(fā)送給 APIServer
(9)由于 Scheduler 在監(jiān)聽(tīng)(Watch)APIServer,并且它在系統(tǒng)中起到了“承上啟下”的作用,“承上”是指它負(fù)責(zé)接收創(chuàng)建的 Pod 事件,為其安排 Node;“啟下”是指安置工作完成后,Node 上的 kubelet 進(jìn)程會(huì)接管后繼工作,負(fù)責(zé) Pod 生命周期中的“下半生”。 換句話說(shuō),Scheduler 的作用是將待調(diào)度的 Pod 按照調(diào)度算法和策略綁定到集群中 Node 上
(10)Scheduler 調(diào)度完畢以后會(huì)更新 Pod 的信息,此時(shí)的信息更加豐富了。除了知道 Pod 的副本數(shù)量,副本內(nèi)容。還知道部署到哪個(gè) Node 上面了。并將上面的 Pod 信息更新至 API Server,由 APIServer 更新至 etcd 中,保存起來(lái)
(11)etcd 將更新成功的事件發(fā)送給 APIServer,APIServer 也開(kāi)始反映此 Pod 對(duì)象的調(diào)度結(jié)果
(12)kubelet 是在 Node 上面運(yùn)行的進(jìn)程,它也通過(guò) List-Watch 的方式監(jiān)聽(tīng)(Watch,通過(guò)https的6443端口)APIServer 發(fā)送的 Pod 更新的事件。kubelet 會(huì)嘗試在當(dāng)前節(jié)點(diǎn)上調(diào)用 Docker 啟動(dòng)容器,并將 Pod 以及容器的結(jié)果狀態(tài)回送至 APIServer
(13)APIServer 將 Pod 狀態(tài)信息存入 etcd 中。在 etcd 確認(rèn)寫入操作成功完成后,APIServer將確認(rèn)信息發(fā)送至相關(guān)的 kubelet,事件將通過(guò)它被接受
注意:在創(chuàng)建 Pod 的工作就已經(jīng)完成了后,為什么 kubelet 還要一直監(jiān)聽(tīng)呢?原因很簡(jiǎn)單,假設(shè)這個(gè)時(shí)候 kubectl 發(fā)命令,要擴(kuò)充 Pod 副本數(shù)量,那么上面的流程又會(huì)觸發(fā)一遍,kubelet 會(huì)根據(jù)最新的 Pod 的部署情況調(diào)整 Node 的資源。又或者 Pod 副本數(shù)量沒(méi)有發(fā)生變化,但是其中的鏡像文件升級(jí)了,kubelet 也會(huì)自動(dòng)獲取最新的鏡像文件并且加載
1.調(diào)度過(guò)程
Scheduler 是 kubernetes 的調(diào)度器,主要的任務(wù)是把定義的 pod 分配到集群的節(jié)點(diǎn)上。其主要考慮的問(wèn)題如下:
主要考慮的問(wèn)題 | 說(shuō)明 |
---|---|
公平 | 如何保證每個(gè)節(jié)點(diǎn)都能被分配資源 |
資源高效利用 | 集群所有資源最大化被使用 |
效率 | 調(diào)度的性能要好,能夠盡快地對(duì)大批量的 pod 完成調(diào)度工作 |
靈活 | 允許用戶根據(jù)自己的需求控制調(diào)度的邏輯 |
Sheduler 是作為單獨(dú)的程序運(yùn)行的,啟動(dòng)之后會(huì)一直監(jiān)聽(tīng) APIServer,獲取 spec.nodeName 為空的 pod,對(duì)每個(gè) pod 都會(huì)創(chuàng)建一個(gè) binding,表明該 pod 應(yīng)該放到哪個(gè)節(jié)點(diǎn)上
調(diào)度分為幾個(gè)部分:首先是過(guò)濾掉不滿足條件的節(jié)點(diǎn),這個(gè)過(guò)程稱為預(yù)算策略(predicate);然后對(duì)通過(guò)的節(jié)點(diǎn)按照優(yōu)先級(jí)排序,這個(gè)是優(yōu)選策略(priorities);最后從中選擇優(yōu)先級(jí)最高的節(jié)點(diǎn)。如果中間任何一步驟有錯(cuò)誤,就直接返回錯(cuò)誤
Predicate常見(jiàn)的算法 | 說(shuō)明 |
---|---|
PodFitsResources | 節(jié)點(diǎn)上剩余的資源是否大于 pod 請(qǐng)求的資源 |
PodFitsHost | 如果 pod 指定了 NodeName,檢查節(jié)點(diǎn)名稱是否和 NodeName 匹配 |
PodFitsHostPorts | 節(jié)點(diǎn)上已經(jīng)使用的 port 是否和 pod 申請(qǐng)的 port 沖突 |
PodSelectorMatches | 過(guò)濾掉和 pod 指定的 label 不匹配的節(jié)點(diǎn) |
NoDiskConflict | 已經(jīng) mount 的 volume 和 pod 指定的 volume 不沖突,除非它們都是只讀 |
如果在 predicate 過(guò)程中沒(méi)有合適的節(jié)點(diǎn),pod 會(huì)一直在 pending 狀態(tài),不斷重試調(diào)度,直到有節(jié)點(diǎn)滿足條件。 經(jīng)過(guò)這個(gè)步驟,如果有多個(gè)節(jié)點(diǎn)滿足條件,就繼續(xù) priorities 過(guò)程:按照優(yōu)先級(jí)大小對(duì)節(jié)點(diǎn)排序。
優(yōu)先級(jí)由一系列鍵值對(duì)組成,鍵是該優(yōu)先級(jí)項(xiàng)的名稱,值是它的權(quán)重(該項(xiàng)的重要性)。有一系列的常見(jiàn)的優(yōu)先級(jí)選項(xiàng)包括
常見(jiàn)的優(yōu)先級(jí)選項(xiàng) | 說(shuō)明 |
---|---|
LeastRequestedPriority | 通過(guò)計(jì)算CPU和Memory的使用率來(lái)決定權(quán)重,使用率越低權(quán)重越高。也就是說(shuō),這個(gè)優(yōu)先級(jí)指標(biāo)傾向于資源使用比例更低的節(jié)點(diǎn) |
BalancedResourceAllocation | 節(jié)點(diǎn)上 CPU 和 Memory 使用率越接近,權(quán)重越高。這個(gè)一般和上面的一起使用,不單獨(dú)使用。比如 node01 的 CPU 和 Memory 使用率 20:60,node02 的 CPU 和 Memory 使用率 50:50,雖然 node01 的總使用率比 node02 低,但 node02 的 CPU 和 Memory 使用率更接近,從而調(diào)度時(shí)會(huì)優(yōu)選 node02 |
ImageLocalityPriority | 傾向于已經(jīng)有要使用鏡像的節(jié)點(diǎn),鏡像總大小值越大,權(quán)重越高 |
2.指定調(diào)度節(jié)點(diǎn)
pod.spec.nodeName 將 Pod 直接調(diào)度到指定的 Node 節(jié)點(diǎn)上,會(huì)跳過(guò) Scheduler 的調(diào)度策略,該匹配規(guī)則是強(qiáng)制匹配
vim myapp.yaml
apiVersion: apps/v1
kind: Deployment
metadata:labels:app: myappname: myapp
spec:replicas: 3selector:matchLabels:app: myapptemplate:metadata:labels:app: myappspec:nodeName: node01containers:- name: myappimage: soscscs/myapp:v1ports:- containerPort: 80kubectl apply -f myapp.yamlkubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp-699655c7fd-blx8b 1/1 Running 0 81s 10.244.0.3 node01 <none> <none>
myapp-699655c7fd-cztzv 1/1 Running 0 81s 10.244.0.4 node01 <none> <none>
myapp-699655c7fd-l2pz9 1/1 Running 0 81s 10.244.0.5 node01 <none> <none>//查看詳細(xì)事件(發(fā)現(xiàn)未經(jīng)過(guò) scheduler 調(diào)度分配)
kubectl describe pod myapp-699655c7fd-blx8b
......Type Reason Age From Message---- ------ ---- ---- -------Normal Pulling 2m6s kubelet Pulling image "soscscs/myapp:v1"Normal Pulled 109s kubelet Successfully pulled image "soscscs/myapp:v1" in 17.32113529sNormal Created 108s kubelet Created container myappNormal Started 108s kubelet Started container myapp
pod.spec.nodeSelector:通過(guò) kubernetes 的 label-selector 機(jī)制選擇節(jié)點(diǎn),由調(diào)度器調(diào)度策略匹配 label,然后調(diào)度 Pod 到目標(biāo)節(jié)點(diǎn),該匹配規(guī)則屬于強(qiáng)制約束
//獲取標(biāo)簽幫助
kubectl label --help
Usage:kubectl label [--overwrite] (-f FILENAME | TYPE NAME) KEY_1=VAL_1 ... KEY_N=VAL_N [--resource-version=version] [options]//需要獲取 node 上的 NAME 名稱
kubectl get node
NAME STATUS ROLES AGE VERSION
node01 Ready <none> 18m v1.20.15
node02 Ready <none> 17m v1.20.15//給對(duì)應(yīng)的 node 設(shè)置標(biāo)簽分別為 kb=a 和 kb=b
kubectl label nodes node01 kb=akubectl label nodes node02 kb=b//查看標(biāo)簽
kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS
node01 Ready <none> 19m v1.20.15 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kb=a,kubernetes.io/arch=amd64,kubernetes.io/hostname=node01,kubernetes.io/os=linux
node02 Ready <none> 18m v1.20.15 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kb=b,kubernetes.io/arch=amd64,kubernetes.io/hostname=node02,kubernetes.io/os=linux//修改成 nodeSelector 調(diào)度方式
vim myapp1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: myapp1
spec:replicas: 3selector:matchLabels:app: myapp1template:metadata:labels:app: myapp1spec:nodeSelector:kb: acontainers:- name: myapp1image: soscscs/myapp:v1ports:- containerPort: 80kubectl apply -f myapp1.yaml kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp1-658b79fb78-cqtcf 1/1 Running 0 3s 10.244.0.6 node01 <none> <none>
myapp1-658b79fb78-g7gzr 1/1 Running 0 3s 10.244.0.8 node01 <none> <none>
myapp1-658b79fb78-jkdd5 1/1 Running 0 3s 10.244.0.7 node01 <none> <none>//查看詳細(xì)事件(通過(guò)事件可以發(fā)現(xiàn)要先經(jīng)過(guò) scheduler 調(diào)度分配)
kubectl describe pod myapp1-658b79fb78-cqtcf
Events:Type Reason Age From Message---- ------ ---- ---- -------Normal Scheduled 36s default-scheduler Successfully assigned default/myapp1-658b79fb78-cqtcf to node01Normal Pulled 36s kubelet Container image "soscscs/myapp:v1" already present on machineNormal Created 36s kubelet Created container myapp1Normal Started 36s kubelet Started container myapp1//修改一個(gè) label 的值,需要加上 --overwrite 參數(shù)
kubectl label nodes node02 kb=a --overwrite//刪除一個(gè) label,只需在命令行最后指定 label 的 key 名并與一個(gè)減號(hào)相連即可:
kubectl label nodes node02 kb-//指定標(biāo)簽查詢 node 節(jié)點(diǎn)
kubectl get node -l kb=a
3.親和性
https://kubernetes.io/zh/docs/concepts/scheduling-eviction/assign-pod-node/
可以把自己理解成一個(gè)Pod,當(dāng)你報(bào)名來(lái)學(xué)云計(jì)算,如果你更傾向去zhangsan老師帶的班級(jí),把不同老師帶的班級(jí)當(dāng)作一個(gè)node的話,這個(gè)就是節(jié)點(diǎn)親和性。如果你是必須要去zhangsan老師帶的班級(jí),這就是硬策略;而你說(shuō)你想去并且最好能去zhangsan老師帶的班級(jí),這就是軟策略
如果你有一個(gè)很好的朋友叫l(wèi)isi,你傾向和lisi同學(xué)在同一個(gè)班級(jí),這個(gè)就是Pod親和性。如果你一定要去lisi同學(xué)在的班級(jí),這就是硬策略;而你說(shuō)你想去并且最好能去lisi同學(xué)在的班級(jí),這就是軟策略。軟策略是不去也可以,硬策略則是不去就不行
1)節(jié)點(diǎn)親和性
pod.spec.nodeAffinity
pod.spec.nodeAffinity | 說(shuō)明 |
---|---|
preferredDuringSchedulingIgnoredDuringExecution | 軟策略 |
requiredDuringSchedulingIgnoredDuringExecution | 硬策略 |
2)Pod 親和性
pod.spec.affinity.podAffinity/podAntiAffinity
pod.spec.affinity.podAffinity/podAntiAffinity | 說(shuō)明 |
---|---|
preferredDuringSchedulingIgnoredDuringExecution | 軟策略 |
requiredDuringSchedulingIgnoredDuringExecution | 硬策略 |
3)鍵值運(yùn)算關(guān)系
鍵值運(yùn)算關(guān)系 | 說(shuō)明 |
---|---|
In | label 的值在某個(gè)列表中 |
NotIn | label 的值不在某個(gè)列表中 |
Gt | label 的值大于某個(gè)值 |
Lt | label 的值小于某個(gè)值 |
Exists | 某個(gè) label 存在 |
DoesNotExist | 某個(gè) label 不存在 |
kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS
node01 Ready <none> 21m v1.20.15 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kb=a,kubernetes.io/arch=amd64,kubernetes.io/hostname=node01,kubernetes.io/os=linux
node02 Ready <none> 21m v1.20.15 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kb=b,kubernetes.io/arch=amd64,kubernetes.io/hostname=node02,kubernetes.io/os=linux//requiredDuringSchedulingIgnoredDuringExecution:硬策略
mkdir /opt/affinity
cd /opt/affinityvim pod1.yaml
apiVersion: v1
kind: Pod
metadata:name: affinitylabels:app: node-affinity-pod
spec:containers:- name: with-node-affinityimage: soscscs/myapp:v1affinity:nodeAffinity:requiredDuringSchedulingIgnoredDuringExecution:nodeSelectorTerms:- matchExpressions:- key: kubernetes.io/hostname #指定node的標(biāo)簽operator: NotIn #設(shè)置Pod安裝到kubernetes.io/hostname的標(biāo)簽值不在values列表中的node上values:- node02kubectl apply -f pod1.yamlkubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
affinity 1/1 Running 0 2m6s 10.244.0.16 node01 <none> <none>kubectl delete pod --all && kubectl apply -f pod1.yaml && kubectl get pods -o wide#如果硬策略不滿足條件,Pod 狀態(tài)一直會(huì)處于 Pending 狀態(tài)。//preferredDuringSchedulingIgnoredDuringExecution:軟策略
vim pod2.yaml
apiVersion: v1
kind: Pod
metadata:name: affinitylabels:app: node-affinity-pod
spec:containers:- name: with-node-affinityimage: soscscs/myapp:v1affinity:nodeAffinity:preferredDuringSchedulingIgnoredDuringExecution:- weight: 1 #如果有多個(gè)軟策略選項(xiàng)的話,權(quán)重越大,優(yōu)先級(jí)越高preference:matchExpressions:- key: kubernetes.io/hostnameoperator: Invalues:- node02kubectl apply -f pod2.yamlkubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
affinity 1/1 Running 0 31s 10.244.1.4 node02 <none> <none>//把values:的值改成node01,則會(huì)優(yōu)先在node01上創(chuàng)建Pod
kubectl delete pod --all && kubectl apply -f pod2.yaml && kubectl get pods -o wide//如果把硬策略和軟策略合在一起使用,則要先滿足硬策略之后才會(huì)滿足軟策略
//示例:
apiVersion: v1
kind: Pod
metadata:name: affinitylabels:app: node-affinity-pod
spec:containers:- name: with-node-affinityimage: soscscs/myapp:v1affinity:nodeAffinity:requiredDuringSchedulingIgnoredDuringExecution: #先滿足硬策略,排除有kubernetes.io/hostname=node02標(biāo)簽的節(jié)點(diǎn)nodeSelectorTerms:- matchExpressions:- key: kubernetes.io/hostnameoperator: NotInvalues:- node02preferredDuringSchedulingIgnoredDuringExecution: #再滿足軟策略,優(yōu)先選擇有kb=a標(biāo)簽的節(jié)點(diǎn)- weight: 1preference:matchExpressions:- key: kboperator: Invalues:- a//Pod親和性與反親和性
調(diào)度策略 匹配標(biāo)簽 操作符 拓?fù)溆蛑С? 調(diào)度目標(biāo)
nodeAffinity 主機(jī) In, NotIn, Exists,DoesNotExist, Gt, Lt 否 指定主機(jī)
podAffinity Pod In, NotIn, Exists,DoesNotExist 是 Pod與指定Pod同一拓?fù)溆?podAntiAffinity Pod In, NotIn, Exists,DoesNotExist 是 Pod與指定Pod不在同一拓?fù)溆騥ubectl label nodes node01 kb=a
kubectl label nodes node02 kb=a//創(chuàng)建一個(gè)標(biāo)簽為 app=myapp01 的 Pod
vim pod4.yaml
apiVersion: v1
kind: Pod
metadata:name: myapp01labels:app: myapp01
spec:containers:- name: with-node-affinityimage: soscscs/myapp:v1kubectl apply -f pod4.yamlkubectl get pods --show-labels -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
myapp01 1/1 Running 0 3s 10.244.1.5 node02 <none> <none> app=myapp01//使用 Pod 親和性調(diào)度,創(chuàng)建多個(gè) Pod 資源
vim pod4.yaml
apiVersion: v1
kind: Pod
metadata:name: myapp02labels:app: myapp02
spec:containers:- name: myapp02image: soscscs/myapp:v1affinity:podAffinity:requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: appoperator: Invalues:- myapp01topologyKey: kb#僅當(dāng)節(jié)點(diǎn)和至少一個(gè)已運(yùn)行且有鍵為“app”且值為“myapp01”的標(biāo)簽 的 Pod 處于同一拓?fù)溆驎r(shí),才可以將該 Pod 調(diào)度到節(jié)點(diǎn)上。 (更確切的說(shuō),如果節(jié)點(diǎn) N 具有帶有鍵 kb 和某個(gè)值 V 的標(biāo)簽,則 Pod 有資格在節(jié)點(diǎn) N 上運(yùn)行,以便集群中至少有一個(gè)具有鍵 kb 和值為 V 的節(jié)點(diǎn)正在運(yùn)行具有鍵“app”和值 “myapp01”的標(biāo)簽的 pod。)
#topologyKey 是節(jié)點(diǎn)標(biāo)簽的鍵。如果兩個(gè)節(jié)點(diǎn)使用此鍵標(biāo)記并且具有相同的標(biāo)簽值,則調(diào)度器會(huì)將這兩個(gè)節(jié)點(diǎn)視為處于同一拓?fù)溆蛑小?調(diào)度器試圖在每個(gè)拓?fù)溆蛑蟹胖脭?shù)量均衡的 Pod。
#如果 kb 對(duì)應(yīng)的值不一樣就是不同的拓?fù)溆?。比?Pod1 在 kb=a 的 Node 上,Pod2 在 kb=b 的 Node 上,Pod3 在 kb=a 的 Node 上,則 Pod2 和 Pod1、Pod3 不在同一個(gè)拓?fù)溆?#xff0c;而Pod1 和 Pod3在同一個(gè)拓?fù)溆?。kubectl apply -f pod4.yamlkubectl get pods --show-labels -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
myapp01 1/1 Running 0 45s 10.244.0.21 node01 <none> <none> app=myapp01
myapp02 1/1 Running 0 3s 10.244.0.23 node01 <none> <none> app=myapp02//使用 Pod 反親和性調(diào)度
示例1:
vim pod5.yaml
apiVersion: v1
kind: Pod
metadata:name: myapp10labels:app: myapp10
spec:containers:- name: myapp10image: soscscs/myapp:v1affinity:podAntiAffinity:preferredDuringSchedulingIgnoredDuringExecution:- weight: 100podAffinityTerm:labelSelector:matchExpressions:- key: appoperator: Invalues:- myapp01topologyKey: kubernetes.io/hostname#如果節(jié)點(diǎn)處于 Pod 所在的同一拓?fù)溆蚯揖哂墟I“app”和值“myapp01”的標(biāo)簽, 則該 pod 不應(yīng)將其調(diào)度到該節(jié)點(diǎn)上。 (如果 topologyKey 為 kubernetes.io/hostname,則意味著當(dāng)節(jié)點(diǎn)和具有鍵 “app”和值“myapp01”的 Pod 處于相同的拓?fù)溆?#xff0c;Pod 不能被調(diào)度到該節(jié)點(diǎn)上。)kubectl apply -f pod5.yamlkubectl get pods --show-labels -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
myapp01 1/1 Running 0 98s 10.244.0.21 node01 <none> <none> app=myapp01
myapp02 1/1 Running 0 56s 10.244.0.23 node01 <none> <none> app=myapp02
myapp10 1/1 Running 0 3s 10.244.1.6 node02 <none> <none> app=myapp10示例2:
vim pod6.yaml
apiVersion: v1
kind: Pod
metadata:name: myapp20labels:app: myapp20
spec:containers:- name: myapp20image: soscscs/myapp:v1affinity:podAntiAffinity:requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: appoperator: Invalues:- myapp01topologyKey: kb//由于指定 Pod 所在的 node01 節(jié)點(diǎn)上具有帶有鍵 kb 和標(biāo)簽值 a 的標(biāo)簽,node02 也有這個(gè)kb=a的標(biāo)簽,所以 node01 和 node02 是在一個(gè)拓?fù)溆蛑?#xff0c;反親和要求新 Pod 與指定 Pod 不在同一拓?fù)溆?#xff0c;所以新 Pod 沒(méi)有可用的 node 節(jié)點(diǎn),即為 Pending 狀態(tài)。
kubectl get pod --show-labels -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
myapp01 1/1 Running 0 5m57s 10.244.0.21 node01 <none> <none> app=myapp01
myapp02 1/1 Running 0 5m15s 10.244.0.23 node01 <none> <none> app=myapp02
myapp10 1/1 Running 0 4m22s 10.244.1.6 node02 <none> <none> app=myapp10
myapp20 0/1 Pending 0 4s <none> <none> <none> <none> app=myapp20kubectl label nodes node02 kb=b --overwritekubectl get pod --show-labels -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
myapp01 1/1 Running 0 6m24s 10.244.0.21 node01 <none> <none> app=myapp01
myapp02 1/1 Running 0 5m42s 10.244.0.23 node01 <none> <none> app=myapp02
myapp10 1/1 Running 0 4m49s 10.244.1.6 node02 <none> <none> app=myapp10
myapp20 1/1 Running 0 31s 10.244.1.8 node02 <none> <none> app=myapp20
4.污點(diǎn)(Taint) 和 容忍(Tolerations)
1)污點(diǎn)(Taint)
節(jié)點(diǎn)親和性,是Pod的一種屬性(偏好或硬性要求),它使Pod被吸引到一類特定的節(jié)點(diǎn)。Taint 則相反,它使節(jié)點(diǎn)能夠排斥一類特定的 Pod
Taint 和 Toleration 相互配合,可以用來(lái)避免 Pod 被分配到不合適的節(jié)點(diǎn)上。每個(gè)節(jié)點(diǎn)上都可以應(yīng)用一個(gè)或多個(gè) taint ,這表示對(duì)于那些不能容忍這些 taint 的 Pod,是不會(huì)被該節(jié)點(diǎn)接受的。如果將 toleration 應(yīng)用于 Pod 上,則表示這些 Pod 可以(但不一定)被調(diào)度到具有匹配 taint 的節(jié)點(diǎn)上
使用 kubectl taint 命令可以給某個(gè) Node 節(jié)點(diǎn)設(shè)置污點(diǎn),Node 被設(shè)置上污點(diǎn)之后就和 Pod 之間存在了一種相斥的關(guān)系,可以讓 Node 拒絕 Pod 的調(diào)度執(zhí)行,甚至將 Node 已經(jīng)存在的 Pod 驅(qū)逐出去
污點(diǎn)的組成格式如下:
key=value:effect
每個(gè)污點(diǎn)有一個(gè) key 和 value 作為污點(diǎn)的標(biāo)簽,其中 value 可以為空,effect 描述污點(diǎn)的作用
當(dāng)前 taint effect 支持如下三個(gè)選項(xiàng)
taint effect 支持選項(xiàng) | 說(shuō)明 |
---|---|
NoSchedule | 表示 k8s 將不會(huì)將 Pod 調(diào)度到具有該污點(diǎn)的 Node 上 |
PreferNoSchedule | 表示 k8s 將盡量避免將 Pod 調(diào)度到具有該污點(diǎn)的 Node 上 |
NoExecute | 表示 k8s 將不會(huì)將 Pod 調(diào)度到具有該污點(diǎn)的 Node 上,同時(shí)會(huì)將 Node 上已經(jīng)存在的 Pod 驅(qū)逐出去 |
kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready master 11d v1.20.11
node01 Ready <none> 11d v1.20.11
node02 Ready <none> 11d v1.20.11//master 就是因?yàn)橛?NoSchedule 污點(diǎn),k8s 才不會(huì)將 Pod 調(diào)度到 master 節(jié)點(diǎn)上
kubectl describe node master
......
Taints: node-role.kubernetes.io/master:NoSchedule#設(shè)置污點(diǎn)
kubectl taint node node01 key1=value1:NoSchedule#節(jié)點(diǎn)說(shuō)明中,查找 Taints 字段
kubectl describe node node01 | grep -i taint#去除污點(diǎn)
kubectl taint node node01 key1:NoSchedule-kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp01 1/1 Running 0 8m35s 10.244.0.21 node01 <none> <none>
myapp02 1/1 Running 0 7m53s 10.244.0.23 node01 <none> <none>
myapp10 1/1 Running 0 7m 10.244.1.6 node02 <none> <none>
myapp20 1/1 Running 0 2m42s 10.244.1.8 node02 <none> <none>kubectl taint node node02 check=mycheck:NoExecute//查看 Pod 狀態(tài),會(huì)發(fā)現(xiàn) node02 上的 Pod 已經(jīng)被全部驅(qū)逐(注:如果是 Deployment 或者 StatefulSet 資源類型,為了維持副本數(shù)量則會(huì)在別的 Node 上再創(chuàng)建新的 Pod)
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp01 1/1 Running 0 9m10s 10.244.0.21 node01 <none> <none>
myapp02 1/1 Running 0 8m28s 10.244.0.23 node01 <none> <none>
2)容忍(Tolerations)
設(shè)置了污點(diǎn)的 Node 將根據(jù) taint 的 effect:NoSchedule、PreferNoSchedule、NoExecute 和 Pod 之間產(chǎn)生互斥的關(guān)系,Pod 將在一定程度上不會(huì)被調(diào)度到 Node 上。但我們可以在 Pod 上設(shè)置容忍(Tolerations),意思是設(shè)置了容忍的 Pod 將可以容忍污點(diǎn)的存在,可以被調(diào)度到存在污點(diǎn)的 Node 上
kubectl taint node node01 check=mycheck:NoExecutevim pod3.yaml
apiVersion: v1
kind: Pod
metadata:name: myapp01labels:app: myapp01
spec:containers:- name: with-node-affinityimage: soscscs/myapp:v1kubectl apply -f pod3.yaml//在兩個(gè) Node 上都設(shè)置了污點(diǎn)后,此時(shí) Pod 將無(wú)法創(chuàng)建成功
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp01 0/1 Pending 0 17s <none> <none> <none> <none>vim pod3.yaml
apiVersion: v1
kind: Pod
metadata:name: myapp01labels:app: myapp01
spec:containers:- name: with-node-affinityimage: soscscs/myapp:v1tolerations:- key: "check"operator: "Equal"value: "mycheck"effect: "NoExecute"tolerationSeconds: 3600#其中的 key、vaule、effect 都要與 Node 上設(shè)置的 taint 保持一致
#operator 的值為 Exists 將會(huì)忽略 value 值,即存在即可
#tolerationSeconds 用于描述當(dāng) Pod 需要被驅(qū)逐時(shí)可以在 Node 上繼續(xù)保留運(yùn)行的時(shí)間kubectl apply -f pod3.yaml//在設(shè)置了容忍之后,Pod 創(chuàng)建成功
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp01 1/1 Running 0 10m 10.244.1.5 node01 <none> <none>//其它注意事項(xiàng)
(1)當(dāng)不指定 key 值時(shí),表示容忍所有的污點(diǎn) keytolerations:- operator: "Exists"(2)當(dāng)不指定 effect 值時(shí),表示容忍所有的污點(diǎn)作用tolerations:- key: "key"operator: "Exists"(3)有多個(gè) Master 存在時(shí),防止資源浪費(fèi),可以如下設(shè)置
kubectl taint node Master-Name node-role.kubernetes.io/master=:PreferNoSchedule//如果某個(gè) Node 更新升級(jí)系統(tǒng)組件,為了防止業(yè)務(wù)長(zhǎng)時(shí)間中斷,可以先在該 Node 設(shè)置 NoExecute 污點(diǎn),把該 Node 上的 Pod 都驅(qū)逐出去
kubectl taint node node01 check=mycheck:NoExecute//此時(shí)如果別的 Node 資源不夠用,可臨時(shí)給 Master 設(shè)置 PreferNoSchedule 污點(diǎn),讓 Pod 可在 Master 上臨時(shí)創(chuàng)建
kubectl taint node master node-role.kubernetes.io/master=:PreferNoSchedule//待所有 Node 的更新操作都完成后,再去除污點(diǎn)
kubectl taint node node01 check=mycheck:NoExecute-//cordon 和 drain
##對(duì)節(jié)點(diǎn)執(zhí)行維護(hù)操作:
kubectl get nodes//將 Node 標(biāo)記為不可調(diào)度的狀態(tài),這樣就不會(huì)讓新創(chuàng)建的 Pod 在此 Node 上運(yùn)行
kubectl cordon <NODE_NAME> #該node將會(huì)變?yōu)镾chedulingDisabled狀態(tài)//kubectl drain 可以讓 Node 節(jié)點(diǎn)開(kāi)始釋放所有 pod,并且不接收新的 pod 進(jìn)程。drain 本意排水,意思是將出問(wèn)題的 Node 下的 Pod 轉(zhuǎn)移到其它 Node 下運(yùn)行
kubectl drain <NODE_NAME> --ignore-daemonsets --delete-emptydir-data --force--ignore-daemonsets:無(wú)視 DaemonSet 管理下的 Pod。
--delete-emptydir-data:如果有 mount local volume 的 pod,會(huì)強(qiáng)制殺掉該 pod。
--force:強(qiáng)制釋放不是控制器管理的 Pod。注:執(zhí)行 drain 命令,會(huì)自動(dòng)做了兩件事情:
(1)設(shè)定此 node 為不可調(diào)度狀態(tài)(cordon)
(2)evict(驅(qū)逐)了 Pod//kubectl uncordon 將 Node 標(biāo)記為可調(diào)度的狀態(tài)
kubectl uncordon <NODE_NAME>
3)Pod啟動(dòng)階段(相位 phase)
Pod 創(chuàng)建完之后,一直到持久運(yùn)行起來(lái),中間有很多步驟,也就有很多出錯(cuò)的可能,因此會(huì)有很多不同的狀態(tài)。
一般來(lái)說(shuō),pod 這個(gè)過(guò)程包含以下幾個(gè)步驟:
(1)調(diào)度到某臺(tái) node 上。kubernetes 根據(jù)一定的優(yōu)先級(jí)算法選擇一臺(tái) node 節(jié)點(diǎn)將其作為 Pod 運(yùn)行的 node
(2)拉取鏡像
(3)掛載存儲(chǔ)配置等
(4)容器運(yùn)行起來(lái)。如果有健康檢查,會(huì)根據(jù)檢查的結(jié)果來(lái)設(shè)置其狀態(tài)
phase 的可能狀態(tài)有
phase 的可能狀態(tài) | 說(shuō)明 |
---|---|
Pending | 表示APIServer創(chuàng)建了Pod資源對(duì)象并已經(jīng)存入了etcd中,但是它并未被調(diào)度完成(比如還沒(méi)有調(diào)度到某臺(tái)node上),或者仍然處于從倉(cāng)庫(kù)下載鏡像的過(guò)程中 |
Running | Pod已經(jīng)被調(diào)度到某節(jié)點(diǎn)之上,并且Pod中所有容器都已經(jīng)被kubelet創(chuàng)建。至少有一個(gè)容器正在運(yùn)行,或者正處于啟動(dòng)或者重啟狀態(tài)(也就是說(shuō)Running狀態(tài)下的Pod不一定能被正常訪問(wèn)) |
Succeeded | 有些pod不是長(zhǎng)久運(yùn)行的,比如job、cronjob,一段時(shí)間后Pod中的所有容器都被成功終止,并且不會(huì)再重啟。需要反饋任務(wù)執(zhí)行的結(jié)果 |
Failed | Pod中的所有容器都已終止了,并且至少有一個(gè)容器是因?yàn)槭〗K止。也就是說(shuō),容器以非0狀態(tài)退出或者被系統(tǒng)終止,比如 command 寫的有問(wèn)題 |
Unknown | 表示無(wú)法讀取 Pod 狀態(tài),通常是 kube-controller-manager 無(wú)法與 Pod 通信。Pod 所在的 Node 出了問(wèn)題或失聯(lián),從而導(dǎo)致 Pod 的狀態(tài)為 Unknow |
如何刪除 Unknown 狀態(tài)的 Pod
如何刪除 Unknown 狀態(tài)的 Pod |
---|
從集群中刪除有問(wèn)題的 Node。使用公有云時(shí),kube-controller-manager 會(huì)在 VM 刪除后自動(dòng)刪除對(duì)應(yīng)的 Node。 而在物理機(jī)部署的集群中,需要管理員手動(dòng)刪除 Node(kubectl delete node <node_name>) |
被動(dòng)等待 Node 恢復(fù)正常,Kubelet 會(huì)重新跟 kube-apiserver 通信確認(rèn)這些 Pod 的期待狀態(tài),進(jìn)而再?zèng)Q定刪除或者繼續(xù)運(yùn)行這些 Pod |
主動(dòng)刪除 Pod,通過(guò)執(zhí)行 kubectl delete pod <pod_name> --grace-period=0 --force 強(qiáng)制刪除 Pod。但是這里需要注意的是,除非明確知道 Pod 的確處于停止?fàn)顟B(tài)(比如 Node 所在 VM 或物理機(jī)已經(jīng)關(guān)機(jī)),否則不建議使用該方法。特別是 StatefulSet 管理的 Pod,強(qiáng)制刪除容易導(dǎo)致腦裂或者數(shù)據(jù)丟失等問(wèn)題 |
##故障排除步驟:
//查看Pod事件
kubectl describe TYPE NAME_PREFIX //查看Pod日志(Failed狀態(tài)下)
kubectl logs <POD_NAME> [-c Container_NAME]//進(jìn)入Pod(狀態(tài)為running,但是服務(wù)沒(méi)有提供)
kubectl exec –it <POD_NAME> bash//查看集群信息
kubectl get nodes//發(fā)現(xiàn)集群狀態(tài)正常
kubectl cluster-info//查看kubelet日志發(fā)現(xiàn)
journalctl -xefu kubelet
群中刪除有問(wèn)題的 Node。使用公有云時(shí),kube-controller-manager 會(huì)在 VM 刪除后自動(dòng)刪除對(duì)應(yīng)的 Node。 而在物理機(jī)部署的集群中,需要管理員手動(dòng)刪除 Node(kubectl delete node <node_name>) |
| 被動(dòng)等待 Node 恢復(fù)正常,Kubelet 會(huì)重新跟 kube-apiserver 通信確認(rèn)這些 Pod 的期待狀態(tài),進(jìn)而再?zèng)Q定刪除或者繼續(xù)運(yùn)行這些 Pod |
| 主動(dòng)刪除 Pod,通過(guò)執(zhí)行 kubectl delete pod <pod_name> --grace-period=0 --force 強(qiáng)制刪除 Pod。但是這里需要注意的是,除非明確知道 Pod 的確處于停止?fàn)顟B(tài)(比如 Node 所在 VM 或物理機(jī)已經(jīng)關(guān)機(jī)),否則不建議使用該方法。特別是 StatefulSet 管理的 Pod,強(qiáng)制刪除容易導(dǎo)致腦裂或者數(shù)據(jù)丟失等問(wèn)題 |
##故障排除步驟:
//查看Pod事件
kubectl describe TYPE NAME_PREFIX //查看Pod日志(Failed狀態(tài)下)
kubectl logs <POD_NAME> [-c Container_NAME]//進(jìn)入Pod(狀態(tài)為running,但是服務(wù)沒(méi)有提供)
kubectl exec –it <POD_NAME> bash//查看集群信息
kubectl get nodes//發(fā)現(xiàn)集群狀態(tài)正常
kubectl cluster-info//查看kubelet日志發(fā)現(xiàn)
journalctl -xefu kubelet