今天會分享幾個我在做軟體開發 或 當擔任 DevOps 時,比較常遇到或被問的問題與排錯的思路,若剛好有遇到相同情況,希望能替讀者節省一些 Debug 的時間。
Pending
,一直無法變 Running
Pod Pending
代表在等待 Control plane 的 scheduler
組件將 Pod 分配到適合的節點上,什麼叫適合?
滿足以下條件
resources.request
以上三個問題,通常能使用 kubectl describe pod
來查看
kubectl describe pod demo-deployment-7cfb7c974d-rcg5s
節錄返回結果中 Conditions 與 Events 區塊
Conditions:
Type Status
PodScheduled False
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 81s (x4 over 16m) default-scheduler 0/2 nodes are available: 1 Insufficient cpu, 1 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: }. preemption: 0/2 nodes are available: 1 No preemption victims found for incoming pod, 1 Preemption is not helpful for scheduling..
能看到 Conditions
中 PodScheduled 狀態為 False,代表 Pod 尚未被分配到節點,而 Events
中能看到原因是沒有節點能足夠 cpu (此 pod) 0/2 nodes are available: 1 Insufficient cpu
能從 Events
的 Message,判斷發生的原因,來調整 Pod 或找管理者協助。
已筆者自身的經驗,以下是我遇到該問題的次數(高到低)與處理方式
CPU/Memory 資源不足
Conditions:
Type Status
PodScheduled False
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 81s (x4 over 16m) default-scheduler 0/2 nodes are available: 1 Insufficient cpu, 1 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: }. preemption: 0/2 nodes are available: 1 No preemption victims found for incoming pod, 1 Preemption is not helpful for scheduling..
以下三種方式能擇一
無法滿足 Pod NodeSelector
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 14s default-scheduler 0/2 nodes are available: 1 node(s) didn't match Pod's node affinity/selector, 1 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: }. preemption: 0/2 nodes are available: 2 Preemption is not helpful for scheduling..
透過 kubectl get node --show-labels
看是否有 Node 符合該 Pod 的 nodeSelector,看是 Node label 漏打還是 nodeSelector 寫錯。
該 Pod 無法滿足 Node 的 taint
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 10s default-scheduler 0/2 nodes are available: 1 node(s) had untolerated taint {key1: my-taint}, 1 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: }. preemption: 0/2 nodes are available: 2 Preemption is not helpful for scheduling..
這情況通常會跟 Kubernetes 管理者一起檢查,因為配置 taint 的 Node 都有特殊用途,比如具有 GPU 或 專門用於運行基礎設施。
若經過管理者確認 Pod 應該要被運行在有 taint 的節點,則添加 tolerations 屬性於 Pod 上,可參閱 (Taints and Tolerations)
若非以上問題,且 Events
也沒錯誤訊息,能在檢查負責調度節點的組件 kube-scheduler
是否運作正常
kubectl get pods -n kube-system | grep kube-scheduler
kubectl logs -n kube-system <kube-scheduler-pod-name>
通常連不到服務的狀況,通常會從兩個面向開始檢查
STATUS
是否為 RUNNINGREADY
是否為 true 或 M/M
M 代表個 Pod 的 container 數量,比如該 Pod 只有一個 Container 則是 1/1
透過 `kubectl get pod 來檢查
NAME READY STATUS RESTARTS AGE
app-1 0/1 ImagePullBackOff 0 72m
app-2 0/1 Error 0 72m
app-3 0/1 Running 0 72m
app-3 1/1 Running 0 72m
STATUS
非 Running 時,能嘗試以下方式
STATUS
去 Google 或 kubectl describe
檢查錯誤原因kubectl logs
檢查運行日誌kubectl get pod ${pod-name} -o yaml
匯出 pod yaml 檢查內容READY
非 ture 與 M/M 時
通常是 readiness 探針檢測的位置不存在,或readiness 探針檢測的返回值返回失敗。
能透過 kubectl describe
從 Events
區塊看到錯誤訊息,若不確定返回值,能進入到容器內調用看看
# 進入容器
kubectl exec -ti ${pod-name} -- bash
# 調用你配置的 Http readiness 端點
$ curl localhost:${port-number}/${readiness target URL path}
若以上檢查都完成,確認 Pod 的 STATUS
為 Running
且 READY
為 true
,我們開始調查流量傳遞是否正確。
回想我們先前介紹的 Ingress, service, pod,分別處理流量轉發的一部分工作,流量傳遞由外到內的大致順序如下
實務經驗上來看,最常見的是 Pod 或 Container 層的問題,所以我們從內到外開始檢查。
透過 kubectl exec
進入 container 中,並調用應用程序,看是否有回應
kubectl exec -ti ${pod-name} -- bash
$ curl localhost:${port-number}
若調用不到,代表該 container 運行的應用程序,不存在你想調用的 Pod,應檢查 container image 版本是否有誤,或包入 container 的應用程序版本是否正確。
檢查透過 Pod IP 進行 Pod to Pod 的調用,看是否服務能正常回應
查詢該 Pod IP
kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
demo-deployment-767f4b86d9-dxc9v 1/1 Running 0 2d19h 10.244.1.49 my-cluster-worker <none> <none>
依此為例 Pod IP 為 10.244.1.49
找一個 Debug Container,從下方選一個方式
kubectl debug
(推薦, 但 kubernetes 版本需 > 1.18)kubectl run -n default debug-container --rm -i --tty --image docker.io/nicolaka/netshoot -- /bin/bash
Debug Container 指有適當除錯工具的 container,方便進行調用測試,而 docker.io/nicolaka/netshoot 是個不錯的選擇。
curl
)的既有 Pod,從該 Pod 進行調用kubectl exec -it ${pod-name} -- /bin/bash
$ ping 10.244.1.49
$ curl 10.244.1.49:{port-number}
若調用不到,很可能是 Pod yaml 中配置的 spec.ports
有問題檢查 Endpoint 是否有映射到 Pod IP
kubectl get endpoints ${endpoints}
NAME ENDPOINTS AGE
demo-deployment 10.244.1.13:8080,10.244.1.48:8080,10.244.1.49:8080 2d19h
能看到 ENDPOINTS 包含 Pod IP 10.244.1.49
,代表 Endpoints 的服務發現機制正常。
若 ENDPOINTS 沒有你的 Pod IP,請檢查 Service 的 selector
是否能對應到 Pod
找一個 Debug Container,參考 檢查 Pod 流量映射規則中第二步驟。
在 Container 中調用該 Service DNS name
Service DNS name 規則為: ${service-name}.${namespace}.svc.cluster.local,依此為例為 demo-deployment.default.svc.cluster.local
$ nslookup demo-deployment.default.svc.cluster.local
$ ping demo-deployment.default.svc.cluster.local
$ curl demo-deployment.default.svc.cluster.local
若調用不到,請確認 service yaml 中的 ports
是否有誤
$ curl hello.ingress.com
若調用不到,檢查 ingress yaml 中 spec.rules
是否正確
透過上述的排查順序,通常能找到問題發生的原因,筆者的經驗上問題比較長出在 Container / Pod 的部分居多,大多時候是應用程序問題, expose 錯 ports,偶爾會有 service selector, ingress rule 寫錯。
更詳細的排查方式,能拜讀這兩篇神作
算是上一個情境的延伸題,通常不同團隊會有自己的 namespace,當服務互相需要調用時,會透過 Service DNS names 調用。
假設你已經透過 Debug container 在同個 namespace 下,透過 Service DNS names 調用到你的服務,那能檢查一下 network policy,network policy 能在 namespace 維度管理流量的進出,可能是對方的 namespace 的 network policy 阻擋流量發送,也可能是你 namespace 的 network policy 阻擋對方流量進入。
# 查 networkpolicies 配置
kubectl get networkpolicies.networking.k8s.io
檢查 networkpolicies 中的 spec
,相關規則參考 官方文檔
kubectl logs
檢查運行日誌kubectl exec
進入 Pod 內部檢查失敗原因
command
屬性搭配 sleep
指令來爭取檢查 container 內部的時間,範例如下apiVersion: v1
kind: Pod
metadata:
name: you-pod-name
labels:
app: you-pod-name
spec:
containers:
- name: app
image: you-image-name
ports:
- containerPort: 80
command: ["/bin/sh", "-ec", "sleep 1000"]
今天快速的分享幾個很常見的問題與排錯思路,希望對開發與維護有幫助
另外推薦花一點時間讀這兩篇大佬分享排錯思路的文章,排查問題時,幫助我節省很多時間。