Kubernetes 排錯之 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 的事件,進而判斷為什么沒有調度。可能的原因包括
- 資源不足,集群內所有的 Node 都不滿足該 Pod 請求的 CPU、內存、GPU 等資源
- HostPort 已被占用,通常推薦使用 Service 對外開放服務端口
Pod 一直處於 Waiting 或 ContainerCreating 狀態
首先還是通過 kubectl describe pod <pod-name> 命令查看到當前 Pod 的事件。可能的原因包括
- 鏡像拉取失敗,比如
- 配置了錯誤的鏡像
- Kubelet 無法訪問鏡像(國內環境訪問
gcr.io需要特殊處理) - 私有鏡像的密鑰配置錯誤
- 鏡像太大,拉取超時(可以適當調整 kubelet 的
--image-pull-progress-deadline和--runtime-request-timeout選項)
- CNI 網絡錯誤,一般需要檢查 CNI 網絡插件的配置,比如
- 無法配置 Pod 網絡
- 無法分配 IP 地址
- 容器無法啟動,需要檢查是否打包了正確的鏡像或者是否配置了正確的容器參數
Pod 處於 ImagePullBackOff 狀態
這通常是鏡像名稱配置錯誤或者私有鏡像的密鑰配置錯誤導致。這種情況可以使用 docker pull <image> 來驗證鏡像是否可以正常拉取。
如果是私有鏡像,需要首先創建一個 docker-registry 類型的 Secret
kubectl create secret docker-registry my-secret --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL
然后在容器中引用這個 Secret
spec:
containers:
- name: private-reg-container
image: <your-private-image>
imagePullSecrets:
- name: my-secret
Pod 一直處於 CrashLoopBackOff 狀態
CrashLoopBackOff 狀態說明容器曾經啟動了,但又異常退出了。此時可以先查看一下容器的日志
kubectl logs <pod-name>
kubectl logs --previous <pod-name>
這里可以發現一些容器退出的原因,比如
- 容器進程退出
- 健康檢查失敗退出
此時如果還未發現線索,還可以到容器內執行命令來進一步查看退出原因
kubectl exec cassandra -- cat /var/log/cassandra/system.log
如果還是沒有線索,那就需要 SSH 登錄該 Pod 所在的 Node 上,查看 Kubelet 或者 Docker 的日志進一步排查了
# 查詢 Node
kubectl get pod <pod-name> -o wide
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,強制刪除容易導致腦裂或者數據丟失等問題。
Pod 行為異常
這里所說的行為異常是指 Pod 沒有按預期的行為執行,比如沒有運行 podSpec 里面設置的命令行參數。這一般是 podSpec yaml 文件內容有誤,可以嘗試使用 --validate 參數重建容器,比如
kubectl delete pod mypod
kubectl create --validate -f mypod.yaml
也可以查看創建后的 podSpec 是否是對的,比如
kubectl get pod mypod -o yaml
修改靜態 Pod 的 Manifest 后未自動重建
Kubelet 使用 inotify 機制檢測 /etc/kubernetes/manifests 目錄(可通過 Kubelet 的 --pod-manifest-path 選項指定)中靜態 Pod 的變化,並在文件發生變化后重新創建相應的 Pod。但有時也會發生修改靜態 Pod 的 Manifest 后未自動創建新 Pod 的情景,此時一個簡單的修復方法是重啟 Kubelet。
