K8S deployment故障可視化排查指南

K8S deployment故障可視化排查指南


這是一個示意圖,可幫助您調試Kubernetes中的deployemnt,

K8S deployment故障可視化排查指南


當您希望在Kubernetes中部署應用程序時,通常定義三個組件:

  • 一個deployment - 這是創建名為Pods的應用程序副本的秘訣
  • 一個service - 內部負載平衡器路由流量到pod
  • 一個ingress - 從外部訪問集群服務的網絡流向的描述
    以下是快速視覺回顧。

在Kubernetes中,您的應用程序通過兩層負載均衡器公開:內部和外部。

K8S deployment故障可視化排查指南

內部的負載均衡器稱為Service,而外部的負載均衡器稱為Ingress。

K8S deployment故障可視化排查指南

pod未直接部署。相反,deploymeny會在其上創建和watchPod。

K8S deployment故障可視化排查指南

假設您希望部署一個簡單的Hello World應用程序,則該應用程序的YAML應該類似於以下內容:

<code>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: /
/<code>

定義很長,很容易忽略組件之間的相互關係
例如:

  • 什麼時候應使用端口80,何時應使用端口8080?
  • 您是否應該為每個服務創建一個新端口,以免它們衝突?
  • 標籤名稱重要嗎?所有的都應該一樣嗎?

在進行調試之前,讓我們回顧一下這三個組件如何相互鏈接。
讓我們從Deployment和Service開始。

連接Deployment和Service

令人驚訝的消息是,Deployment和Service根本沒有連接。
而是,該服務直接指向Pod,並完全跳過部署。
因此,您應該注意的是Pod和Service之間的相互關係。
您應該記住三件事:

  • 服務選擇器應至少與Pod的一個標籤匹配
  • 服務targetPort應與containerPortPod中容器的匹配
  • 服務port可以是任何號碼。多個服務可以使用同一端口,因為它們分配了不同的IP地址。
    下圖總結了如何連接端口:

考慮Service暴露的以下Pod。

K8S deployment故障可視化排查指南

創建Pod時,應為Pod containerPort中的每個容器定義端口。

K8S deployment故障可視化排查指南

創建服務時,可以定義port和targetPort。但是您應該連接哪一個容器?

K8S deployment故障可視化排查指南

targetPort並且containerPort應該始終匹配

K8S deployment故障可視化排查指南

如果您的容器暴露了端口3000,則targetPort應當與該端口號匹配。

K8S deployment故障可視化排查指南

如果您查看YAML,則標籤和ports/ targetPort應該匹配:

<code>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
/<code>

Deployment 頭部的track: canary是什麼?
那也應該匹配嗎?
該標籤屬於Deployment,Service的選擇器未使用它來路由流量。
換句話說,您可以安全地刪除它或為其分配其他值。
那matchLabels選擇器呢?
它始終必須與Pod標籤匹配,並且由Deployment用來跟蹤Pod。
假設您進行了正確的更改,如何測試它?
您可以使用以下命令檢查Pod是否具有正確的標籤:

<code>kubectl get pods --show-labels
/<code>

或者,如果您具有屬於多個應用程序的Pod:

<code>kubectl get pods --selector any-name=my-app --show-labels
/<code>

any-name=my-app標籤在哪裡any-name: my-app。
還有問題嗎?
您也可以連接到Pod!
您可以使用kubectl中的port-forward命令連接到服務並測試連接。

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

如果:

  • service/ 是服務的名稱-在當前的YAML中是my-service
  • 3000是您希望在計算機上打開的端口
  • 80是服務在port現場暴露的端口
    如果可以連接,則說明設置正確。
    如果不行,則很可能是您放錯了標籤或端口不匹配。連接Service和ingress暴露您的應用的下一步是配置Ingress。

Ingress必須知道如何檢索服務,然後檢索Pod並將流量路由到它們。

Ingress按名稱和公開的端口檢索正確的服務。

在Ingress和Service中應該匹配兩件事:

  • 在Ingress中該servicePort應該匹配port的服務
  • 在Ingress中該serviceName應該匹配name的服務
    下圖總結了如何連接端口:

您已經知道該服務公開了一個端口。

K8S deployment故障可視化排查指南

Ingress有一個名為servicePort的字段

K8S deployment故障可視化排查指南

Service端口和ingress servicePort應始終匹配。

K8S deployment故障可視化排查指南

如果決定為服務分配端口80,則也應將servicePort更改為80。

K8S deployment故障可視化排查指南


在實踐中,您應該查看以下幾行:

<code>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: /
/<code>

您如何測試Ingress的功能?
您可以使用與以前相同的策略kubectl port-forward,但是應該連接到Ingress控制器,而不是連接到服務。
首先,使用以下命令檢索Ingress控制器的Pod名稱:

<code>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

/<code>

確定Ingress Pod(可能在不同的命名空間中)並描述它以檢索端口

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

最後,連接到Pod:

<code>kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-system
/<code>

此時,每次您訪問計算機上的端口3000時,請求都會轉發到Ingress控制器Pod上的端口80。
如果訪問本地3000端口

回顧端口

快速回顧一下哪些端口和標籤應該匹配:

  • 服務選擇器應與Pod的標籤匹配
  • 服務targetPort應與containerPortPod中容器的匹配
  • 服務端口可以是任何數字。多個服務可以使用同一端口,因為它們分配了不同的IP地址。
  • 在servicePort該入口的應該匹配port在服務
  • 服務名稱應與serviceNameIngress 中的字段匹配
  • 知道如何構造YAML定義只是故事的一部分。
    出問題了怎麼辦?
    Pod可能無法啟動,或者正在崩潰。

解決Kubernetes Deployment問題的3個步驟

在深入研究異常的Deployment之前,必須有一個明確定義的Kubernetes工作方式的思維模型。
由於每個部署中都有三個組件,因此您應該從底部開始依次調試所有組件。

  • 您應該確保Pods正在運行,然後
  • 專注於讓服務將流量路由到Pod,然後
  • 檢查是否正確配置了Ingress

您應該從底部開始對Deployment進行故障排除。首先,檢查Pod是否已就緒並正在運行。

K8S deployment故障可視化排查指南

如果Pod已就緒,則應調查服務是否可以將流量分配給Pod。

K8S deployment故障可視化排查指南

最後,您應該檢查服務與入口之間的連接。

K8S deployment故障可視化排查指南

Pod故障排除

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

<code>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
/<code>

在上述會話中,最後一個Pod為Running and Ready - 但是,前兩個Pod 既不是Running也不為Ready。
您如何調查出了什麼問題?
有四個有用的命令可以對Pod進行故障排除:

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

常見pod錯誤

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

  • ImagePullBackoff
  • ImageInspectError
  • ErrImagePull
  • ErrImageNeverPull
  • registry不可用
  • InvalidImageName
    運行時錯誤包括:
  • CrashLoopBackOff
  • RunContainerError
  • KillContainerError
  • VerifyNonRootError
  • RunInitContainerError
  • CreatePodSandboxError
  • ConfigPodSandboxError
  • KillPodSandboxError
  • SetupNetworkError
  • TeardownNetworkError
    有些錯誤比其他錯誤更常見。
    以下是最常見的錯誤以及如何修復它們的列表。

ImagePullBackOff

當Kubernetes無法檢索Pod容器之一的registry時,將出現此錯誤。


共有三個罪魁禍首:

  • image名稱無效-例如,您拼錯了名稱,或者image不存在
  • 您為image指定了不存在的標籤
  • 您嘗試檢索的image屬於一個私有registry,而Kubernetes沒有憑據可以訪問它
    前兩種情況可以通過更正image名稱和標記來解決。
    最後,您應該將憑證添加到secret中的私人resistry中,並在Pod中引用它。

CrashLoopBackOff

如果容器無法啟動,則Kubernetes將CrashLoopBackOff消息顯示為狀態。
通常,在以下情況下容器無法啟動:

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

/<pod-name>/<code>

將打印前一個容器的錯誤信息

RunContainerError

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

  • 掛載不存在的卷,例如ConfigMap或Secrets
  • 將只讀卷安裝為可讀寫

您應該使用kubectl describe pod <pod-name>收集和分析錯誤。/<pod-name>

Pods處於Pending狀態

當您創建Pod時,該Pod保持Pending狀態。
為什麼?
假設您的調度程序組件運行良好,原因如下:

  • 群集沒有足夠的資源(例如CPU和內存)來運行Pod
  • 當前的命名空間具有ResourceQuota對象,創建Pod將使命名空間超過配額
  • 該Pod綁定到一個待處理的 PersistentVolumeClaim
    檢查event部分最好的辦法是運行kubectl describe命令:kubectl describe pod
    對於因ResourceQuotas而導致的錯誤,可以使用以下方法檢查群集的日誌:kubectl get events --sort-by=.metadata.creationTimestampPods處於 not Ready狀態如果Pod正在運行但not Ready,則表明readiness探針失敗。
    當readiness探針失敗時,Pod未連接到服務,並且沒有流量轉發到該實例。
    準備就緒探針失敗是特定於應用程序的錯誤,因此您應通過kubectl describe檢查其中的event部分以識別錯誤。Service故障排除如果您的Pod正在運行並處於就緒狀態,但仍無法收到應用程序的響應,則應檢查服務的配置是否正確。
    服務旨在根據流量的標籤將流量路由到Pod。
    因此,您應該檢查的第一件事是服務定位了多少個Pod。
    您可以通過檢查Service中的endpoint來做到這一點:kubectl describe service <service-name> | grep Endpoints端點是一對,並且在服務以Pod為目標時,應該至少有一個。
    如果”Endpoints”部分為空,則有兩種解釋:/<service-name>
  • 您沒有運行帶有正確標籤的Pod(提示:您應檢查自己是否在正確的命名空間中)
    您selector在服務標籤上有錯字
  • 如果您看到端點列表,但仍然無法訪問您的應用程序,則targetPort可能是您服務中的罪魁禍首。

    您如何測試服務?
    無論服務類型如何,您都可以使用kubectl port-forward它來連接:kubectl port-forward service/<service-name> 3000:80即:/<service-name>
  • 是服務的名稱
  • 3000 是您希望在計算機上打開的端口
  • 80 是服務公開的端口

對Ingress進行故障排除

如果您已到達本節,則:

  • pod正在運行並準備就緒
  • 服務會將流量分配到Pod
    但是您仍然看不到應用程序的響應。
    這意味著最有可能Ingress配置錯誤。
    由於正在使用的Ingress控制器是集群中的第三方組件,因此有不同的調試技術,具體取決於Ingress控制器的類型。
    但是在深入研究Ingress專用工具之前,您可以檢查一些簡單的方法。
    入口使用serviceName和servicePort連接到服務。
    您應該檢查這些配置是否正確。
    您可以檢查是否已使用以下命令正確配置了Ingress:kubectl describe ingress <ingress-name>如果Backend列為空,則配置中一定有一個錯誤。

    如果您可以在Backend列中看到端點,但仍然無法訪問該應用程序,則可能是以下問題:/<ingress-name>
  • 您如何將Ingress暴露於公共互聯網
  • 您如何將群集暴露於公共互聯網
    您可以通過直接連接到Ingress Pod來將基礎結構問題與Ingress隔離開。
    首先,為您的Ingress控制器(可以位於其他名稱空間中)檢索Pod:
<code>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
/<code>

describe以檢索端口:

<code>kubectl describe pod nginx-ingress-controller-6fc5bcc --namespace kube-system \\
| grep Ports
/<code>

最後,連接到Pod:

<code>kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-system
/<code>

此時,每次您訪問計算機上的端口3000時,請求都會轉發到Pod上的端口80。
現在可以用嗎?

  • 如果可行,則問題出在基礎架構中。您應該調查流量如何路由到您的群集。
  • 如果不起作用,則問題出在Ingress控制器中。您應該調試Ingress。
    如果仍然無法使Ingress控制器正常工作,則應開始對其進行調試。
    有許多不同版本的Ingress控制器。
    熱門選項包括Nginx,HAProxy,Traefik等。
    您應該查閱Ingress控制器的文檔以查找故障排除指南。
    由於ingress nginx是最受歡迎的Ingress控制器,因此在下一部分中我們將介紹一些技巧。

調試Ingress Nginx

Ingress-nginx項目有一個kubectl plugin。
您可以kubectl ingress-nginx用來:

  • 檢查日誌,後端,證書等。
  • 連接到入口
  • 檢查當前配置
    您應該嘗試的三個命令是:
  • kubectl ingress-nginx lint,它會檢查 nginx.conf
  • kubectl ingress-nginx backend,以檢查後端(類似於kubectl describe ingress )
  • kubectl ingress-nginx logs,查看日誌請注意,您可能需要使用來為Ingress控制器指定正確的名稱空間—namespace 。

摘要

如果您不知道從哪裡開始,在Kubernetes中進行故障排除可能是一項艱鉅的任務。
您應該始終牢記從下至上解決問題:從Pod開始,然後通過Service and Ingress向上移動堆棧。
您在本文中瞭解到的相同調試技術可以應用於其他對象,例如:
失敗的Jobs和CronJobs,StatefulSets 和 DaemonSets


分享到:


相關文章: