k8s deployment問題排查思路

端口回顧
現在我們來快速回顧一下哪些端口和標籤應該匹配:

Service selector 應與 Pod 的標籤匹配
Service 的 targetPort 應與 Pod 中容器的 containerPort 匹配
Service 的端口可以是任何數字。多個服務可以使用同一端口,因爲它們分配了不同的 IP 地址
Ingress 的 servicePort 應該匹配 Service 的 port
Serivce 的名稱應與 Ingress 中的 serviceName 字段匹配
知道了如何定義 YAML 資源清單文件這只是我們故事的一部分。出了問題後該怎麼辦?Pod 可能無法啓動,或者正在崩潰。接下來給大家介紹幾種常見的故障排查方法。

故障排查3步驟
在深入研究失敗的 Deployment 之前,我們必須對 Kubernetes 的工作原理有一個明確定義的模型。由於每個Deployment 中都有三個組件,因此你應該自下而上依次調試所有組件。

你應該先確保 Pods 正在運行
然後,專注於讓 Service 將流量路由到正確的 Pod
然後,檢查是否正確配置了 Ingress
你應該從底部開始對 Deployment 進行故障排除。首先,檢查 Pod 是否已就緒並正在運行。
1 /3

你應該從底部開始對 Deployment 進行故障排除。首先,檢查 Pod 是否已就緒並正在運行。
Next
如果 Pod 已就緒,則應查看 Service 是否可以將流量分配給 Pod。
2 /3
Prev
如果 Pod 已就緒,則應查看 Service 是否可以將流量分配給 Pod。
Next
最後,你應該檢查 Service與 Ingress 之間的連接。
3 /3
Prev
最後,你應該檢查 Service與 Ingress 之間的連接。

1.Pod 故障排查
在大多數情況下,問題出在 Pod 本身。你應該確保 Pod 正在運行並準備就緒。該如何檢查呢?

$ kubectl get pods
NAME READY STATUS RESTARTS AGE
app1 0/1 ImagePullBackOff 0 47h
app2 0/1 Error 0 47h
app3-76f9fcd46b-xbv4k 1/1 Running 1 47h
在上述會話中,最後一個 Pod 處於就緒並正常運行的狀態;但是,前兩個 Pod 既不處於 Running 也不是 Ready。

你應該如何查看出了什麼問題呢?有四個有用的命令可以對 Pod 進行故障排除:

kubectl logs 有助於檢索 Pod 容器的日誌
kubectl describe pod 檢索與 Pod 相關的事件列表很有用
kubectl get pod 用於提取存儲在 Kubernetes 中的 Pod 的 YAML 定義
kubectl exec -it bash 在 Pod 的一個容器中運行交互式命令很有用
那麼應該使用哪一個呢?沒有一種萬能的。相反,我們應該結合着使用它們。

常見 Pod 錯誤
Pod 可能會出現啓動和運行時錯誤。啓動錯誤包括:

ImagePullBackoff
ImageInspectError
ErrImagePull
ErrImageNeverPull
RegistryUnavailable
InvalidImageName
運行時錯誤包括:

CrashLoopBackOff
RunContainerError
KillContainerError
VerifyNonRootError
RunInitContainerError
CreatePodSandboxError
ConfigPodSandboxError
KillPodSandboxError
SetupNetworkError
TeardownNetworkError
有些錯誤比其他錯誤更常見。以下是最常見的錯誤列表以及如何修復它們的方法。

ImagePullBackOff
當 Kubernetes 無法獲取到 Pod 中某個容器的鏡像時,將出現此錯誤。共有三個可能的原因:

鏡像名稱無效-例如,你拼錯了名稱,或者鏡像不存在
你爲鏡像指定了不存在的標籤
你嘗試檢索的鏡像屬於一個私有 registry,而 Kubernetes 沒有憑據可以訪問它
前兩種情況可以通過修改鏡像名稱和標記來解決。針對第三種情況,你應該將私有 registry 的訪問憑證通過 Secret添加到 Kubernetes 中並在 Pod 中引用它。

官方文檔中有一個有關如何實現此目標的示例。

CrashLoopBackOff
如果容器無法啓動,則 Kubernetes 將顯示錯誤狀態爲:CrashLoopBackOff。

通常,在以下情況下容器無法啓動:

應用程序中存在錯誤,導致無法啓動
你未正確配置容器
Liveness 探針失敗太多次
你應該嘗試從該容器中檢索日誌以調查其失敗的原因。如果由於容器重新啓動太快而看不到日誌,則可以使用以下命令:

$ kubectl logs --previous
這個命令可以打印前一個容器的錯誤日誌信息。

RunContainerError
當容器無法啓動時,會出現此錯誤。甚至在容器內的應用程序啓動之前。該問題通常是由於配置錯誤,例如:

掛載不存在的卷,例如 ConfigMap 或 Secrets
將只讀卷掛載爲可讀寫
你應該使用kubectl describe pod命令收集和分析錯誤
Pending 狀態的 Pod
當創建 Pod 時,該 Pod 處於 Pending 狀態。爲什麼?假設你的調度程序組件運行良好,可能的原因如下:

集羣沒有足夠的資源(例如CPU和內存)來運行 Pod
當前的命名空間具有 ResourceQuota 對象,創建 Pod 將使命名空間超過配額
該 Pod 綁定到一個處於 pending 狀態的 PersistentVolumeClaim
最好的選擇是檢查kubectl describe命令輸出的“事件”部分內容:

$ kubectl describe pod
對於因 ResourceQuotas 而導致的錯誤,可以使用以下方法檢查集羣的日誌:

$ kubectl get events --sort-by=.metadata.creationTimestamp
未就緒狀態的 Pod
如果 Pod 正在運行但未就緒(not ready),則表示 readiness 就緒探針失敗。當“就緒”探針失敗時,Pod 未連接到服務,並且沒有流量轉發到該實例。

就緒探針失敗是應用程序的特定錯誤,因此你應檢查kubectl describe中的“事件”部分以識別錯誤。

2.Service 故障排查
如果你的 Pod 正在運行並處於就緒狀態,但仍無法收到應用程序的響應,則應檢查服務的配置是否正確。

Service 旨在根據標籤將流量路由到對應的 Pod。因此,你應該檢查的第一件事是服務關聯了多少個 Pod。你可以通過檢查服務中的端點(endpoint)來做到這一點:

$ kubectl describe service | grep Endpoints
端點是一個集合,並且在服務以 Pod 爲目標時,應該至少有一個端點。如果“端點”部分爲空,則有兩種解釋:

你沒有運行帶有正確標籤的 Pod(應檢查自己是否在正確的命名空間中)
Service 的 selector 標籤上有錯字
如果你看到端點列表,但仍然無法訪問你的應用程序,則 targetPort 很有可能不匹配導致的。那我們應該如何測試 Service 呢?

無論服務類型如何,你都可以使用kubectl port-forward來連接它:

$ kubectl port-forward service/ 3000:80
3.Ingress 的故障排查
如果你已經排查到這一步了的話,則:

Pod 正在運行並準備就緒
Serivce 會將流量分配到 Pod
但是你仍然看不到應用程序的響應。這意味着最有可能是 Ingress 配置錯誤。由於正在使用的 Ingress 控制器是集羣中的第三方組件,因此有不同的調試技術,具體取決於 Ingress 控制器的類型。

但是在深入研究 Ingress 專用工具之前,你可以用一些簡單的方法進行檢查。

Ingress 使用 serviceName 和 servicePort 連接到 Service。你應該檢查這些配置是否正確。你可以通過下面命令檢查 Ingress 配置是否正確:

$ kubectl describe ingress
如果 backend 一列爲空,則配置中必然有一個錯誤。如果你可以在“backend”列中看到端點,但是仍然無法訪問該應用程序,則可能是以下問題:

你如何將 Ingress 暴露於公網的
你如何將集羣暴露於公網的
你還可以通過直接連接到 Ingress Pod 來將基礎問題與 Ingress 隔離開。首先,獲取你的 Ingress 控制器 Pod(可以位於其他名稱空間中):

$ kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS
kube-system coredns-5644d7b6d9-jn7cq 1/1 Running
kube-system etcd-minikube 1/1 Running
kube-system kube-apiserver-minikube 1/1 Running
kube-system kube-controller-manager-minikube 1/1 Running
kube-system kube-proxy-zvf2h 1/1 Running
kube-system kube-scheduler-minikube 1/1 Running
kube-system nginx-ingress-controller-6fc5bcc 1/1 Running
然後描述它以獲取 Ingress 控制器 Pod 的端口:

$ kubectl describe pod nginx-ingress-controller-6fc5bcc
–namespace kube-system
| grep Ports
最後,連接到 Pod:

$ kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-system
此時,每次你訪問計算機上的端口 3000 時,請求都會轉發到 Pod 上的端口 80。現在可以用嗎?

如果可行,則問題出在基礎架構中,你應該調查流量如何路由到你的集羣。
如果不起作用,則問題出在 Ingress 控制器中,你應該調試 Ingress。
如果仍然無法使 Ingress 控制器正常工作,則應開始對其進行調試。目前有許多不同版本的 Ingress 控制器。熱門選項包括 Nginx,HAProxy,Traefik 等,你應該查閱 Ingress 控制器的文檔以查找故障排除指南。

由於 Ingress Nginx 是最受歡迎的 Ingress 控制器,因此接下來我們將介紹一些有關調試 ingress-nginx 的技巧。

調試 Ingress Nginx
Ingress-nginx 項目有一個 Kubectl 的官方插件。

你可以使用 kubectl ingress-nginx :

檢查日誌,後端,證書等。
連接到 ingress
檢查當前配置
你應該嘗試的三個命令是:

kubectl ingress-nginx lint,它會檢查 nginx.conf 配置
kubectl ingress-nginx backend,它會檢查後端(類似於kubectl describe ingress)
kubectl ingress-nginx logs,查看日誌
請注意,你可能需要爲 Ingress 控制器指定正確的名稱空間 namespace。

總結
如果你不知道從哪裏開始,那麼在 Kubernetes 中進行故障排查可能是一項艱鉅的任務。你應該始終牢記從下至上解決問題:從 Pod 開始,然後通過 Service 和 Ingress 向上移動排查。

你在本文中瞭解到的調試技術也可以應用於其他對象,例如:

failing Job 和 CronJob
StatefulSets 和 DaemonSets

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章