問題描述
在搭建Kubernetes集群過程中痢掠,安裝了kube-dns插件后仓技,運(yùn)行一個ubuntu容器施禾,發(fā)現(xiàn)容器內(nèi)無法解析集群外域名颁湖,一開始可以解析集群內(nèi)域名宣蠕,一段時間后也無法解析集群內(nèi)域名。
$ nslookup kubernetes.default
Server: 10.99.0.2
Address 1: 10.99.0.2 kube-dns.kube-system.svc.cluster.local
nslookup: can't resolve 'kubernetes.default'
排查過程
在排查問題前甥捺,先思考一下Kubernetes集群中的DNS解析過程抢蚀,在安裝好kube-dns的集群中,普通Pod的dnsPolicy屬性是默認(rèn)值ClusterFirst镰禾,也就是會指向集群內(nèi)部的DNS服務(wù)器皿曲,kube-dns負(fù)責(zé)解析集群內(nèi)部的域名唱逢,kube-dns Pod的dnsPolicy值是Default,意思是從所在Node繼承DNS服務(wù)器屋休,對于無法解析的外部域名惶我,kube-dns會繼續(xù)向集群外部的dns進(jìn)行查詢,過程如圖博投。
Ubuntu容器是一個普通的Pod,在Linux系統(tǒng)中盯蝴,/etc/resolv.conf是存儲DNS服務(wù)器的文件毅哗,普通Pod的/etc/resolv.conf文件應(yīng)該存儲的是kube-dns的Service IP。
nameserver 10.99.0.2 # 這里存儲的是kube-dns的Service IP
search default.svc.cluster.local. svc.cluster.local. cluster.local.
options ndots:5
查看后發(fā)現(xiàn)/etc/resolv.conf文件中存儲的是kube-dns的Service IP捧挺,證明這一步?jīng)]有問題虑绵,接下來查看一下kube-dns的Pod,先進(jìn)入kube-dns的Pod中檢查一下/etc/resolv.conf文件闽烙,這里存儲的應(yīng)該是集群外部的DNS服務(wù)器地址翅睛,查看后發(fā)現(xiàn),這里存儲的地址是127.0.0.53黑竞,進(jìn)一步查看kube-dns Pod的log捕发,發(fā)現(xiàn)出現(xiàn)了非常多的i/o timeout錯誤。
2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:38019->127.0.0.53:53: i/o timeout
2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:57567->127.0.0.53:53: i/o timeout
2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:52599->127.0.0.53:53: i/o timeout
2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:42539->127.0.0.53:53: i/o timeout
2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:46885->127.0.0.53:53: i/o timeout
2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:44189->127.0.0.53:53: i/o timeout
2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:56505->127.0.0.53:53: i/o timeout
2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:47320->127.0.0.53:53: i/o timeout
2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:42464->127.0.0.53:53: i/o timeout
2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:49203->127.0.0.53:53: i/o timeout
2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:58103->127.0.0.53:53: i/o timeout
2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:47148->127.0.0.53:53: i/o timeout
2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:36883->127.0.0.53:53: i/o timeout
2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:40968->127.0.0.53:53: i/o timeout
2018/07/11 07:12:47 [ERROR] 2 [www.baidu.com](http://www.baidu.com/). A: unreachable backend: read udp 127.0.0.1:55672->127.0.0.53:53: i/o timeout
現(xiàn)在基本上可以發(fā)現(xiàn)問題的原因了很魂,kube-dns只能解析集群內(nèi)部地址扎酷,而集群外部地址應(yīng)該發(fā)給外部DNS服務(wù)器進(jìn)行解析,由于kube-dns Pod中的/etc/resolv.conf文件存儲的DNS服務(wù)器地址是127.0.0.53遏匆,127...*都是回環(huán)地址法挨,也就是集群外域名的DNS解析請求會再次發(fā)送回kube-dns,導(dǎo)致形成一個循環(huán)幅聘,這也是一秒鐘會出現(xiàn)幾十次i/o timeout日志的原因凡纳,請求會不斷的在kube-dns中循環(huán),kube-dns就像一個黑洞一樣帝蒿,吃掉了所有dns解析請求荐糜,不斷累積的請求最終會導(dǎo)致整個集群的網(wǎng)絡(luò)出現(xiàn)卡頓。
為什么
雖然問題的原因找到了葛超,但是為什么kube-dns Pod中/etc/resolv.conf文件存儲的DNS服務(wù)器是127.0.0.53狞尔?
kube-dns Pod的dnsPolicy值是Default,查看一下Kubernetes文檔巩掺。
"
Default
": The Pod inherits the name resolution configuration from the node that the pods run on. See related discussion for more details.
所以kube-dns的/etc/resolv.conf文件是從Node中繼承來的偏序,查看Node中的/etc/resolv.conf文件,存儲的DNS服務(wù)器地址確實(shí)是127.0.0.53胖替,那么下一個問題出現(xiàn)了研儒,在Node中發(fā)送DNS解析請求為什么不會產(chǎn)生回環(huán)的問題呢豫缨?
Node使用的是Ubuntu 18.04 Server,在這個版本的系統(tǒng)中端朵,DNS解析請求并不是直接發(fā)給所在網(wǎng)絡(luò)的DNS服務(wù)器的好芭,Ubuntu 18.04中有一個systemd-resolved服務(wù),為本地應(yīng)用程序提供了DNS解析服務(wù)冲呢,例如nslookup localhost舍败,解析程序從/etc/resolv.conf文件中找到DNS服務(wù)器127.0.0.53,發(fā)送解析請求敬拓,systemd-resolved會監(jiān)聽在53端口上邻薯,捕獲到解析請求后,如果是自己可以解析的乘凸,例如localhost厕诡,會直接返回127.0.0.1,如果不能解析营勤,才會發(fā)送給外部服務(wù)器灵嫌,而外部服務(wù)器的地址存儲在/run/systemd/resolve/resolv.conf文件中,這個文件是systemd-resolved服務(wù)器的配置文件葛作,過程如圖寿羞。
怎么破
理解了問題的來龍去脈,解決問題的辦法也就應(yīng)運(yùn)而生赂蠢。在Kubernetes集群中稠曼,kubelet是worker組建,負(fù)責(zé)管理Pod客年,根據(jù)kubernetes文檔霞幅,kubelet默認(rèn)會從Node的/etc/resolv.conf文件讀取DNS服務(wù)器地址,使得dnsPolicy是Default的Pod得以繼承量瓜,kubelet中的--resolv-conf參數(shù)可以指定這個配置文件的地址司恳。在Ubuntu 18.04中,將這個參數(shù)設(shè)置為systemd-resolved的DNS服務(wù)器配置文件/run/systemd/resolve/resolv.conf绍傲,Pod就會繼承真正的外部DNS服務(wù)器扔傅。
總結(jié)
通過對問題的探究,也理解了Kubernetes集群中DNS解析的完整過程烫饼,如圖猎塞。
* 在Ubuntu 16.04中也是類似的邏輯,只不過systemd-resolved換成了dnsmasq杠纵,監(jiān)聽地址是127.0.1.1
* 在具體實(shí)踐過程中荠耽,也順便探究了CoreDNS和KubeDNS架構(gòu)和解析邏輯上的區(qū)別,不過不在此問題的討論范圍比藻,有興趣的朋友可以自己看一下铝量。
* 如果Kubernetes集群是安裝在NAT網(wǎng)絡(luò)下的虛擬機(jī)上倘屹,虛擬機(jī)(也就是Kubernetes集群中的Node)中/etc/resolv.conf文件可能被修改為NAT的地址,也就不會出現(xiàn)上面這個問題慢叨。
參考內(nèi)容
https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/
https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/
https://kubernetes.io/docs/tasks/administer-cluster/dns-custom-nameservers/
https://www.freedesktop.org/software/systemd/man/systemd-resolved.service.html
https://github.com/kubernetes/kubernetes/issues/49411
https://github.com/kubernetes/kubernetes/issues/45828