一: 污點
1.1 污點的作用
節點親和性,是Pod的一種屬性(偏好或硬性要求) ,它使Pod被吸引到一類特定的節點。Taint則相反,它使節點能夠排斥一類特定的PodTaint和Toleration相互配合,可以用來避免Pod被分配到不合適的節點上。每個節點上都可以應用一個或多個taint
,這表示對於那些不能容忍這些taint的Pod,是不會被該節點接受的。如果將toleration應用於Pod上,則表示這些Pod
可以(但不一定)被調度到具有匹配taint的節點上。
使用kubectl taint命令可以給某個Node節點設置污點, Node被設置上污點之后就和Pod之間存在了一種相斥的關系,可以讓Node拒絕Pod的調度執行,甚至將Node已經存在的Pod驅逐出去。
/
1.2 污點的組成
污點的組成格式如下:key-value:effect
每個污點有一個key和value作為污點的標簽,其中value可以為空, effect描述污點的作用。
當前taint effect支持如下三個選項:
- NoSchedule:表示k8s將不會將Pod調度到具有該污點的Node上
- PreferNoschedule:表示k8s將盡量避免將Pod調度到具有該污點的Node上
- NoExecute:表示k8s將不會將Pod調度到具有該污點的Node上,同時會將Node上已經存在的Pod驅逐出去
[root@master ~]# kubectl describe nodes master | grep -i 'taints'
Taints: node-role.kubernetes.io/master:NoSchedule

1.3 設置,查看,去除污點
#為node01節點設置污點 key1=value1:NoSchedule. NoSchedule便是pod不調度到這個節點
[root@master ~]# kubectl taint nodes node01 key1=value1:NoSchedule
node/node01 tainted
#通過describe 查看節點詳細信息查看污點,並不區分大小寫過濾 ‘key'
[root@master ~]# kubectl describe node node01 | grep -i 'key1'
Taints: key1=value1:NoSchedule
[root@master ~]#
#刪除node01的污點key1:NoSchedule
[root@master ~]# kubectl taint node node01 key1:NoSchedule-
node/node01 untainted
[root@master ~]# kubectl describe node node01 | grep -i 'key1'

1.4 示例
[root@master demo]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp01 1/1 Running 0 29s 10.244.1.143 node01 <none> <none>
myapp02 1/1 Running 0 17s 10.244.2.110 node02 <none> <none>
myapp03 1/1 Running 0 9s 10.244.1.144 node01 <none> <none>
[root@master demo]#
#設置node01節點,不允許將pod調度到上面,同時還會驅逐該節點上的pod
[root@master demo]# kubectl taint node node01 check=mycheck:NoExecute
node/node01 tainted
#node01節點上的pod被驅逐
[root@master demo]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp02 1/1 Running 0 84s 10.244.2.110 node02 <none> <none>
注意:如果是Deployment或者StateFulSet資源類型,為了未出副本數量,則會在其他的node上創建新的pod

二:容忍
2.1 容忍的作用
容忍(Tolerations)
設置了污點的Node將根據taint的effect : Noschedule, PreferNoschedule, NoExecute和Pod之間產生互斥的關系, Pod將在一定程度上不會被調度到Node上。但我們可以在Pod上設置容忍(Tolerations) ,意思是設置了容忍的Pod
將可以容忍污點的存在,可以被調度到存在污點的Node上。
2.2 示例
2.2.1 將兩個節點都設置污點
#將node02也打上污點NoExecute。node01和node02都有此污點
[root@master demo]# kubectl taint node node02 check=mycheck:NoExecute
node/node02 tainted
[root@master demo]# vim pod3.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp01
labels:
app: myapp01
spec:
containers:
- name: with-node-affinity
image: soscscs/myapp:v1
[root@master demo]# kubectl apply -f pod3.yaml
pod/myapp01 created
#此時,兩個節點都設置了NoExecute,所以,pod無法調度
root@master demo]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp01 0/1 Pending 0 23s <none> <none> <none> <none>

2.2.2 在pod上配置容忍
[root@master demo]# vim pod3.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp01
labels:
app: myapp01
spec:
containers:
- name: with-node-affinity
image: soscscs/myapp:v1
tolerations:
- key: "check"
operator: "Equal"
value: "mycheck"
effect: "NoExecute"
tolerationSeconds: 3600
#其中的 key、vaule、effect 都要與 Node 上設置的 taint 保持一致
#operator 的值為 Exists 將會忽略 value 值,即存在即可
#tolerationSeconds 用於描述當 Pod 需要被驅逐時可以在 Pod 上繼續保留運行的時間
#如果不設置tolerationSeconds,則pod將不限時
#在配置了pod的容忍后,pod的狀態變為了running
[root@master demo]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp01 1/1 Running 0 6m18s 10.244.2.111 node02 <none> <none>

2.3 注意事項
#當不指定 key 值時,表示容忍所有的污點 key
tolerations:
- operator: "Exists"
#當不指定 effect 值時,表示容忍所有的污點作用
tolerations:
- key: "key"
operator: "Exists"
#有多個 Master 存在時,防止資源浪費,可以如下設置
kubectl taint nodes Master-Name node-role.kubernetes.io/master=:PreferNoSchedule
2.4 node更新時對pod的操作
#如果某個 Node 更新升級系統組件,為了防止業務長時間中斷,可以先在該 Node 設置 NoExecute 污點,把該 Node 上的 Pod 都驅逐出去
kubectl taint nodes node01 check=mycheck:NoExecute
#此時如果別的 Node 資源不夠用,可臨時給 Master 設置 PreferNoSchedule 污點,讓 Pod 可在 Master 上臨時創建
kubectl taint nodes master node-role.kubernetes.io/master=:PreferNoSchedule
#待所有 Node 的更新操作都完成后,再去除污點
kubectl taint nodes node01 check=mycheck:NoExecute-
三: Pod啟動階段
3.1 Pod過程的步驟
Pod 創建完之后,一直到持久運行起來,中間有很多步驟,也就有很多出錯的可能,因此會有很多不同的狀態。
一般來說,pod 這個過程包含以下幾個步驟:
- 調度到某台 node 上。kubernetes 根據一定的優先級算法選擇一台 node 節點將其作為 Pod 運行的 node
- 拉取鏡像
- 掛載存儲配置等
- 運行起來。如果有健康檢查,會根據檢查的結果來設置其狀態。
3.2 Pod啟動的5種狀態
phase 的可能狀態有:
●Pending:表示APIServer創建了Pod資源對象並已經存入了etcd中,但是它並未被調度完成(比如還沒有調度到某台node上),或者仍然處於從倉庫下載鏡像的過程中。
●Running:Pod已經被調度到某節點之上,並且Pod中所有容器都已經被kubelet創建。至少有一個容器正在運行,或者正處於啟動或者重啟狀態(也就是說Running狀態下的Pod不一定能被正常訪問)。
●Succeeded:有些pod不是長久運行的,比如job、cronjob,一段時間后Pod中的所有容器都被成功終止,並且不會再重啟。需要反饋任務執行的結果。
●Failed:Pod中的所有容器都已終止了,並且至少有一個容器是因為失敗終止。也就是說,容器以非0狀態退出或者被系統終止,比如 command 寫的有問題。
●Unknown:因為某些原因無法取得 Pod 的狀態,通常是因為與 Pod 所在主機通信失敗。
四: 故障排除步驟
-
查看Pod事件
- kubectl describe TYPE NAME_PREFIX
-
查看Pod日志(Failed狀態下)
- kubectl logs <POD_NAME> [-c Container_NAME]
-
進入Pod(狀態為running,但是服務沒有提供)
- kubectl exec –it <POD_NAME> bash
-
查看集群信息
- kubectl get nodes
-
發現集群狀態正常
- kubectl cluster-info
-
查看kubelet日志發現
- journalctl -xefu kubelet
五:對節點執行維護操作
kubectl get nodes
//將 Node 標記為不可調度的狀態,這樣就不會讓新創建的 Pod 在此 Node 上運行
kubectl cordon <NODE_NAME> #該node將會變為SchedulingDisabled狀態
//kubectl drain 可以讓 Node 節點開始釋放所有 pod,並且不接收新的 pod 進程。drain 本意排水,意思是將出問題的 Node 下的 Pod 轉移到其它 Node 下運行
kubectl drain <NODE_NAME> --ignore-daemonsets --delete-local-data --force
--ignore-daemonsets:無視 DaemonSet 管理下的 Pod。
--delete-local-data:如果有 mount local volume 的 pod,會強制殺掉該 pod。
--force:強制釋放不是控制器管理的 Pod,例如 kube-proxy。
注:執行 drain 命令,會自動做了兩件事情:
(1)設定此 node 為不可調度狀態(cordon)
(2)evict(驅逐)了 Pod
//kubectl uncordon 將 Node 標記為可調度的狀態
kubectl uncordon <NODE_NAME>
如果node的標記為 cordon ,則經過scheduler調度的pod,無法調度到那個節點。
而使用nodeName 進行指定,則跳過了scheduler 調度過程,因此不會受到cordon的影響
