這是一個示意圖,可幫助您除錯Kubernetes中的deployemnt,
當您希望在Kubernetes中部署應用程式時,通常定義三個元件:
一個deployment - 這是建立名為Pods的應用程式副本的祕訣一個service - 內部負載平衡器路由流量到pod一個ingress - 從外部訪問叢集服務的網路流向的描述以下是快速視覺回顧。在Kubernetes中,您的應用程式通過兩層負載均衡器公開:內部和外部。
內部的負載均衡器稱為Service,而外部的負載均衡器稱為Ingress。
pod未直接部署。相反,deploymeny會在其上建立和watchPod。
假設您希望部署一個簡單的Hello World應用程式,則該應用程式的YAML應該類似於以下內容:
apiVersion: apps/v1kind: Deploymentmetadata: name: my-deployment labels: track: canaryspec: 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: v1kind: Servicemetadata: name: my-servicespec: ports: - port: 80 targetPort: 8080 selector: name: app---apiVersion: networking.k8s.io/v1beta1kind: Ingressmetadata: name: my-ingressspec: rules: - http: paths: - backend: serviceName: app servicePort: 80 path: /定義很長,很容易忽略元件之間的相互關係例如:
什麼時候應使用埠80,何時應使用埠8080?您是否應該為每個服務建立一個新埠,以免它們衝突?標籤名稱重要嗎?所有的都應該一樣嗎?在進行除錯之前,讓我們回顧一下這三個元件如何相互連結。讓我們從Deployment和Service開始。
連線Deployment和Service令人驚訝的訊息是,Deployment和Service根本沒有連線。而是,該服務直接指向Pod,並完全跳過部署。因此,您應該注意的是Pod和Service之間的相互關係。您應該記住三件事:
服務選擇器應至少與Pod的一個標籤匹配服務targetPort應與containerPortPod中容器的匹配服務port可以是任何號碼。多個服務可以使用同一埠,因為它們分配了不同的IP地址。下圖總結了如何連線埠:考慮Service暴露的以下Pod。
建立Pod時,應為Pod containerPort中的每個容器定義埠。
建立服務時,可以定義port和targetPort。但是您應該連線哪一個容器?
targetPort並且containerPort應該始終匹配
如果您的容器暴露了埠3000,則targetPort應當與該埠號匹配。
如果您檢視YAML,則標籤和ports/ targetPort應該匹配:
apiVersion: apps/v1kind: Deploymentmetadata: name: my-deployment labels: track: canaryspec: 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: v1kind: Servicemetadata: name: my-servicespec: ports: - port: 80 targetPort: 8080 selector: any-name: my-appDeployment 頭部的track: canary是什麼?那也應該匹配嗎?該標籤屬於Deployment,Service的選擇器未使用它來路由流量。換句話說,您可以安全地刪除它或為其分配其他值。那matchLabels選擇器呢?它始終必須與Pod標籤匹配,並且由Deployment用來跟蹤Pod。假設您進行了正確的更改,如何測試它?您可以使用以下命令檢查Pod是否具有正確的標籤:
kubectl get pods --show-labels或者,如果您具有屬於多個應用程式的Pod:
kubectl get pods --selector any-name=my-app --show-labelsany-name=my-app標籤在哪裡any-name: my-app。還有問題嗎?您也可以連線到Pod!您可以使用kubectl中的port-forward命令連線到服務並測試連線。
kubectl port-forward service/<service name> 3000:80如果:
service/ 是服務的名稱-在當前的YAML中是my-service3000是您希望在計算機上開啟的埠80是服務在port現場暴露的埠如果可以連線,則說明設定正確。如果不行,則很可能是您放錯了標籤或埠不匹配。連線Service和ingress暴露您的應用的下一步是配置Ingress。Ingress必須知道如何檢索服務,然後檢索Pod並將流量路由到它們。
Ingress按名稱和公開的埠檢索正確的服務。
在Ingress和Service中應該匹配兩件事:
在Ingress中該servicePort應該匹配port的服務在Ingress中該serviceName應該匹配name的服務下圖總結了如何連線埠:您已經知道該服務公開了一個埠。
Ingress有一個名為servicePort的欄位
Service埠和ingress servicePort應始終匹配。
如果決定為服務分配埠80,則也應將servicePort更改為80。
在實踐中,您應該檢視以下幾行:
apiVersion: v1kind: Servicemetadata: name: my-servicespec: ports: - port: 80 targetPort: 8080 selector: any-name: my-app---apiVersion: networking.k8s.io/v1beta1kind: Ingressmetadata: name: my-ingressspec: rules: - http: paths: - backend: serviceName: my-service servicePort: 80 path: /您如何測試Ingress的功能?您可以使用與以前相同的策略kubectl port-forward,但是應該連線到Ingress控制器,而不是連線到服務。首先,使用以下命令檢索Ingress控制器的Pod名稱:
kubectl get pods --all-namespacesNAMESPACE NAME READY STATUSkube-system coredns-5644d7b6d9-jn7cq 1/1 Runningkube-system etcd-minikube 1/1 Runningkube-system kube-apiserver-minikube 1/1 Runningkube-system kube-controller-manager-minikube 1/1 Runningkube-system kube-proxy-zvf2h 1/1 Runningkube-system kube-scheduler-minikube 1/1 Runningkube-system nginx-ingress-controller-6fc5bcc 1/1 Running確定Ingress Pod(可能在不同的名稱空間中)並描述它以檢索埠
kubectl describe pod nginx-ingress-controller-6fc5bcc \\ --namespace kube-system \\ | grep PortsPorts: 80/TCP, 443/TCP, 18080/TCP最後,連線到Pod:
kubectl port-forward nginx-ingress-controller-6fc5bcc 3000:80 --namespace kube-system此時,每次您訪問計算機上的埠3000時,請求都會轉發到Ingress控制器Pod上的埠80。如果訪問本地3000埠
回顧埠快速回顧一下哪些埠和標籤應該匹配:
服務選擇器應與Pod的標籤匹配服務targetPort應與containerPortPod中容器的匹配服務埠可以是任何數字。多個服務可以使用同一埠,因為它們分配了不同的IP地址。在servicePort該入口的應該匹配port在服務服務名稱應與serviceNameIngress 中的欄位匹配知道如何構造YAML定義只是故事的一部分。出問題了怎麼辦?Pod可能無法啟動,或者正在崩潰。解決Kubernetes Deployment問題的3個步驟在深入研究異常的Deployment之前,必須有一個明確定義的Kubernetes工作方式的思維模型。由於每個部署中都有三個元件,因此您應該從底部開始依次除錯所有元件。
您應該確保Pods正在執行,然後專注於讓服務將流量路由到Pod,然後檢查是否正確配置了Ingress您應該從底部開始對Deployment進行故障排除。首先,檢查Pod是否已就緒並正在執行。
如果Pod已就緒,則應調查服務是否可以將流量分配給Pod。
最後,您應該檢查服務與入口之間的連線。
Pod故障排除在大多數情況下,問題出在Pod本身。您應該確保Pod正在執行並準備就緒。您如何檢查?
kubectl get podsNAME READY STATUS RESTARTS AGEapp1 0/1 ImagePullBackOff 0 47happ2 0/1 Error 0 47happ3-76f9fcd46b-xbv4k 1/1 Running 1 47h在上述會話中,最後一個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可能會出現啟動和執行時錯誤。啟動錯誤包括:
ImagePullBackoffImageInspectErrorErrImagePullErrImageNeverPullregistry不可用InvalidImageName執行時錯誤包括:CrashLoopBackOffRunContainerErrorKillContainerErrorVerifyNonRootErrorRunInitContainerErrorCreatePodSandboxErrorConfigPodSandboxErrorKillPodSandboxErrorSetupNetworkErrorTeardownNetworkError有些錯誤比其他錯誤更常見。以下是最常見的錯誤以及如何修復它們的列表。ImagePullBackOff當Kubernetes無法檢索Pod容器之一的registry時,將出現此錯誤。共有三個罪魁禍首:
image名稱無效-例如,您拼錯了名稱,或者image不存在您為image指定了不存在的標籤您嘗試檢索的image屬於一個私有registry,而Kubernetes沒有憑據可以訪問它前兩種情況可以通過更正image名稱和標記來解決。最後,您應該將憑證新增到secret中的私人resistry中,並在Pod中引用它。CrashLoopBackOff如果容器無法啟動,則Kubernetes將CrashLoopBackOff訊息顯示為狀態。通常,在以下情況下容器無法啟動:
應用程式中存在錯誤,導致無法啟動您未正確配置Liveness探針失敗太多次您應該嘗試從該容器中檢索日誌,以調查其失敗的原因。如果由於容器重新啟動太快而看不到日誌,則可以使用以下命令:kubectl logs <pod-name> --previous將列印前一個容器的錯誤資訊
RunContainerError當容器無法啟動時出現錯誤。甚至在容器內的應用程式啟動之前。該問題通常是由於配置錯誤,例如:
掛載不存在的卷,例如ConfigMap或Secrets將只讀卷安裝為可讀寫您應該使用kubectl describe pod <pod-name>收集和分析錯誤。
Pods處於Pending狀態當您建立Pod時,該Pod保持Pending狀態。為什麼?假設您的排程程式元件執行良好,原因如下:
群集沒有足夠的資源(例如CPU和記憶體)來執行Pod當前的名稱空間具有ResourceQuota物件,建立Pod將使名稱空間超過配額該Pod繫結到一個待處理的 PersistentVolumeClaim檢查event部分最好的辦法是執行kubectl describe命令:kubectl describe pod <pod name>對於因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”部分為空,則有兩種解釋:您沒有執行帶有正確標籤的Pod(提示:您應檢查自己是否在正確的名稱空間中)您selector在服務標籤上有錯字如果您看到端點列表,但仍然無法訪問您的應用程式,則targetPort可能是您服務中的罪魁禍首。您如何測試服務?無論服務型別如何,您都可以使用kubectl port-forward它來連線:kubectl port-forward service/<service-name> 3000:80即: 是服務的名稱3000 是您希望在計算機上開啟的埠80 是服務公開的埠對Ingress進行故障排除如果您已到達本節,則:
pod正在執行並準備就緒服務會將流量分配到Pod但是您仍然看不到應用程式的響應。這意味著最有可能Ingress配置錯誤。由於正在使用的Ingress控制器是叢集中的第三方元件,因此有不同的除錯技術,具體取決於Ingress控制器的型別。但是在深入研究Ingress專用工具之前,您可以檢查一些簡單的方法。入口使用serviceName和servicePort連線到服務。您應該檢查這些配置是否正確。您可以檢查是否已使用以下命令正確配置了Ingress:kubectl describe ingress <ingress-name>如果Backend列為空,則配置中一定有一個錯誤。如果您可以在Backend列中看到端點,但仍然無法訪問該應用程式,則可能是以下問題:您如何將Ingress暴露於公共網際網路您如何將群集暴露於公共網際網路您可以通過直接連線到Ingress Pod來將基礎結構問題與Ingress隔離開。首先,為您的Ingress控制器(可以位於其他名稱空間中)檢索Pod:kubectl get pods --all-namespacesNAMESPACE NAME READY STATUSkube-system coredns-5644d7b6d9-jn7cq 1/1 Runningkube-system etcd-minikube 1/1 Runningkube-system kube-apiserver-minikube 1/1 Runningkube-system kube-controller-manager-minikube 1/1 Runningkube-system kube-proxy-zvf2h 1/1 Runningkube-system kube-scheduler-minikube 1/1 Runningkube-system nginx-ingress-controller-6fc5bcc 1/1 Runningdescribe以檢索埠:
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 NginxIngress-nginx專案有一個kubectl plugin。您可以kubectl ingress-nginx用來:
檢查日誌,後端,證書等。連線到入口檢查當前配置您應該嘗試的三個命令是:kubectl ingress-nginx lint,它會檢查 nginx.confkubectl ingress-nginx backend,以檢查後端(類似於kubectl describe ingress )kubectl ingress-nginx logs,檢視日誌請注意,您可能需要使用來為Ingress控制器指定正確的名稱空間—namespace 。摘要如果您不知道從哪裡開始,在Kubernetes中進行故障排除可能是一項艱鉅的任務。您應該始終牢記從下至上解決問題:從Pod開始,然後通過Service and Ingress向上移動堆疊。您在本文中了解到的相同除錯技術可以應用於其他物件,例如:失敗的Jobs和CronJobs,StatefulSets 和 DaemonSets