1. 程式人生 > >Kubernetes(k8s)中文文件 應用程式相關的故障排查_Kubernetes中文社群

Kubernetes(k8s)中文文件 應用程式相關的故障排查_Kubernetes中文社群

譯者:林帆

這個小節將幫助讀者除錯部署在Kubernetes的應用程式執行不正常的情況。本篇並不會包含如何除錯叢集組建過程中出現錯誤的問題,這些內容在文件的下一節中進行介紹。

內容提要

  • 應用程式故障排查
    • 常見問題
    • 故障診斷
      • 排查Pods的故障
        • Pod始終處於Pending狀態
        • Pod始終處於Waiting狀態
        • Pod一直崩潰或執行不正常
        • Pod在執行但沒有如預期工作
      • 排查Replication Controllers的故障
      • 排查Services的故障
        • 服務沒有端點資訊
        • 網路流量沒有正確的轉發
        • 其他問題

常見問題

一些經常被提到的問題都更新在Kubernetes專案GitHub的

常見問題頁面。

故障診斷

故障排查的第一步是對故障進行分類。一般來說,應用程式的故障可以分為下面幾個方面:

  • Pods的故障
  • ReplicationControllers的故障
  • Services的故障

排查Pods的故障

檢查Pod的問題首先應該瞭解Pod所處的狀況。下面這個命令能夠獲得Pod當前的狀態和近期的事件列表:

$ kubectl describe pods ${POD_NAME}

確認清楚在Pod以及其中每一個容器的狀態,是否都處於Runing?通過觀察容器的已執行時間判斷它是否剛剛才重新啟動過?

根據不同的執行狀態,使用者應該採取不同的調查措施。

Pod始終處於Pending狀態

如果Pod保持在Pending的狀態,這意味著它無法被正常的排程到一個節點上。通常來說,這是由於某種系統資源無法滿足Pod執行的需求。觀察剛才kubectl describe命令的輸出內容,其中應該包括了能夠判斷錯誤原因的訊息。常見的原因有以下這些:

  • 系統沒有足夠的資源:你也許已經用盡了叢集中所有的CPU或記憶體資源。對於這種情況,你需要清理一些不在需要的Pod,調整它們所需的資源量,或者向叢集中增加新的節點。在計算資源文件有更詳細的說明。
  • 使用者指定了hostPort:通過hostPort使用者能夠將服務暴露到指定的主機埠上,但這樣會限制Pod能夠被排程執行的節點。在大多數情況下,hostPort
    配置都是沒有必要的,使用者應該採用Service的方式暴露其對外的服務。如果使用者確實必須使用hostPort的功能,那麼此Pod最多隻能部署到和叢集節點相同的數目。

Pod始終處於Waiting狀態

Pod處在Waiting的狀態,說明它已經被排程分配到了一個工作節點,然而它無法在那個節點上執行。同樣的,在剛才kubectl describe命令的輸出內容中,應該包含有更詳細的錯誤資訊。最經常導致Pod始終Waiting的原因是無法下載所需的映象(譯者注:由於國內特殊的網路環境,這類問題出現得特別普遍)。使用者可以從下面三個方面進行排查:

  • 請確保正確書寫了映象的名稱
  • 請檢查所需映象是否已經推送到了倉庫中
  • 手工的在節點上執行一次docker pull <映象名稱>檢測映象能否被正確的拉取下來

Pod一直崩潰或執行不正常

首先,檢視正在執行容器的日誌。

$ kubectl logs <Pod名稱> <Pod中的容器名稱>

如果容器之前已經崩潰過,通過以下命令可以獲得容器前一次執行的日誌內容。

$ kubectl logs --previous <Pod名稱> <Pod中的容器名稱>

此外,還可以使用exec命令在指定的容器中執行任意的除錯命令。

$ kubectl exec <Pod名稱> -c <Pod中的容器名稱> -- <任意命令> <命令引數列表...>

值得指出的是,對於只有一個容器的Pod情況,-c <Pod中的容器名稱>這個引數是可以省略的。

例如檢視一個執行中的Cassandra日誌檔案內容,可以參考下面這個命令:

$ kubectl exec cassandra -- cat /var/log/cassandra/system.log

要是上面的這些辦法都不奏效,你也可以找到正在執行該Pod的主機地址,然後使用SSH登陸進去檢測。但這是在確實迫不得已的情況下才會採用的措施,通常使用Kubernetes暴露的API應該足夠獲得所需的環境資訊。因此,如果當你發現自己不得不登陸到主機上去獲取必要的資訊資料時,不妨到Kubernetes的GitHub頁面中給我們提一個功能需求(Feature Request),在需求中附上詳細的使用場景以及為什麼當前Kubernetes所提供的工具不能夠滿足需要。

Pod在執行但沒有如預期工作

如果Pod沒有按照預期的功能執行,有可能是由於在Pod描述檔案中(例如你本地機器的mypod.yaml檔案)存在一些錯誤,這些配置中的錯誤在Pod時建立並沒有引起致命的故障。這些錯誤通常包括Pod描述的某些元素巢狀層級不正確,或是屬性的名稱書寫有誤(這些錯誤屬性在執行時會被忽略掉)。舉例來說,如果你把command屬性誤寫為了commnd,Pod仍然會啟動,但使用者所期待執行的命令則不會被執行。

對於這種情況,首先應該嘗試刪掉正在執行的Pod,然後使用--validate引數重新執行一次。繼續之前的例子,當執行kubectl create --validate -f mypod.yaml命令時,被誤寫為commndcommand指令會導致下面這樣的錯誤:

I0805 10:43:25.129850   46757 schema.go:126] unknown field: commnd
I0805 10:43:25.129973   46757 schema.go:129] this may be a false alarm, see https://github.com/kubernetes/kubernetes/issues/6842
pods/mypod

下一件事是檢查當前apiserver執行Pod所使用的Pod描述檔案內容是否與你想要建立的Pod內容(使用者本地主機的那個yaml檔案)一致。比如,執行kubectl get pods/mypod -o yaml > mypod-on-apiserver.yaml命令將正在執行的Pod描述檔案內容匯出來儲存為mypod-on-apiserver.yaml,並將它和使用者自己的Pod描述檔案mypod.yaml進行對比。由於apiserver會嘗試自動補全一些缺失的Pod屬性,在apiserver匯出的Pod描述檔案中有可能比本地的Pod描述檔案多出若干行,這是正常的,但反之如果本地的Pod描述檔案比apiserver匯出的Pod描述檔案多出了新的內容,則很可能暗示著當前執行的Pod使用了不正確的內容。

排查Replication Controllers的故障

Replication Controllers的邏輯十分直白,它的作用只是建立新的Pod副本,僅僅可能出現的錯誤便是它無法建立正確的Pod,對於這種情況,應該參考上面的『排查Pods的故障』部分進行檢查。

也可以使用kubectl describe rc <控制器名稱>來顯示與指定Replication Controllers相關的事件資訊。

Service為一系列後端Pod提供負載均衡的功能。有些十分常見的故障都可能導致Service無法正常工作,以下將提供對除錯Service相關問題的參考。

首先,檢查Service連線的服務提供端點(endpoint),對於任意一個Service物件,apiserver都會為其建立一個端點資源(譯者注:即提供服務的IP地址和埠號)。

這個命令可以檢視到Service的埠資源:

$ kubectl get endpoints <Service名稱>

請檢查這個命令輸出端點資訊中的埠號與實際容器提供服務的埠號是否一致。例如,如果你的Service使用了三個Nginx容器的副本(replicas),這個命令應該輸出三個不同的IP地址的端點資訊。

服務沒有端點資訊

如果剛剛的命令顯示Service沒有端點資訊,請嘗試通過Service的選擇器找到具有相應標籤的所有Pod。假設你的Service描述選擇器內容如下:

...
spec:
  - selector:
     name: nginx
     type: frontend

可以使用以下命令找出相應的Pod:

$ kubectl get pods --selector=name=nginx,type=frontend

找到了符合標籤的Pod後,首先確認這些被選中的Pod是正確,有無錯選、漏選的情況。

如果被選中的Pod沒有問題,則問題很可能出在這些Pod暴露的埠沒有被正確的配置好。要是一個Service指定了containerPort,但被選中的Pod並沒有在配置中列出相應的埠,它們就不會出現在端點列表中。

請確保所用Pod的containerPort與Service的containerPort配置資訊是一致的。

網路流量沒有正確的轉發

如果你能夠連線到Service,但每次連線上就立即被斷開,同時Service的端點列表內容是正確的,很可能是因為Kubernetes的kube-proxy服務無法連線到相應的Pod。

請檢查以下幾個方面:

  • Pod是否在正常工作?從每個Pod的自動重啟動次數可以作為有用的參考資訊,前面介紹過的Pod錯誤排查也介紹了更詳細的方法
  • 能夠直接連線到Pod提供的服務埠上嗎?不妨獲取到Pod的IP地址,然後嘗試直接連線它,以驗證Pod本身十分執行正確。
  • 容器中的應用程式是否監聽在Pod和Service中配置的那個埠?Kubernetes不會自動的對映埠號,因此如果應用程式監聽在8080埠,務必保證Service和Pod的containerPort都配置為了8080。

其他問題

如果上述的這些步驟還不足以解答你所遇到的問題,也就是說你已經確認了相應的Service正在執行,並且具有恰當的端點資源,相應的Pod能夠提供正確的服務,叢集的DNS域名服務沒有問題,IPtable的防火牆配置沒有問題,kube-proxy服務也都運轉正常。

請參看本文件故障排除部分的其他小節,以獲取更加全面的故障處理資訊。

K8S中文社群微信公眾號