?
?一 污點(Taint) 和 容忍(Tolerations)
(一)污點
在Kubernetes(K8s)中,污點(Taints)是一個重要的概念,用于實現Pod的調度控制。以下是關于污點的詳細解釋:1.污點定義
污點是什么:污點是一種定義在節點上的鍵值型屬性數據,用于讓節點拒絕將Pod調度運行于其上,除非該Pod對象具有接納節點污點的容忍度(Toleration)。鍵值型數據:污點由三個部分組成:key、value和effect。其中key和value是污點的名稱和值,而effect則定義了污點的效果。2.污點效果
污點的效果(Effect)主要有三種類型:NoSchedule:新的不能容忍此污點的Pod對象不會被調度至當前節點,但已在該節點上運行的Pod對象不受影響。PreferNoSchedule:Kubernetes會盡量避免將新的不能容忍此污點的Pod對象調度至當前節點,但如果沒有其他可用節點,仍然會調度。類似于節點親和與pod親和中的軟策略NoExecute:新的不能容忍此污點的Pod對象不會被調度至當前節點,而且已在該節點上運行但不再滿足匹配規則的Pod對象將被驅逐。
1.1 污點(taint)
節點親和性,是Pod的一種屬性(偏好或硬性要求),它使Pod被吸引到一類特定的節點。Taint 則相反,它使節點能夠排斥一類特定的 Pod。
Taint 和 Toleration 相互配合,可以用來避免 Pod 被分配到不合適的節點上。每個節點上都可以應用一個或多個 taint ,這表示對于那些不能容忍這些 taint 的 Pod,是不會被該節點接受的。如果將 toleration 應用于 Pod 上,則表示這些 Pod 可以(但不一定)被調度到具有匹配 taint 的節點上。
使用 kubectl taint 命令可以給某個 Node 節點設置污點,Node 被設置上污點之后就和 Pod 之間存在了一種相斥的關系,可以讓 Node 拒絕 Pod 的調度執行,甚至將 Node 已經存在的 Pod 驅逐出去。
污點的組成格式下:
key=value:effect
每個污點有一個 key 和 value 作為污點的標簽,其中 value 可以為空,effect 描述污點的作用。
當前 taint effect 支持如下三個選項:
●NoSchedule:表示 k8s 將不會將 Pod 調度到具有該污點的 Node 上
●PreferNoSchedule:表示 k8s 將盡量避免將 Pod 調度到具有該污點的 Node 上
●NoExecute:表示 k8s 將不會將 Pod 調度到具有該污點的 Node 上,同時會將 Node 上已經存在的 Pod 驅逐出去
?
?master 就是因為有 NoSchedule 污點,k8s 才不會將 Pod 調度到 master 節點上
設置污點
kubectl taint node node01 key1=value1:NoSchedule
#節點說明中,查找 Taints 字段
kubectl describe node node-name ?
#去除污點
kubectl taint node node01 key1:NoSchedule-
kubectl taint node node01 鍵名=鍵值:NoSchedule
//增加污點kubectl taint node node01 鍵名=鍵值:NoSchedule-
kubectl taint node node01 鍵名-
//刪除kubectl describe nodes node01|grep -A5 -i taint
//查看
?
?舉例說明:將node02節點設置為NoSchedule
?
驗證污點的作用——NoExecute?
此時,給node02也設置為NoExecute 兩個都是驅逐?
因此所有在node01上面的pod都被驅逐出來,并轉移到node02上面,查看 Pod 狀態,會發現 node01 上的 Pod 已經被全部驅逐(注:如果是 Deployment 或者 StatefulSet 資源類型,為了維持副本數量則會在別的 Node 上再創建新的 Pod)
?
?自主創建的pod會停止,一直處于pending的狀態,因為node01 node02都被設置成了NoExecute,找不到適合的node,才會變成pending
驗證污點的作用—NoSchedule??
原本在node1上面的pod不會被刪除,新建的pod不會調度到node1節點上面
?隨后,新建一個pod 觀察一下,因為node01 有污點,不會將pod調度到node01上,因此pod01 在node02上
?
?
驗證污點的作用——PreferNoSchedule?
分別給node01 node02 創建污點
?過濾一下node1? node02的taint污點
隨后,創建一個新的pod
污點設置在node上面,容忍設置在pod節點上面
?
?二、容忍(pod可以適應node上面的污點)
設置了污點的 Node 將根據 taint 的 effect:NoSchedule、PreferNoSchedule、NoExecute 和 Pod 之間產生互斥的關系,Pod 將在一定程度上不會被調度到 Node 上。但我們可以在 Pod 上設置容忍(Tolerations),意思是設置了容忍的 Pod 將可以容忍污點的存在,可以被調度到存在污點的 Node 上。,沒有設置污點的node也是可以調度的。
2.容忍的組成
容忍通常包含以下幾個部分:
鍵(Key):與污點的鍵相匹配。
值(Value):與污點的值相匹配。如果不指定值,Pod將容忍所有值的同名污點。
效應(Effect):與污點的效應相匹配。常見的效應包括NoSchedule、PreferNoSchedule和NoExecute。
容忍期限(TolerationSeconds)(僅對NoExecute效應有效):指定Pod在節點被賦予NoExecute污點后,能夠繼續在該節點上運行的時間(以秒為單位)。超過這個時間后,Pod將被驅逐。
操作符(Operator):用于指定容忍與污點的匹配方式。常見的操作符包括Equal和Exists。Equal要求鍵、值和效應都完全匹配,而Exists只要求鍵和效應匹配。
?隨后,設置一個pod 跟node02這個節點做容忍
apiVersion: v1
kind: Pod
metadata:name: myapp01labels:app: myapp01
spec:containers:- name: with-node-affinityimage: soscscs/myapp:v1tolerations:- key: "check"operator: "Equal"value: "no"effect: "NoExecute"tolerationSeconds: 15
?
?#其中的 key、vaule、effect 都要與 Node 上設置的 taint 保持一致
#operator 的值為 Exists 將會忽略 value 值,即存在即可
#tolerationSeconds 用于描述當 Pod 需要被驅逐時可以在 Node 上繼續保留運行的時間
?其它注意事項(equal表示精確匹配,exists表示模糊匹配)
(1)當不指定 key 值時,表示容忍所有的污點 key,就是指明只要key這個鍵相同即可,里面的值是什么都無所謂。
? tolerations:
? - operator: "Exists"
舉例說明:
? 隨后,寫一個yaml文件去創建pod
當超過40秒之后,就會被驅逐
2)作當不指定 effect 值時,表示容忍所有的污點用
? tolerations:
? - key: "key"
? ? operator: "Exists"
//其它注意事項
(1)當不指定 key 值時,表示容忍所有的污點 keytolerations:- operator: "Exists"(2)當不指定 effect 值時,表示容忍所有的污點作用tolerations:- key: "key"operator: "Exists"(3)有多個 Master 存在時,防止資源浪費,可以如下設置
kubectl taint node Master-Name node-role.kubernetes.io/master=:PreferNoSchedule//如果某個 Node 更新升級系統組件,為了防止業務長時間中斷,可以先在該 Node 設置 NoExecute 污點,把該 Node 上的 Pod 都驅逐出去
kubectl taint node node01 check=mycheck:NoExecute//此時如果別的 Node 資源不夠用,可臨時給 Master 設置 PreferNoSchedule 污點,讓 Pod 可在 Master 上臨時創建
kubectl taint node master node-role.kubernetes.io/master=:PreferNoSchedule//待所有 Node 的更新操作都完成后,再去除污點
kubectl taint node node01 check=mycheck:NoExecute-
?(三)資源優化
1.多master使用
當有多個master存在時,可以將備用的master的污點狀態設置為PreferNoSchedule,這樣的話,會盡可能避免此節點,當其它節點不可調用(資源頂峰、節點故障、節點更新等)時,可以使用master進行臨時調度,待資源恢復時,再將pod轉移?
kubectl taint node Master-Name node-role.kubernetes.io/master=:PreferNoSchedule
2.Node更新
當某個node節點需要資源更新時,為防止業務長時間中斷,可以依次升級node,首先將需要升級的node節點設置污點,將pod資源調度到其它node節點上(如master資源充足也可以臨時調用),等到該節點升級完畢后,去除污點。依次類推,將所有節點更新升級?
kubectl taint node node-name key=value:NoExecute
#設置污點
-------------------------------------------------------------------------------
kubectl taint node node-name key:NoExecute-
#去除污點
3.維護操作
作用:阻止新的 Pods 被調度到該節點上。當一個節點被標記為 cordon 時,已經在該節點上運行的 Pods 不會被驅逐,但新的 Pods 不會被調度到這個節點。
使用場景:通常用于節點的維護或升級,確保在維護期間不會有新的工作負載被分配到該節點上。命令示例:kubectl cordon node01
首先,刪除node1 node2上面的污點
? ? ? ? ? ? ?? ? ? ? ? ?設置的cordon維護策略,默認的污點為NoSchedule
驗證一下:
創建兩個pod
?
恢復調度:
使用 kubectl uncordon node01 命令可以恢復節點的調度狀態,允許新的 Pods 調度到該節點上。
?drain?
//kubectl drain 可以讓 Node 節點開始釋放所有 pod,并且不接收新的 pod 進程。drain 本意排水,意思是將出問題的 Node 下的 Pod 轉移到其它 Node 下運行
kubectl drain <NODE_NAME> --ignore-daemonsets --delete-emptydir-data --force--ignore-daemonsets:無視 DaemonSet 管理下的 Pod。
--delete-emptydir-data:如果有 mount local volume 的 pod,會強制殺掉該 pod。
--force:強制釋放不是控制器管理的 Pod。
注:執行 drain 命令,會自動做了兩件事情:
(1)設定此 node 為不可調度狀態(cordon)
(2)evict(驅逐)了 Pod??
簡單來說
cordon的作用類似于NoSchedule
drain的作用類似于NoExecute
?四、Pod啟動階段?
第一步:controller manager管理的控制器創建pod副本
第二步:scheduler調度器根據調度算法選擇最合適的node節點調度pod
第三步:kubelet拉取鏡像
第四步:kubelet掛載存儲卷
第五步:kubelet創建并運行容器
第六步:kubelet根據容器探針的探測結果設置Pod狀態
?
五、關于pod的五種狀態
Pending:Pod已經創建,但是Pod還處于包括未完成調度到node節點或者還處于在拉取鏡像的過程中、存儲卷掛載失敗的情況
Running:Pod所有容器已被創建,且至少有一個容器正在運行
Succeeded:Pod所有容器都已經成功退出,且不再重啟。(Completed)
Failed:Pod所有容器都已經退出,且至少有一個容器是異常退出的。(Error)
Unknown:master節點的controller manager無法獲取到Pod的狀態信息,通常是因為master節點的apiserver與Pod所在node節點的kubelet通信失聯導致的(比如node節點宕機或kubelet進程故障)
總結:Pod遵循預定于的生命周期,起始于Pend階段,如果至少有一個容器正常運行,則進Running階段,之后取決于Pod是否有容器以失敗狀態退出而進入Succeeded或Failed階段。
?六、k8s常見的排障手段
針對組件故障
kubectl get nodes 查看node節點運行狀態
kubectl describe nodes <node節點名稱> 查看node節點的詳細信息和資源描述
kubectl get cs 查看master組件的健康狀態
kubectl cluster-info 查看集群信息journalctl -u -f kubelet 跟蹤查看kubelet進程日志
針對pod故障
kubectl get pods -o wide 查看Pod的運行狀態和就緒狀態
kubectl describe <pods|其它資源類型> <資源名稱> 查看資源的詳細信息和事件描述,主要是針對處于Pending狀態的故障
kubectl logs <Pod資源名稱> -c <容器名稱> -f -p 查看Pod容器的主進程日志,主要是針對進入Running狀態后的故障,比如Failed異常問題
kubectl exec -it <Pod資源名稱> -c <容器名稱> sh|bash 進入Pod容器查看容器內部相關的狀態信息,比如進程、端口、文件、流量等狀態信息
kubectl debug -it <Pod資源名稱> --image=<臨時工具容器的鏡像名> --target=<目標容器> 在Pod中創建臨時工具容器進入目標容器進行調試,主要針對沒有調試工具的容器使用
nsenter -n --target <容器ID> 在Pod容器宿主機使用nsenter轉換網絡namespace,直接在宿主機進入目標容器的網絡命名空間進行抓包等調試工作
針對網絡故障
kubectl get svc 查看service資源的clusterIP、port、nodePort等信息
kubectl describe svc <svc資源名稱> 查看service資源的標簽選擇器、endpoints端點等信息
kubectl get pods --show-lables 查看Pod的標簽
故障排除思路
在k8s的操作中,由于組件較多,任何一步有錯誤,都可能導致整個k8s集群陷入不可以狀態,下面我就結合工作中的一些操作做一總結
1.環境設置
防火墻策略、核心防護可能會導致節點之間無法通信
swap分區會導致kubelet無法啟動,kubelet無法啟動,意味著網絡插件與kube-proxy容器無法啟動
集群信息:使用kubectl get node查看集群信息,確保節點之間通信正常
2.pod事件處理
kubectl describe <資源類型> <資源名稱>:查看資源詳細信息
kubectl get events:指令查看所有事件信息,并使用grep過濾關鍵字?
kubectl exec –it pod_name bash :進入容器查看,只限于處于Running狀態
kubectl logs pod_name:查看pod日志,在Failed狀態下
journalctl -xefu kubelet:查看kubelet日志