K8s常見問題:Service 不能訪問排查流程
在學習Kubernetes過程中,經常會遇到Service無法訪問,這篇文章總結了可能導致的情況,希望能幫助你找到問題所在。
為了完成本次演練,先運行部署一個應用:
[root@k8s-master ~]# kubectl create deployment web --image=nginx --replicas=3
[root@k8s-master ~]# kubectl expose deployment web --port=80 --type=NodePort確保Pod運行:
[root@k8s-master ~]# kubectl get pods,svc
NAME READY STATUS RESTARTS AGE
pod/web-96d5df5c8-6rtxj 1/1 Running 0 110s
pod/web-96d5df5c8-dfbkv 1/1 Running 0 110s
pod/web-96d5df5c8-jghbs 1/1 Running 0 110s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3d5h
service/web NodePort 10.104.0.64 <none> 80:32035/TCP 22s問題1:無法通過 Service 名稱訪問
如果你是訪問的Service名稱,需要確保CoreDNS服務已經部署:
[root@k8s-master ~]# kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-7f89b7bc75-745s4 1/1 Running 0 3d5h
coredns-7f89b7bc75-fgdfm 1/1 Running 0 3d5h確認CoreDNS已部署,如果狀態(tài)不是Running,請檢查容器日志進一步查找問題。
接下來創(chuàng)建一個臨時Pod測試下DNS解析是否正常:
root@k8s-master ~]# kubectl run -it --rm --image=busybox:1.28.4 -- sh
If you don't see a command prompt, try pressing enter.
/ # nslookup web
Server: 10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name: web
Address 1: 10.104.0.64 web.default.svc.cluster.local如果解析失敗,可以嘗試限定命名空間:
/ # nslookup web.default
Server: 10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name: web.default
Address 1: 10.104.0.64 web.default.svc.cluster.local如果解析成功,需要調整應用使用跨命名空間的名稱訪問Service。
如果仍然解析失敗,嘗試使用完全限定的名稱:
/ # nslookup web.default.svc.cluster.local
Server: 10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name: web.default.svc.cluster.local
Address 1: 10.104.0.64 web.default.svc.cluster.local說明:其中“default”表示正在操作的命名空間,“svc”表示是一個Service,“cluster.local”是集群域。
再集群中的Node嘗試指定DNS IP(你的可能不同,可以通過kubectl get svc -n kube-system查看)解析下:
[root@k8s-node1 ~]# nslookup web.default.svc.cluster.local 10.96.0.10
Server: 10.96.0.10
Address: 10.96.0.10#53
Name: web.default.svc.cluster.local
Address: 10.104.0.64如果你能使用完全限定的名稱查找,但不能使用相對名稱,則需要檢查 /etc/resolv.conf 文件是否正確:
/ # cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5說明:
nameserver:行必須指定CoreDNS Service,它通過在kubelet設置 --cluster-dns 參加自動配置。
search :行必須包含一個適當的后綴,以便查找 Service 名稱。在本例中,它在本地 Namespace(default.svc.cluster.local)、所有 Namespace 中的 Service(svc.cluster.local)以及集群(cluster.local)中查找服務。
options :行必須設置足夠高的 ndots,以便 DNS 客戶端庫優(yōu)先搜索路徑。在默認情況下,Kubernetes 將這個值設置為 5。
問題2:無法通過 Service IP訪問
假設可以通過Service名稱訪問(CoreDNS正常工作),那么接下來要測試的 Service 是否工作正常。從集群中的一個節(jié)點,訪問 Service 的 IP:
[root@k8s-master ~]# curl -I 10.104.0.64:80
HTTP/1.1 200 OK如果 Service 是正常的,你應該看到正確的狀態(tài)碼。如果沒有,有很多可能出錯的地方,請繼續(xù)。
思路1:Service 端口配置是否正確?
檢查 Service 配置和使用的端口是否正確:
[root@k8s-master ~]# kubectl get svc web -o yaml
...
spec:
clusterIP: 10.104.0.64
clusterIPs:
- 10.104.0.64
externalTrafficPolicy: Cluster
ports:
- nodePort: 32035
port: 80
protocol: TCP
targetPort: 80
selector:
app: web
...spec.ports[]:訪問ClusterIP帶的端口
targetPort :目標端口,是容器中服務提供的端口
spec.nodePort :集群外部訪問端口,http://NodeIP:32035
思路2:Service 是否正確關聯(lián)到Pod?
檢查 Service 關聯(lián)的 Pod 是否正確:
[root@k8s-master ~]# kubectl get pods -l app=web
NAME READY STATUS RESTARTS AGE
web-96d5df5c8-6rtxj 1/1 Running 0 38m
web-96d5df5c8-dfbkv 1/1 Running 0 38m
web-96d5df5c8-jghbs 1/1 Running 0 38m-l app=hostnames 參數是一個標簽選擇器。
在 Kubernetes 系統(tǒng)中有一個控制循環(huán),它評估每個 Service 的選擇器,并將結果保存到 Endpoints 對象中。
[root@k8s-master ~]# kubectl get endpoints web
NAME ENDPOINTS AGE
web 10.244.169.135:80,10.244.169.136:80,10.244.36.73:80 38m結果所示, endpoints 控制器已經為 Service 找到了 Pods。但并不說明關聯(lián)的Pod就是正確的,還需要進一步確認Service 的 spec.selector 字段是否與Deployment中的 metadata.labels 字段值一致。
[root@k8s-master ~]# kubectl get svc web -o yaml
...
selector:
app: web[root@k8s-master ~]# kubectl get deployment web -o yaml
...
selector:
matchLabels:
app: web思路3:Pod 是否正常工作?
檢查Pod是否正常工作,繞過Service,直接訪問Pod IP:
[root@k8s-master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-96d5df5c8-6rtxj 1/1 Running 0 50m 10.244.169.135 k8s-node2 <none> <none>
web-96d5df5c8-dfbkv 1/1 Running 0 50m 10.244.36.73 k8s-node1 <none> <none>
web-96d5df5c8-jghbs 1/1 Running 0 50m 10.244.169.136 k8s-node2 <none>[root@k8s-master ~]# curl -I 10.244.169.135:80
HTTP/1.1 200 OK注: 使用的是
Pod端口(80),而不是Service端口(80
如果不能正常響應,說明容器中服務有問題, 這個時候可以用kubectl logs查看日志或者使用 kubectl exec 直接進入 Pod檢查服務。
除了本身服務問題外,還有可能是CNI網絡組件部署問題,現(xiàn)象是:curl訪問10次,可能只有兩三次能訪問,能訪問時候正好Pod是在當前節(jié)點,這并沒有走跨主機網絡。
如果是這種現(xiàn)象,檢查網絡組件運行狀態(tài)和容器日志:
[root@k8s-master ~]# kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
calico-kube-controllers-97769f7c7-2cvnw 1/1 Running 0 3d6h
calico-node-c7jjd 1/1 Running 0 3d6h
calico-node-cc9jt 1/1 Running 0 3d6h
calico-node-xqhwh 1/1 Running 0 3d6h思路4:kube-proxy 組件正常工作嗎?
如果到了這里,你的 Service 正在運行,也有 Endpoints, Pod 也正在服務。
接下來就該檢查負責 Service 的組件kube-proxy是否正常工作。
確認 kube-proxy 運行狀態(tài):
[root@k8s-node1 ~]# ps -ef |grep kube-proxy
root 5842 2246 0 04:56 pts/1 00:00:00 grep --color=auto kube-proxy
root 46540 46510 0 Mar12 ? 00:00:52 /usr/local/bin/kube-proxy --config=/var/lib/kube-proxy/config.conf --hostname-override=k8s-node1如果有進程存在,下一步確認它有沒有工作中有錯誤,比如連接主節(jié)點失敗。
要做到這一點,必須查看日志。查看日志方式取決于K8s部署方式,如果是kubeadm部署:
kubectl logs kube-proxy-mplxk -n kube-system如果是二進制方式部署:
journalctl -u kube-proxy思路5:kube-proxy 是否在寫 iptables 規(guī)則?
kube-proxy 的主要負載 Services 的 負載均衡 規(guī)則生成,默認情況下使用iptables實現(xiàn),檢查一下這些規(guī)則是否已經被寫好了。
[root@k8s-node1 ~]# iptables-save |grep web
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/web" -m tcp --dport 32035 -j KUBE-MARK-MASQ
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/web" -m tcp --dport 32035 -j KUBE-SVC-LOLE4ISW44XBNF3G
-A KUBE-SEP-AHKVJ4M3GZYQHEVU -s 10.244.36.73/32 -m comment --comment "default/web" -j KUBE-MARK-MASQ
-A KUBE-SEP-AHKVJ4M3GZYQHEVU -p tcp -m comment --comment "default/web" -m tcp -j DNAT --to-destination 10.244.36.73:80
-A KUBE-SEP-OUZ3ZV3ZECH37O4J -s 10.244.169.136/32 -m comment --comment "default/web" -j KUBE-MARK-MASQ
-A KUBE-SEP-OUZ3ZV3ZECH37O4J -p tcp -m comment --comment "default/web" -m tcp -j DNAT --to-destination 10.244.169.136:80
-A KUBE-SEP-PO5YJF2LZTBQLFX5 -s 10.244.169.135/32 -m comment --comment "default/web" -j KUBE-MARK-MASQ
-A KUBE-SEP-PO5YJF2LZTBQLFX5 -p tcp -m comment --comment "default/web" -m tcp -j DNAT --to-destination 10.244.169.135:80
-A KUBE-SERVICES ! -s 10.244.0.0/16 -d 10.104.0.64/32 -p tcp -m comment --comment "default/web cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
-A KUBE-SERVICES -d 10.104.0.64/32 -p tcp -m comment --comment "default/web cluster IP" -m tcp --dport 80 -j KUBE-SVC-LOLE4ISW44XBNF3G
-A KUBE-SVC-LOLE4ISW44XBNF3G -m comment --comment "default/web" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-PO5YJF2LZTBQLFX5
-A KUBE-SVC-LOLE4ISW44XBNF3G -m comment --comment "default/web" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-OUZ3ZV3ZECH37O4J
-A KUBE-SVC-LOLE4ISW44XBNF3G -m comment --comment "default/web" -j KUBE-SEP-AHKVJ4M3GZYQHEVU如果你已經講代理模式改為IPVS了,可以通過這種方式查看:
[root@k8s-node1 ~]# ipvsadm -ln
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
...
TCP 10.104.0.64:80 rr
-> 10.244.169.135:80 Masq 1 0 0
-> 10.244.36.73:80 Masq 1 0 0
-> 10.244.169.136:80 Masq 1 0 0...正常會得到上面結果,如果沒有對應規(guī)則,說明kube-proxy組件沒工作或者與當前操作系統(tǒng)不兼容導致生成規(guī)則失敗。
附:Service工作流程圖

- END -
公眾號后臺回復「加群」加入一線高級工程師技術交流群,一起交流進步。
推薦閱讀 31天拿下K8s含金量最高的CKA證書!【本周開班】 Kubernetes 運維架構師實戰(zhàn)集訓營 Docker環(huán)境部署Prometheus+Grafana監(jiān)控系統(tǒng) 搞懂 Prometheus 告警神器 Alertmanager Zabbix 通過 API 監(jiān)控 Kubernetes Kubernetes 學習筆記總結,超詳細! Kubernetes生產環(huán)境最佳實踐 高性能 Nginx HTTPS 調優(yōu) - 如何為 HTTPS 提速 30%
點亮,服務器三年不宕機


