作者:鄭增權
愛可生南區資料庫工程師,愛可生 DBA 團隊成員,負責資料庫相關技術支援。愛好:桌球、羽毛球、咖啡、電影
本文來源:原創投稿
*愛可生開源社群出品,原創內容未經授權不得隨意使用,轉載請聯絡小編並註明來源。
一、本文概述及主要術語
1.1概述
本文基於 Pod 、Service 和 Ingress 三大模組進行劃分,對於 Kubernetes 日常可能出現的故障問題,提供了較為具體的排查步驟,並附上相關解決方法或參考文獻。
1.2 主要術語
- Pod: Kubernetes 中建立和管理的、最小的可部署的計算單元。是一組(一個或多個) 容器; 這些容器共享儲存、網路、以及怎樣執行這些容器的宣告。
- Port-forward: 通過埠轉發對映本地埠到指定的應用埠。
- Service: 一個 Kubernetes 的 Service 是一種抽象,它定義了一組 Pods 的邏輯集合和一個用於訪問它們的策略 - 有時被稱為微服務。
- Ingress: 提供了叢集外部到內部 HTTP 和 HTTPS 服務的路由通訊,流量路由通過 Ingress 資源上定義的規則控制。
二、故障診斷流程
2.1 Pods 模組檢查
- 以下流程若成功則繼續往下進行,若失敗則根據提示進行跳轉。
2.1.1 檢查是否有pod處於PENDING狀態
- kubectl get pods: 如果有 pod 處於 PENDING 狀態則往下看,否則前往2.1.5 。
[root@10-186-65-37 ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-deploy-55b54d55b8-5msx8 0/1 Pending 0 5m
- kubectl describe pod <pod-name>: 若正確輸出指定的一個或多個資源的詳細資訊,則判斷是否叢集資源不足,若不足則進行擴充,否則前往 2.1.2 。
2.1.2 檢查是否觸發 ResourceQuota limit
- kubectl describe resourcequota -n <namespace>:
[root@10-186-65-37 ~]# kubectl describe quota compute-resources --namespace=myspace
Name: compute-resources
Namespace: myspace
Resource Used Hard
-------- ---- ----
limits.cpu 0 2
limits.memory 0 2Gi
pods 0 4
requests.cpu 0 1
requests.memory 0 1Gi
- 如有限制則進行相應資源釋放或擴充,參考:
https://kubernetes.io/zh/docs... - 否則前往 2.1.3
2.1.3檢查是否有 PVC 處於 PENDING 狀態
- 持久卷(PersistentVolume,PV)是叢集中的一塊儲存,可以由管理員事先供應,或者使用儲存類(Storage Class)來動態供應;持久卷申領(PersistentVolumeClaim, PVC)表達的是使用者對儲存的請求。
kubectl describe pvc <pvc-name>:
若 STATUS 為 Pending[root@10-186-65-37 k8s-file]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE local-device-pvc Pending local-device 72s
則參考如下連結進行解決:
https://kubernetes.io/zh/docs...
- 否則前往 2.1.4
2.1.4 檢查 pod 是否被分配至 node
- kubectl get pods -o wide:
若已被分配至 node
[root@10-186-65-37 ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp-deploy-55b54d55b8-5msx8 1/1 Running 0 14d 10.244.4.9 10-186-65-122 <none> <none>
myapp-deploy-55b54d55b8-7ldj4 1/1 Running 0 14d 10.244.2.10 10-186-65-126 <none> <none>
myapp-deploy-55b54d55b8-cwdwt 1/1 Running 0 14d 10.244.3.9 10-186-65-126 <none> <none>
myapp-deploy-55b54d55b8-gvmb9 1/1 Running 0 14d 10.244.4.10 10-186-65-122 <none> <none>
myapp-deploy-55b54d55b8-xbqb6 1/1 Running 0 14d 10.244.5.9 10-186-65-118 <none> <none>
則是 Scheduler 方面的問題,參考如下連結進行解決:
https://kubernetes.io/zh/docs...
- 否則為 Kubectl 的問題。
2.1.5 檢查是否有 pods 處於 RUNNING 狀態
- kubectl get pods -o wide:
如果 pods 處於 RUNNING 狀態則前往 2.1.10 ,否則前往 2.1.6 。
2.1.6 檢查 pod 日誌
- kubectl logs <pod-name>:
若能正確獲取日誌則根據日誌修復相關問題。
[root@10-186-65-37 ~]# kubectl logs myapp-deploy-55b54d55b8-5msx8
127.0.0.1 - - [30/Sep/2021:06:53:16 +0000] "GET / HTTP/1.1" 200 65 "-" "curl/7.29.0" "-"
127.0.0.1 - - [30/Sep/2021:07:49:44 +0000] "GET / HTTP/1.1" 200 65 "-" "curl/7.29.0" "-"
127.0.0.1 - - [30/Sep/2021:07:51:09 +0000] "GET / HTTP/1.1" 200 65 "-" "curl/7.29.0" "-"
127.0.0.1 - - [30/Sep/2021:07:57:00 +0000] "GET / HTTP/1.1" 200 65 "-" "curl/7.29.0" "-"
127.0.0.1 - - [30/Sep/2021:08:03:56 +0000] "GET / HTTP/1.1" 200 65 "-" "curl/7.29.0" "-"
- 若無法獲取日誌則判斷容器是否快速停止執行,若快速停止則執行:
kubectl logs <pod-name> --previous - 無法獲取日誌,且容器並非快速停止執行,則前往 2.1.7 。
2.1.7 Pod 狀態是否處於 ImagePullBackOff
- kubectl describe pod <pod-name>:
檢視 status 是否為 ImagePullBackOff ?不為 ImagePullBackOff 則前往 2.1.8 . - 檢視 image 名稱是否正確,錯誤則修正。
- 檢視 image tag 是否存在並經過驗證。
- 是否從 private registry 拉取映象?若是則確認配置資訊正確。
- 若並非從 private registry 拉取映象,問題可能出在 CRI(容器執行時介面) 或 kubectl 。
2.1.8 Pod 狀態是否處於 CrashLoopBackOff
- kubectl describe pod <pod-name>:
檢視 status 是否為 CrashLoopBackOff ?否則前往 2.1.9 。 - 若是則檢視日誌並修復應用程式崩潰。
- 確認是否遺漏了 Dockerfile 中的 CMD 指令?
Docker history <image-id> (後可加 --no-trunc 顯示完整輸出)
[root@10-186-65-37 ~]# docker history fb4cca6b4e4c
IMAGE CREATED CREATED BY SIZE COMMENT
fb4cca6b4e4c 22 months ago /bin/sh -c #(nop) COPY file:957630e64c05c549… 121MB
<missing> 2 years ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 2 years ago /bin/sh -c #(nop) ADD file:1d711f09b1bbc7c8d… 42.3MB
- Pod 狀態是否頻繁重啟且狀態處於 Running 和 CrashLoopBackOff 之間切換?若是則需修復 liveness probe(存活探測器)的問題,請參考如下連結:
https://kubernetes.io/zh/docs...
2.1.9 Pod 狀態是否處於 RunContainerError
- kubectl describe pod <pod-name>:
檢視 status 是否為 RunContainerError 。 - 若狀態為 RunContainerError 問題可能由於掛載卷 (volume) 導致,請參考如下連結:
https://kubernetes.io/zh/docs... - 否則請在 StackOverflow 等網站尋求幫助。
2.1.10 檢查是否有 pods 處於 READY 狀態
若處於 READY 狀態,則繼續往下執行進行對映設定
[root@10-186-65-37 ~]# kubectl get pods NAME READY STATUS RESTARTS AGE myapp-deploy-55b54d55b8-5msx8 1/1 Running 0 14d myapp-deploy-55b54d55b8-7ldj4 1/1 Running 0 14d
若無處於 READY 狀態的 pods 則前往 2.1.11 。
- kubectl port-forward <pod-name> 8080:<pod-port>
- 對映成功前往2.2
a)進行對映
[root@10-186-65-37 ~]# kubectl port-forward myapp-deploy-55b54d55b8-5msx8 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
b)驗證對映成功
[root@10-186-65-37 ~]# curl localhost:8080
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
- 失敗則需確認程式可被所有地址監聽,設定語句如下:
kubectl port-forward --address 0.0.0.0 <pod-name> 8080:<pod-port>
若無法被所有地址監聽則為未知狀態(Unknown state)。
2.1.11 檢查 Readiness(就緒探測器)
- kubectl describe pod <pod-name>
- 正常輸出則根據日誌和參考如下連結修復相應問題
https://kubernetes.io/zh/docs... - 失敗則為未知狀態(Unknown state)。
2.2 Service 模組檢查
2.2.1 Service 當前狀態檢查
- kubectl describe service <service-name>
成功輸出如下:
[root@10-186-65-37 ~]# kubectl describe service myapp
\Name: myapp
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"myapp","namespace":"default"},"spec":{"ports":[{"name":"http","po...
Selector: app=myapp,release=canary
Type: ClusterIP
IP: 10.96.109.76
Port: http 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.2.10:80,10.244.3.9:80,10.244.4.10:80 + 2 more...
Session Affinity: None
Events: <none>
- 是否能看到 Endpoints 列且有正常輸出?非正常輸出則前往 2.2.2 。
kubectl port-forward service/<service-name> 8080:<service-port>
成功輸出如下:[root@10-186-65-37 ~]# kubectl port-forward service/myapp 8080:80 Forwarding from 127.0.0.1:8080 -> 80 Forwarding from [::1]:8080 -> 80
- 成功則前往 2.3 ,失敗則前往 2.2.4 。
2.2.2 Selector 與 Pod label 比對
- 檢視 pod 的 label 資訊
kubectl describe pod <pod-name>
[root@10-186-65-37 ~]# kubectl describe pod myapp-deploy-55b54d55b8-5msx8 | grep -i label -A 2
Labels: app=myapp
pod-template-hash=55b54d55b8
release=canary
檢視 service 的 selector 資訊
kubectl describe service <service-name>[root@10-186-65-37 ~]# kubectl describe service myapp | grep -i selector Selector: app=myapp,release=canary
- 比對兩者是否正確匹配,錯誤則進行修正,正確則前往 2.2.3 。
2.2.3 檢查 Pod 是否已分配 IP
- 檢視 pod 的 ip 資訊
kubectl describe pod <pod-name> 已正確分配 ip ,則問題是由於 kubectl 導致。
[root@10-186-65-37 ~]# kubectl describe pod myapp-deploy-55b54d55b8-5msx8 | grep -i 'ip' IP: 10.244.4.9 IPs: IP: 10.244.4.9
- 未分配 ip ,則問題是由於 Controller manager 導致。
2.2.4 檢查 Service TargetPort 與 Pod ContainerPort
- 檢視 service 的 TargetPort 資訊:
kubectl describe service <service-name>
[root@10-186-65-37 ~]# kubectl describe service myapp | grep -i targetport
TargetPort: 80/TCP
檢視 pod 的 ContainerPort 資訊:
kubectl describe pod < pod-name >[root@10-186-65-37 ~]# kubectl describe pod myapp-deploy-55b54d55b8-5msx8 | grep -i port Port: 80/TCP Host Port: 0/TCP
- 上方兩者一致則問題是由於 kube-proxy 導致,不一致則進行資訊修正。
2.3 Ingress 模組檢查
2.3.1 Ingress 當前狀態檢查
kubectl describe ingress <ingress-name>
成功輸出如下:[root@10-186-65-37 ~]# kubectl describe ingress ingress-tomcat-tls Name: ingress-tomcat-tls Namespace: default Address: Default backend: default-http-backend:80 (<none>) TLS: tomcat-ingress-secret terminates tomcat.quan.com Rules: Host Path Backends ---- ---- -------- tomcat.quan.com tomcat:8080 (10.244.2.11:8080,10.244.4.11:8080,10.244.5.10:8080) Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"extensions/v1beta1","kind":"Ingress","metadata":{"annotations":{"kubernets.io/ingress.class":"nginx"},"name":"ingress-tomcat-tls","namespace":"default"},"spec":{"rules":[{"host":"tomcat.quan.com","http":{"paths":[{"backend":{"serviceName":"tomcat","servicePort":8080},"path":null}]}}],"tls":[{"hosts":["tomcat.quan.com"],"secretName":"tomcat-ingress-secret"}]}} kubernets.io/ingress.class: nginx Events: <none>
- 是否能看到 backends 列且有正常輸出?正常輸出前往 2.3.4 ,否則前往 2.3.2 。
2.3.2 檢查 ServiceName 和 ServicePort
- kubectl describe ingress <ingress-name>
- kubectl describe service <service-name>
[root@10-186-65-37 ~]# kubectl describe ingress ingress-tomcat-tls | grep -E 'serviceName|servicePort'
kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"extensions/v1beta1","kind":"Ingress","metadata":{"annotations":{"kubernets.io/ingress.class":"nginx"},"name":"ingress-tomcat-tls","namespace":"default"},"spec":{"rules":[{"host":"tomcat.quan.com","http":{"paths":[{"backend":{"serviceName":"tomcat","servicePort":8080},"path":null}]}}],"tls":[{"hosts":["tomcat.quan.com"],"secretName":"tomcat-ingress-secret"}]}}
- 檢查前兩者的 ServiceName 和 ServicePort 書寫是否正確,若正確則前往2.3.3,錯誤請修正。
2.3.3 Ingress controller 文件
- 問題是由於 Ingress controller 導致,請查閱文件尋找解決方法:
https://kubernetes.io/docs/co...
2.3.4 檢查 port-forward ingress
1.kubectl port-forward <ingress-pod-name> 8080:<ingress-port>
測試是否能正常訪問:curl localhost:8080
可正常訪問前往 2.3.5 ,否則前往 2.3.3 。
2.3.5 檢查能否在外網通過 Ingress 進行訪問
- 可從外網成功訪問,故障排查結束。
- 若無法從外網訪問,則問題是由於基礎設施(infrastructure)或叢集暴露(exposed)方式導致,請排查。