Pod異常狀態排錯
一、常用命令
首先列出Pod排查過程中的常用命令:
查看Pod狀態:kubectl get pod podname -o wide
查看Pod的yaml配置:kubectl get pods podname -o yaml
查看pod事件:kubectl describe pods podname
查看容器日志:kubectl logs podsname -c container-name
二、Pod狀態
- Error:Pod 啟動過程中發生錯誤
- NodeLost : Pod 所在節點失聯
- Unkown : Pod 所在節點失聯或其它未知異常
- Waiting : Pod 等待啟動
- Pending : Pod 等待被調度
- ContainerCreating : Pod 容器正在被創建
- Terminating : Pod 正在被銷毀
- CrashLoopBackOff :容器退出,kubelet 正在將它重啟
- InvalidImageName :無法解析鏡像名稱
- ImageInspectError :無法校驗鏡像
- ErrImageNeverPull :策略禁止拉取鏡像
- ImagePullBackOff :正在重試拉取
- RegistryUnavailable :連接不到鏡像中心
- ErrImagePull :通用的拉取鏡像出錯
- CreateContainerConfigError :不能創建 kubelet 使用的容器配置
- CreateContainerError :創建容器失敗
- RunContainerError :啟動容器失敗
- PreStartHookError : 執行 preStart hook 報錯
- PostStartHookError :執行 postStart hook 報錯
- ContainersNotInitialized :容器沒有初始化完畢
- ContainersNotReady :容器沒有準備完畢
- ContainerCreating :容器創建中
- PodInitializing :pod 初始化中
- DockerDaemonNotReady :docker還沒有完全啟動
- NetworkPluginNotReady :網絡插件還沒有完全啟動
三、pod遇到的問題
1、pod一直處于Pending狀態
Pending 狀態說明 Pod 還沒有被調度到某個節點上,需要看下 Pod 事件進一步判斷原因,比如
$ kubectl describe pod tikv-0
. ...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 3m (x106 over 33m) default-scheduler 0/4 nodes are available: 1 node(s) had no available volume zone, 2 Insufficient cpu, 3 Insufficient memory.
下面是我遇到的一些原因:
- 節點資源不夠
節點資源不夠有以下幾種情況:
1、CPU負載過高
2、剩余可被分配的內存不足
3、剩余可用GPU數量不足
如果判斷某個 Node 資源是否足夠?通過下面的命令查看node資源情況,關注以下信息:
kubectl describe node nodename
- Allocatable : 表示此節點能夠申請的資源總和
- Allocated resources : 表示此節點已分配的資源 (Allocatable 減去節點上
- 所有 Pod 總 的 Request)
前者與后者相減,可得出剩余可申請的資源。如果這個值小于 Pod 的 request,就不滿足 Pod 的 資源要求,Scheduler 在 Predicates (預選) 階段就會剔除掉這個 Node,也就不會調度上去。
不滿足 nodeSelector 與 affinity
如果節點上存在污點 (Taints),而 Pod 沒有響應的容忍 (Tolerations),Pod 也將不會調度上 去。通過 describe node 可以看下 Node 有哪些 Taints:
$ kubectl describe nodes host1
...
Taints: special=true:NoSchedule
污點既可以是手動添加也可以是被自動添加,下面可以看一下。
手動添加的污點:
通過類似以下方式可以給節點添加污點:
$ kubectl taint node host1 special=true:NoSchedule node "host1" tainted
另外,有些場景下希望新加的節點默認不調度 Pod,直到調整完節點上某些配置才允許調度,就給新加 的節點都加上node.kubernetes.io/unschedulable 這個污點。
自動添加的污點
如果節點運行狀態不正常,污點也可以被自動添加,從 v1.12 開始, TaintNodesByCondition 特性進入 Beta 默認開啟,controller manager 會檢查 Node 的 Condition,如果命中條件 就自動為 Node 加上相應的污點,這些 Condition 與 Taints 的對應關系如下:
Conditon Value Taints -------- ----- ------ OutOfDisk True node.kubernetes.io/out-of-disk Ready False node.kubernetes.io/not-ready Ready Unknown node.kubernetes.io/unreachable MemoryPressure True node.kubernetes.io/memory-pressure PIDPressure True node.kubernetes.io/pid-pressure DiskPressure True node.kubernetes.io/disk-pressure NetworkUnavailable True node.kubernetes.io/network-unavailable
解釋下上面各種條件的意思:
- OutOfDisk 為 True 表示節點磁盤空間不夠了
- Ready 為 False 表示節點不健康
- Ready 為 Unknown 表示節點失聯,在 node-monitor-grace-period 這
- 么長的時間內沒有 上報狀態 controller-manager 就會將 Node 狀態置
- 為 Unknown (默認 40s)
- MemoryPressure 為 True 表示節點內存壓力大,實際可用內存很少
- PIDPressure 為 True 表示節點上運行了太多進程,PID 數量不夠用了
- DiskPressure 為 True 表示節點上的磁盤可用空間太少了
- NetworkUnavailable 為 True 表示節點上的網絡沒有正確配置,無法跟
- 其它 Pod 正常通 信
另外,在云環境下,比如騰訊云 TKE,添加新節點會先給這個 Node 加上node.cloudprovider.kubernetes.io/uninitialized 的污點,等 Node 初始化成功后才自動移 除這個污點,避免 Pod 被調度到沒初始化好的 Node 上。
- kube-scheduler 沒有正常運行
檢查 maser 上的 kube-scheduler 是否運行正常,異常的話可以嘗試重啟臨時恢復。
3、Pod 處于 CrashLoopBackOff 狀態
Pod 如果處于 CrashLoopBackOff 狀態說明之前是啟動了,只是又異常退出了,只要 Pod 的 restartPolicy不是 Never 就可能被重啟拉起,此時 Pod 的 RestartCounts 通常是大于 0 的,可以先看下容器進程的退出狀態碼來縮小問題范圍
容器進程主動退出:
如果是容器進程主動退出,退出狀態碼一般在 0-128 之間,除了可能是業務程序 BUG,還有其它許 多可能原因
系統OOM
如果發生系統 OOM,可以看到 Pod 中容器退出狀態碼是 137,表示被 SIGKILL 信號殺死,同時 內核會報錯: Out of memory: Kill process … 。大概率是節點上部署了其它非 K8S 管理的進 程消耗了比較多的內存,或者 kubelet 的 --kube-reserved 和 --system-reserved 配的 比較小,沒有預留足夠的空間給其它非容器進程,節點上所有 Pod 的實際內存占用總量不會超過 /sys/fs/cgroup/memory/kubepods 這里 cgroup 的限制,這個限制等于 capacity - "kube- reserved" - "system-reserved" ,如果預留空間設置合理,節點上其它非容器進程(kubelet, dockerd, kube-proxy, sshd 等) 內存占用沒有超過 kubelet 配置的預留空間是不會發生系統 OOM 的,可以根據實際需求做合理的調整。
系統OOM
如果是 cgrou OOM 殺掉的進程,從 Pod 事件的下 Reason 可以看到是 OOMKilled ,說明 容器實際占用的內存超過 limit 了,同時內核日志會報: ``。可以根據需求調整下 limit。
節點內存碎片化
如果節點上內存碎片化嚴重,缺少大頁內存,會導致即使總的剩余內存較多,但還是會申請內存失敗,
健康檢查失敗
2、Pod 一直處于 ContainerCreating 或 Waiting 狀 態
Pod 配置錯誤
- 檢查是否打包了正確的鏡像
- 檢查配置了正確的容器參數
掛載 Volume 失敗
- Volume 掛載失敗也分許多種情況,先列下我這里目前已知的。
- limit 設置太小或者單位不對
如果 limit 設置過小以至于不足以成功運行 Sandbox 也會造成這種狀態,常見的是因為 memory limit 單位設置不對造成的 limit 過小,比如誤將 memory 的 limit 單位像 request 一樣設 置為小 m ,這個單位在 memory 不適用,會被 k8s 識別成 byte, 應該用 Mi 或M
拉取鏡像失敗
- 鏡像拉取失敗也分很多情況,這里列舉下:
- 配置了錯誤的鏡像
- Kubelet 無法訪問鏡像倉庫(比如默認 pause 鏡像在 gcr.io 上,國內環境訪問需要特殊處 理)
- 拉取私有鏡像的
imagePullSecret沒有配置或配置有誤 - 鏡像太大,拉取超時
3. Pod 一直處于 Terminating 狀態
- 磁盤爆滿
如果 docker 的數據目錄所在磁盤被寫滿,docker 無法正常運行,無法進行刪除和創建操作,所以 kubelet 調用 docker 刪除容器沒反應,看 event 類似這樣:
- 存在 Finalizers
k8s 資源的 metadata 里如果存在 finalizers ,那么該資源一般是由某程序創建的,并且在其 創建的資源的 metadata 里的 finalizers 加了一個它的標識,這意味著這個資源被刪除時需要 由創建資源的程序來做刪除前的清理,清理完了它需要將標識從該資源的 finalizers 中移除,然 后才會最終徹底刪除資源。比如 Rancher 創建的一些資源就會寫入 finalizers 標識。
處理建議:kubectl edit 手動編輯資源定義,刪掉 finalizers ,這時再看下資源,就會發現 已經刪掉了
4、Pod 一直處于 Unknown 狀態
通常是節點失聯,沒有上報狀態給 apiserver,到達閥值后 controller-manager 認為節點失聯 并將其狀態置為 Unknown
可能原因:
- 節點高負載導致無法上報
- 節點宕機
- 節點被關機
- 網絡不通
5、Pod 一直處于 Error 狀態
通常處于 Error 狀態說明 Pod 啟動過程中發生了錯誤。常見的原因包括:
- 依賴的 ConfigMap、Secret 或者 PV 等不存在
- 請求的資源超過了管理員設置的限制,比如超過了
LimitRange等 - 違反集群的安全策略,比如違反了
PodSecurityPolicy等 - 容器無權操作集群內的資源,比如開啟 RBAC 后,需要為
ServiceAccount配置角色綁定
6、Pod 一直處于 ImagePullBackOff 狀態
- http 類型 registry,地址未加入到 insecure- registry
dockerd 默認從 https 類型的 registry 拉取鏡像,如果使用 https 類型的 registry,則 必須將它添加到 insecure-registry 參數中,然后重啟或 reload dockerd 生效。
- https 自簽發類型 resitry,沒有給節點添加 ca 證書
如果 registry 是 https 類型,但證書是自簽發的,dockerd 會校驗 registry 的證書,校驗 成功才能正常使用鏡像倉庫,要想校驗成功就需要將 registry 的 ca 證書放置到/etc/docker/certs.d/<registry:port>/ca.crt 位置
- 私有鏡像倉庫認證失敗
如果 registry 需要認證,但是 Pod 沒有配置 imagePullSecret,配置的 Secret 不存在或者 有誤都會認證失敗。
- 鏡像文件損壞
如果 push 的鏡像文件損壞了,下載下來也用不了,需要重新 push 鏡像文件。
- 鏡像拉取超時
如果節點上新起的 Pod 太多就會有許多可能會造成容器鏡像下載排隊,如果前面有許多大鏡像需要下 載很長時間,后面排隊的 Pod 就會報拉取超時。
- 鏡像不存在
鏡像配置錯誤或者鏡像不存在會導致拉取超時。

浙公網安備 33010602011771號