Pod 排錯
本章介紹 Pod 運行異常的排錯方法。
一般來說,無論 Pod 處於什麼異常狀態,都可以執行以下命令來查看 Pod 的狀態
kubectl get pod <pod-name> -o yaml查看 Pod 的配置是否正確kubectl describe pod <pod-name>查看 Pod 的事件kubectl logs <pod-name> [-c <container-name>]查看容器日誌
這些事件和日誌通常都會有助於排查 Pod 發生的問題。
Pod 一直處於 Pending 狀態
Pending 說明 Pod 還沒有調度到某個 Node 上面。可以通過 kubectl describe pod <pod-name> 命令查看到當前 Pod 的事件,進而判斷爲什麼沒有調度。如
$ kubectl describe pod mypod
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 12s (x6 over 27s) default-scheduler 0/4 nodes are available: 2 Insufficient cpu.可能的原因包括
資源不足,集群內所有的 Node 都不滿足該 Pod 請求的 CPU、內存、GPU 或者臨時存儲空間等資源。解決方法是刪除集群內不用的 Pod 或者增加新的 Node。
HostPort 端口已被佔用,通常推薦使用 Service 對外開放服務端口
Pod 一直處於 Waiting 或 ContainerCreating 狀態
首先還是通過 kubectl describe pod <pod-name> 命令查看到當前 Pod 的事件
可以發現,該 Pod 的 Sandbox 容器無法正常啓動,具體原因需要查看 Kubelet 日誌:
發現是 cni0 網橋配置了一個不同網段的 IP 地址導致,刪除該網橋(網絡插件會自動重新創建)即可修復
除了以上錯誤,其他可能的原因還有
鏡像拉取失敗,比如
配置了錯誤的鏡像
Kubelet 無法訪問鏡像(國內環境訪問
gcr.io需要特殊處理)私有鏡像的密鑰配置錯誤
鏡像太大,拉取超時(可以適當調整 kubelet 的
--image-pull-progress-deadline和--runtime-request-timeout選項)
CNI 網絡錯誤,一般需要檢查 CNI 網絡插件的配置,比如
無法配置 Pod 網絡
無法分配 IP 地址
容器無法啓動,需要檢查是否打包了正確的鏡像或者是否配置了正確的容器參數
Pod 處於 ImagePullBackOff 狀態
這通常是鏡像名稱配置錯誤或者私有鏡像的密鑰配置錯誤導致。這種情況可以使用 docker pull <image> 來驗證鏡像是否可以正常拉取。
如果是私有鏡像,需要首先創建一個 docker-registry 類型的 Secret
然後在容器中引用這個 Secret
Pod 一直處於 CrashLoopBackOff 狀態
CrashLoopBackOff 狀態說明容器曾經啓動了,但又異常退出了。此時 Pod 的 RestartCounts 通常是大於 0 的,可以先查看一下容器的日誌
這裏可以發現一些容器退出的原因,比如
容器進程退出
健康檢查失敗退出
OOMKilled
如果此時如果還未發現線索,還可以到容器內執行命令來進一步查看退出原因
如果還是沒有線索,那就需要 SSH 登錄該 Pod 所在的 Node 上,查看 Kubelet 或者 Docker 的日誌進一步排查了
Pod 處於 Error 狀態
通常處於 Error 狀態說明 Pod 啓動過程中發生了錯誤。常見的原因包括
依賴的 ConfigMap、Secret 或者 PV 等不存在
請求的資源超過了管理員設置的限制,比如超過了 LimitRange 等
違反集群的安全策略,比如違反了 PodSecurityPolicy 等
容器無權操作集群內的資源,比如開啓 RBAC 後,需要爲 ServiceAccount 配置角色綁定
Pod 處於 Terminating 或 Unknown 狀態
從 v1.5 開始,Kubernetes 不會因爲 Node 失聯而刪除其上正在運行的 Pod,而是將其標記爲 Terminating 或 Unknown 狀態。想要刪除這些狀態的 Pod 有三種方法:
從集群中刪除該 Node。使用公有云時,kube-controller-manager 會在 VM 刪除後自動刪除對應的 Node。而在物理機部署的集群中,需要管理員手動刪除 Node(如
kubectl delete node <node-name>。Node 恢復正常。Kubelet 會重新跟 kube-apiserver 通信確認這些 Pod 的期待狀態,進而再決定刪除或者繼續運行這些 Pod。
用戶強制刪除。用戶可以執行
kubectl delete pods <pod> --grace-period=0 --force強制刪除 Pod。除非明確知道 Pod 的確處於停止狀態(比如 Node 所在 VM 或物理機已經關機),否則不建議使用該方法。特別是 StatefulSet 管理的 Pod,強制刪除容易導致腦裂或者數據丟失等問題。
如果 Kubelet 是以 Docker 容器的形式運行的,此時 kubelet 日誌中可能會發現如下的錯誤:
如果是這種情況,則需要給 kubelet 容器設置 --containerized 參數並傳入以下的存儲卷
處於 Terminating 狀態的 Pod 在 Kubelet 恢復正常運行後一般會自動刪除。但有時也會出現無法刪除的情況,並且通過 kubectl delete pods <pod> --grace-period=0 --force 也無法強制刪除。此時一般是由於 finalizers 導致的,通過 kubectl edit 將 finalizers 刪除即可解決。
Pod 行爲異常
這裏所說的行爲異常是指 Pod 沒有按預期的行爲執行,比如沒有運行 podSpec 裏面設置的命令行參數。這一般是 podSpec yaml 文件內容有誤,可以嘗試使用 --validate 參數重建容器,比如
也可以查看創建後的 podSpec 是否是對的,比如
修改靜態 Pod 的 Manifest 後未自動重建
Kubelet 使用 inotify 機制檢測 /etc/kubernetes/manifests 目錄(可通過 Kubelet 的 --pod-manifest-path 選項指定)中靜態 Pod 的變化,並在文件發生變化後重新創建相應的 Pod。但有時也會發生修改靜態 Pod 的 Manifest 後未自動創建新 Pod 的情景,此時一個簡單的修復方法是重啓 Kubelet。
Nginx 啓動失敗
Nginx 啓動失敗,錯誤消息是 nginx: [emerg] socket() [::]:8000 failed (97: Address family not supported by protocol)。這是由於服務器未開啓 IPv6 導致的,解決方法有兩種:
第一種方法,服務器開啓 IPv6;
或者,第二種方法,刪除或者註釋掉
/etc/nginx/conf.d/default.conf文件中的listen [::]:80 default_server;。
Namespace 一直處於 terminating 狀態
Namespace 一直處於 terminating 狀態,一般有兩種原因:
Namespace 中還有資源正在刪除中
Namespace 的 Finalizer 未正常清理
對第一個問題,可以執行下面的命令來查詢所有的資源
而第二個問題則需要手動清理 Namespace 的 Finalizer 列表:
1) 使用 kubectl patch:
2) 使用 kubectl proxy:
3) 使用 kubectl --raw:
Pod 排錯圖解

(圖片來自A visual guide on troubleshooting Kubernetes deployments)
參考文檔
Last updated