Kubernetes 故障排除視覺化指南

筆記。 翻譯。:本文是在公共領域發布的專案資料的一部分 學習8s,訓練公司和個人管理員使用 Kubernetes。 在其中,專案經理 Daniele Polencic 分享了關於在 K8s 叢集上運行的應用程式出現一般問題時應採取哪些步驟的可視化說明。

Kubernetes 故障排除視覺化指南

TL;DR:這是一個圖表,可以幫助您調試 Kubernetes 中的部署:

Kubernetes 故障排除視覺化指南

尋找和修復叢集中錯誤的流程圖。 原文(英文)可在 PDF и 如圖.

將應用程式部署到 Kubernetes 時,通常需要定義三個元件:

  • 部署 - 這是一種建立應用程式副本的方法,稱為 pod;
  • 服務 — 在 Pod 之間分配流量的內部負載平衡器;
  • 入口 — 流量如何從外部世界到達服務的描述。

這是一個快速的圖形摘要:

1)在Kubernetes中,應用程式透過兩層負載平衡器接收來自外界的流量:內部和外部。

Kubernetes 故障排除視覺化指南

2)內部均衡器稱為Service,外部均衡器稱為Ingress。

Kubernetes 故障排除視覺化指南

3) Deployment 建立 Pod 並監控它們(它們不是手動建立的)。

Kubernetes 故障排除視覺化指南

假設您想部署一個簡單的應用程式 你好世界。 它的 YAML 設定如下圖所示:

apiVersion: apps/v1
kind: Deployment # <<<
metadata:
  name: my-deployment
  labels:
    track: canary
spec:
  selector:
    matchLabels:
      any-name: my-app
  template:
    metadata:
      labels:
        any-name: my-app
    spec:
      containers:
      - name: cont1
        image: learnk8s/app:1.0.0
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service # <<<
metadata:
  name: my-service
spec:
  ports:
  - port: 80
    targetPort: 8080
  selector:
    name: app
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress # <<<
metadata:
  name: my-ingress
spec:
  rules:
  - http:
    paths:
    - backend:
        serviceName: app
        servicePort: 80
      path: /

這個定義相當長,很容易混淆各個元件之間的關係。

例如:

  • 什麼時候應該使用連接埠 80,什麼時候應該使用 8080?
  • 我應該為每個服務建立一個新端口,這樣它們就不會發生衝突嗎?
  • 標籤名稱重要嗎? 它們應該在任何地方都一樣嗎?

在專注於調試之前,讓我們記住這三個元件如何相互關聯。 讓我們從部署和服務開始。

部署與服務的關係

您會感到驚訝,但部署和服務沒有任何關係。 相反,Service 繞過 Deployment 直接指向 Pod。

因此,我們感興趣的是 Pod 和 Services 如何相互關聯。 要記住三件事:

  1. 選擇器(selector) 服務必須至少符合一個 Pod 標籤。
  2. targetPort 必須匹配 containerPort Pod 內的容器。
  3. port 服務可以是任何東西。 不同的服務可以使用相同的端口,因為它們具有不同的IP位址。

下圖以圖形形式表示了上述所有內容:

1) 假設該服務將流量定向到某個 pod:

Kubernetes 故障排除視覺化指南

2)建立pod時,必須指定 containerPort 對於 Pod 中的每個容器:

Kubernetes 故障排除視覺化指南

3)創建服務時,必須指定 port и targetPort. 但要使用哪一個來連接容器呢?

Kubernetes 故障排除視覺化指南

4)透過 targetPort。 必須匹配 containerPort.

Kubernetes 故障排除視覺化指南

5) 假設容器中開啟了3000端口,那麼該值 targetPort 應該是一樣的。

Kubernetes 故障排除視覺化指南

在 YAML 檔案中,標籤和 ports / targetPort 必須匹配:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deployment
  labels:
    track: canary
spec:
  selector:
    matchLabels:
      any-name: my-app
  template:
    metadata:
     labels:  # <<<
        any-name: my-app  # <<<
   spec:
      containers:
      - name: cont1
        image: learnk8s/app:1.0.0
        ports:
       - containerPort: 8080  # <<<
---
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  ports:
  - port: 80
   targetPort: 8080  # <<<
 selector:  # <<<
    any-name: my-app  # <<<

標籤怎麼樣 track: canary 在部署部分的頂部? 應該匹配嗎?

此標籤是特定於部署的,服務不使用它來路由流量。 換句話說,它可以被刪除或分配不同的值。

選擇器怎麼樣 matchLabels?

它必須始終與 Pod 的標籤匹配,因為 Deployment 使用它來追蹤 Pod。

假設您進行了正確的編輯。 如何檢查它們?

您可以使用以下命令檢查 pod 標籤:

kubectl get pods --show-labels

或者,如果 Pod 屬於多個應用程式:

kubectl get pods --selector any-name=my-app --show-labels

在哪裡 any-name=my-app 是一個標籤 any-name: my-app.

還有什麼困難嗎?

您可以連接到 Pod! 為此,您需要使用命令 port-forward 在 kubectl. 它允許您連接到服務並檢查連接。

kubectl port-forward service/<service name> 3000:80

在這裡:

  • service/<service name> - 服務名稱; 在我們的例子中是 my-service;
  • 3000是電腦上需要開放的連接埠;
  • 80 - 欄位中指定的端口 port 服務。

如果連線已建立,則設定正確。

如果連線失敗,則表示標籤有問題或連接埠不符。

Service與Ingress的關係

提供對應用程式的存取的下一步涉及設定 Ingress。 Ingress 需要知道如何找到服務,然後找到 Pod 並將流量導向它們。 Ingress 透過名稱和開放連接埠尋找所需的服務。

Ingress 和 Service 的描述中兩個參數必須符合:

  1. servicePort Ingress 中必須符合參數 port 服務中;
  2. serviceName Ingress 中的欄位必須匹配 name 在服務中。

下圖總結了連接埠連線:

1) 如您所知,Service 會監聽特定的 port:

Kubernetes 故障排除視覺化指南

2)Ingress有一個參數叫 servicePort:

Kubernetes 故障排除視覺化指南

3)該參數(servicePort) 必須始終匹配 port 在服務定義中:

Kubernetes 故障排除視覺化指南

4) 如果Service中指定了80端口,則需要 servicePort 也等於 80:

Kubernetes 故障排除視覺化指南

實際操作中,需要注意以下幾行:

apiVersion: v1
kind: Service
metadata:
 name: my-service  # <<<
spec:
  ports:
 - port: 80  # <<<
   targetPort: 8080
  selector:
    any-name: my-app
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: my-ingress
spec:
  rules:
  - http:
    paths:
    - backend:
       serviceName: my-service  # <<<
       servicePort: 80  # <<<
     path: /

如何檢查Ingress是否正在運作?

您可以使用該方法 kubectl port-forward,但您需要連接到 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(它可能位於不同的命名空間中)並執行命令 describe找出連接埠號碼:

kubectl describe pod nginx-ingress-controller-6fc5bcc 
--namespace kube-system 
 | grep Ports
Ports:         80/TCP, 443/TCP, 18080/TCP

最後,連接到 pod:

kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-system

現在,每次您向電腦上的連接埠 3000 發送請求時,該請求都會透過 Ingress 控制器轉送到 pod 的連接埠 80。 通過去 http://localhost:3000,您應該看到應用程式產生的頁面。

連接埠總結

讓我們再次記住哪些連接埠和標籤必須匹配:

  1. Service 定義中的選擇器必須與 pod 的標籤相符;
  2. targetPort 定義中的服務必須符合 containerPort pod 內的容器;
  3. port 定義中的服務可以是任何東西。 不同的服務可以使用相同的端口,因為它們具有不同的IP位址;
  4. servicePort 入口必須匹配 port 在服務的定義中;
  5. 服務名稱必須與欄位相符 serviceName 在入口處。

不幸的是,僅僅知道如何正確建構 YAML 配置是不夠的。

當出現問題時會發生什麼事?

Pod 可能無法啟動或崩潰。

診斷 Kubernetes 中應用程式問題的 3 個步驟

在開始調試部署之前,您需要充分了解 Kubernetes 的工作原理。

由於K8s中下載的每個應用程式都具有三個元件,因此應該按照一定的順序對它們進行調試,從最底層開始。

  1. 首先,您需要確保 Pod 正常工作,然後...
  2. 檢查服務是否向 Pod 提供流量,然後...
  3. 檢查 Ingress 配置是否正確。

視覺表現:

1)你應該從最底層開始找問題。 首先檢查 pod 是否有狀態 Ready и Running:

Kubernetes 故障排除視覺化指南

2) 如果 Pod 準備就緒 (Ready),您應該找出該服務是否在 Pod 之間分配流量:

Kubernetes 故障排除視覺化指南

3)最後需要分析服務與Ingress的連結:

Kubernetes 故障排除視覺化指南

1. Pod 的診斷

大多數情況下,問題與 Pod 有關。 確保 Pod 列為 Ready и Running。 您可以使用以下命令進行檢查:

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 被列為 Running и Ready然而,另外兩人卻並非如此。

如何理解出了什麼問題?

有四個有用的命令可用於診斷 pod:

  1. kubectl logs <имя pod'а> 允許您從 pod 中的容器中提取日誌;
  2. kubectl describe pod <имя pod'а> 允許您查看與 pod 關聯的事件清單;
  3. kubectl get pod <имя pod'а> 允許您取得儲​​存在 Kubernetes 中的 pod 的 YAML 設定;
  4. kubectl exec -ti <имя pod'а> bash 允許您在 pod 容器之一中啟動互動式命令 shell

你應該選擇哪一個?

事實是,不存在通用命令。 應結合使用這些方法。

典型的 Pod 問題

Pod 錯誤主要有兩種類型:啟動錯誤和執行階段錯誤。

啟動錯誤:

  • ImagePullBackoff
  • ImageInspectError
  • ErrImagePull
  • ErrImageNeverPull
  • RegistryUnavailable
  • InvalidImageName

運行時錯誤:

  • CrashLoopBackOff
  • RunContainerError
  • KillContainerError
  • VerifyNonRootError
  • RunInitContainerError
  • CreatePodSandboxError
  • ConfigPodSandboxError
  • KillPodSandboxError
  • SetupNetworkError
  • TeardownNetworkError

有些錯誤比其他錯誤更常見。 以下是一些最常見的錯誤以及解決方法。

影像拉回關閉

當 Kubernetes 無法取得其中一個 pod 容器的映像時,就會發生此錯誤。 以下是三個最常見的原因:

  1. 圖片名稱不正確 - 例如,您輸入錯誤,或圖片不存在;
  2. 為圖像指定了不存在的標籤;
  3. 該鏡像儲存在私人註冊表中,Kubernetes 無權存取它。

前兩個原因很容易消除 - 只需更正圖像名稱和標籤。 對於後者,您需要在 Secret 中輸入封閉註冊表的憑證,並在 pod 中新增指向它的連結。 在 Kubernetes 文件中 有一個例子 如何做到這一點。

崩潰循環回退

Kubenetes 拋出錯誤 CrashLoopBackOff,如果容器無法啟動。 這通常發生在以下情況:

  1. 應用程式中存在一個錯誤,導致其無法啟動;
  2. 容器 配置不正確;
  3. 活性測試失敗次數太多。

您必須嘗試從容器中取得日誌以找出其失敗的原因。 如果由於容器重新啟動太快導致日誌存取困難,可以使用以下命令:

kubectl logs <pod-name> --previous

它顯示容器先前版本的錯誤訊息。

運行容器錯誤

當容器無法啟動時會出現此錯誤。 它對應於應用程式啟動之前的時刻。 通常是由於設定不正確造成的,例如:

  • 嘗試掛載不存在的捲,例如 ConfigMap 或 Secrets;
  • 嘗試將唯讀卷安裝為讀寫。

該團隊非常適合分析此類錯誤 kubectl describe pod <pod-name>.

Pod 處於 Pending 狀態

一旦創建,Pod 就保持在狀態 Pending.

為什麼會這樣?

以下是可能的原因(我假設調度程序正常運作):

  1. 叢集沒有足夠的資源(例如處理能力和記憶體)來運行 Pod。
  2. 該物件安裝在適當的命名空間中 ResourceQuota 並且建立 pod 會導致命名空間超出配額。
  3. Pod 綁定為 Pending PersistentVolumeClaim.

在這種情況下,建議使用指令 kubectl describe 並檢查該部分 Events:

kubectl describe pod <pod name>

如果出現與以下相關的錯誤 ResourceQuotas,建議使用指令查看叢集日誌

kubectl get events --sort-by=.metadata.creationTimestamp

Pod 尚未就緒

如果 pod 列為 Running,但未處於狀態 Ready,意味著檢查其準備情況 (就緒探針) 失敗了。

發生這種情況時,Pod 不會連接到服務,並且沒有流量流向它。 就緒測試失敗是由應用程式中的問題引起的。 在這種情況下,要找到錯誤,您需要分析該部分 Events 在命令輸出中 kubectl describe.

2. 服務診斷

如果 pod 列為 Running и Ready,但應用程式仍然沒有響應,您應該檢查服務設定。

服務負責根據 Pod 的標籤將流量路由到 Pod。 因此,您需要做的第一件事是檢查有多少 Pod 使用該服務。 為此,您可以檢查服務中的端點:

kubectl describe service <service-name> | grep Endpoints

端點是一對形式的值 <IP-адрес:порт>,並且輸出中必須至少存在一對這樣的(即,至少有一個 Pod 與該服務一起工作)。

如果節 Endpoins 空,有兩種選擇:

  1. 沒有具有正確標籤的 Pod(提示:檢查命名空間是否選擇正確);
  2. 選擇器中的服務標籤有錯誤。

如果您看到端點列表但仍然無法存取應用程序,則可能的罪魁禍首是 targetPort 在服務描述中。

如何檢查服務的功能?

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

kubectl port-forward service/<service-name> 3000:80

在這裡:

  • <service-name> - 服務名稱;
  • 3000是你在電腦上打開的連接埠;
  • 80 - 服務端埠。

3. 入口診斷

如果您已經讀到這裡,那麼:

  • pod 列為 Running и Ready;
  • 此服務成功在 Pod 之間分配流量。

但是,您仍然無法存取該應用程式。

這意味著 Ingress 控制器很可能未正確配置。 由於Ingress控制器是叢集中的第三方元件,因此根據其類型有不同的偵錯方法。

但在使用特殊工具來設定 Ingress 之前,您可以做一些非常簡單的事情。 入口用途 serviceName и servicePort 連接到該服務。 您需要檢查它們是否配置正確。 您可以使用以下命令執行此操作:

kubectl describe ingress <ingress-name>

如果列 Backend 為空,很有可能配置錯誤。 如果後端已就位,但應用程式仍然無法訪問,則問題可能與以下內容有關:

  • 從公共網際網路進入輔助功能設定;
  • 來自公共互聯網的叢集可訪問性設定。

您可以透過直接連接到 Ingress Pod 來識別基礎架構的問題。 為此,首先找到 Ingress Controller 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

使用命令 describe設定連接埠:

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 控制器有很多種。 最受歡迎的是 Nginx、HAProxy、Traefik 等。 (有關現有解決方案的更多信息,請參閱 我們的評論 - 大約。 譯) 您應該參閱相關控制器文件中的故障排除指南。 因為 入口 Nginx 是最受歡迎的 Ingress 控制器,我們在文章中包含了一些技巧來解決與其相關的問題。

調試 Ingress Nginx 控制器

Ingress-nginx專案有官方的 kubectl 插件。 團隊 kubectl ingress-nginx 可以用於:

  • 日誌、後端、證書等分析;
  • 與 Ingress 的連接;
  • 研究當前配置。

以下三個命令將幫助您完成此操作:

  • kubectl ingress-nginx lint - 檢查 nginx.conf;
  • kubectl ingress-nginx backend — 探索後端(類似 kubectl describe ingress <ingress-name>);
  • kubectl ingress-nginx logs — 檢查日誌。

請注意,在某些情況下,您可能需要使用標誌為 Ingress 控制器指定正確的命名空間 --namespace <name>.

總結

如果您不知道從哪裡開始,對 Kubernetes 進行故障排除可能會很困難。 您應該始終自下而上解決問題:從 pod 開始,然後繼續到服務和 Ingress。 本文所述的調試技術可以應用於其他對象,例如:

  • 空閒作業和 CronJobs;
  • StatefulSet 和 DaemonSet。

我表達我的感激之情 蓋爾蓋利里斯科, 丹尼爾·韋貝爾 и 查爾斯·克里斯蒂拉吉 提出寶貴意見和補充。

譯者PS

另請閱讀我們的博客:

來源: www.habr.com

添加評論