採坑指南——k8s域名解析coredns問題排查過程
採坑指南——k8s域名解析coredns問題排查過程
正文
前幾天,在ucloud上搭建的k8s叢集(搭建教程後續會發出)。今天發現域名解析不了。
元件版本:k8s 1.15.0,coredns:1.3.1
過程是這樣的:
首先用以下yaml檔案建立了一個nginx服務
apiVersion: v1
kind: Service
metadata:
name: nginx-svc-old
labels:
app: nginx-svc
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: nginx-old
spec:
replicas: 1
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
建立好之後:
因只部署了一個master節點。在master宿主機上直接執行以下命令:
nslookup nginx-svc-old.default.svc
發現不能解析域名。事先也在宿主機上/etc/resolv.conf裡配置了nameserver {coredns的podIP}
這樣一來,就以為可能是coredns有問題。。
然後用以下yaml建立了一個busybox作為除錯工具:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: busybox-deployment
spec:
replicas: 1
template:
metadata:
labels:
app: busybox
spec:
restartPolicy: Always
containers:
- name: busybox
command:
- sleep
- "3600"
image: busybox
這裡用的是截止2019/07/20,busybox的最新映象。建立好之後,exec進入容器,執行測試命令
發現解析不了:
/ # nslookup nginx-svc-old.default.svc
Server: 10.96.0.10
Address: 10.96.0.10:53
** server can't find nginx-svc-old.default.svc: NXDOMAIN
*** Can't find nginx-svc-old.default.svc: No answer
根據coredns解析叢集內域名原理可知:
服務 a 訪問服務 b,對於同一個 Namespace下,可以直接在 pod 中,通過 curl b 來訪問。對於跨 Namespace 的情況,服務名後邊對應 Namespace即可,比如 curl b.default。DNS 如何解析,依賴容器內 resolv 檔案的配置。
檢視busybox容器內的resolve.conf檔案:
[root@liabio nginx]# kubectl exec -ti busybox-deployment-59755c8c6d-rmrfq sh
/ # nslookup nginx-svc-old.default.svc
Server: 10.96.0.10
Address: 10.96.0.10:53
** server can't find nginx-svc-old.default.svc: NXDOMAIN
*** Can't find nginx-svc-old.default.svc: No answer
/ # cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
/ #
這個檔案中,配置的 DNS Server,一般就是 K8S 中,kubedns 的 Service 的 ClusterIP,這個IP是虛擬IP,無法ping,但可以訪問。
在容器內發請求時,會根據 /etc/resolv.conf 進行解析流程。選擇 nameserver 10.96.0.10 進行解析,然後用nginx-svc-old ,依次帶入 /etc/resolve.conf 中的 search 域,進行DNS查詢,分別是:
search 內容類似如下(不同的pod,第一個域會有所不同)
search default.svc.cluster.local svc.cluster.local cluster.local
nginx-svc-old.default.svc.cluster.local -> nginx-svc-old.svc.cluster.local -> nginx-svc-old.cluster.local
直到找到為止。所以,我們執行 ping nginx-svc-old,或者執行 ping nginx-svc-old.default,都可以完成DNS請求,這2個不同的操作,會分別進行不同的DNS查詢步驟。
根據以上原理,檢視到busybox內的域名/etc/resolv.conf沒有問題,nameserver指向正確的kube-dns的service clusterIP。
這下更加懷疑core-dns有問題了。
但檢視coredns日誌,可以看到並沒有報錯:
那就說明不是coredns問題了。。
把busybox裡報的錯誤,進行搜尋google
*** Can't find nginx-svc-old.default.svc: No answer
查到了以下兩個issue:
issues1:
https://github.com/kubernetes/kubernetes/issues/66924
issues2:
https://github.com/easzlab/kubeasz/issues/260
發現都說是busybox映象的問題,從1.28.4以後的映象都存在這問題。把映象換成1.28.4試試?修改yaml版本號:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: busybox-deployment
spec:
replicas: 1
template:
metadata:
labels:
app: busybox
spec:
restartPolicy: Always
containers:
- name: busybox
command:
- sleep
- "3600"
image: busybox:1.28.4
重新apply後,進入容器:
確實可以成功解析域名了。
那為什麼宿主機上直接執行測試命令,域名不能解析呢?
繼續google,知道resolver域名解析器:
nameserver關鍵字,如果沒指定nameserver就找不到DNS伺服器,其它關鍵字是可選的。nameserver表示解析域名時使用該地址指定的主機為域名伺服器。其中域名伺服器是按照檔案中出現的順序來查詢的,且只有當第一個nameserver沒有反應時才查詢下面的nameserver,一般不要指定超過3個伺服器。
而我在宿主上/etc/resolv.conf中nameserver如下:
且前三個域名解析伺服器後可以通。
現在試著把coredns的其中一個podIP:192.168.155.73放到第一個nameserver:
可以看到現在可以解析了。
其實最好把kube-dns service的clusterIP放到/etc/resolv.conf中,這樣pod重啟後也可以解析。
參考
Linux中/etc/resolv.conf檔案簡析
https://blog.csdn.net/lcr_happy/article/details/54867510
CoreDNS系列1:Kubernetes內部域名解析原理、弊端及優化方式