一文搞懂Kubernetes如何實(shí)現(xiàn)DNS解析
最近在處理 Kuberntes 中的 DNS 解析問(wèn)題, 正好借這個(gè)機(jī)會(huì)學(xué)習(xí)下 Kubernetes 中的 DNS 服務(wù)器工作原理, 處理的 DNS 服務(wù)器問(wèn)題會(huì)稍后再水一篇博客介紹.
我對(duì)解析過(guò)程的了解也比較粗淺, 僅介紹下配置中的內(nèi)容.
Pod 中的 DNS 概覽
眾所周知, DNS 服務(wù)器用于將域名轉(zhuǎn)換為 IP (具體為啥要轉(zhuǎn)換建議復(fù)習(xí)下 7 層網(wǎng)絡(luò)模型). Linux 服務(wù)器中 DNS 解析配置位于/etc/resolv.conf, 在 Pod 中也不例外, 下面是某個(gè) Pod 中的配置:
- nameserver 10.96.0.10
- search kube-system.svc.cluster.local svc.cluster.local cluster.local
- options ndots:5
假如我們平時(shí)想要修改自己本機(jī)上的 DNS 服務(wù)器, 比如想要修改為8.8.8.8, 就會(huì)這么去修改:
- nameserver 8.8.8.8
- nameserver 8.8.4.4
如果想要調(diào)試 DNS 服務(wù)器, 測(cè)試返回結(jié)果, 可以使用 dig 工具:
- > dig baidu.com @8.8.8.8
- ; <<>> DiG 9.16.10 <<>> baidu.com @8.8.8.8
- ;; global options: +cmd
- ;; Got answer:
- ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 5114
- ;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
- ;; OPT PSEUDOSECTION:
- ; EDNS: version: 0, flags:; udp: 512
- ;; QUESTION SECTION:
- ;baidu.com. IN A
- ;; ANSWER SECTION:
- baidu.com. 159 IN A 39.156.69.79
- baidu.com. 159 IN A 220.181.38.148
- ;; Query time: 10 msec
- ;; SERVER: 8.8.8.8#53(8.8.8.8)
- ;; WHEN: Tue Jan 12 09:26:13 HKT 2021
- ;; MSG SIZE rcvd: 70
DNS 服務(wù)器 – nameserver
我們先從nameserver 10.96.0.10來(lái)看, 為什么請(qǐng)求這個(gè)地址可以進(jìn)行 DNS 解析. 這個(gè)答案就是 iptables, 我僅截取 UDP 的 53 端口, 以下內(nèi)容可以通過(guò)iptables-save獲得.
- -A KUBE-SERVICES -d 10.96.0.10/32 -p udp -m comment --comment "kube-system/kube-dns:dns cluster IP" -m udp --dport 53 -j KUBE-SVC-TCOU7JCQXEZGVUNU
- # 簡(jiǎn)單解釋下, 這條規(guī)則表示, 如果目標(biāo)地址是 10.96.0.10的udp53端口, 那么就會(huì)跳轉(zhuǎn)到這條鏈上`KUBE-SVC-TCOU7JCQXEZGVUNU`
我們?cè)倏聪逻@條鏈KUBE-SVC-TCOU7JCQXEZGVUNU:
- -A KUBE-SVC-TCOU7JCQXEZGVUNU -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-Q3HNNZPXUAYYDXW2
- -A KUBE-SVC-TCOU7JCQXEZGVUNU -j KUBE-SEP-BBR3Z5NWFGXGVHEZ
- -A KUBE-SEP-Q3HNNZPXUAYYDXW2 -p udp -m udp -j DNAT --to-destination 172.32.3.219:53
- -A KUBE-SEP-BBR3Z5NWFGXGVHEZ -p udp -m udp -j DNAT --to-destination 172.32.6.239:53
- # 聯(lián)系之前的規(guī)則, 這幾條規(guī)則完整的意思是:
- # 本機(jī)中, 發(fā)給10.96.0.10:53的流量, 一半轉(zhuǎn)發(fā)到172.32.3.219:53, 另一半轉(zhuǎn)發(fā)到172.32.6.239:53
Kubernetes 的 Deployment
再看下我們的 Kubernetes 中 Pod 的 IP 地址, 也就是說(shuō), DNS 請(qǐng)求實(shí)際上會(huì)到我們的 Coredns 容器中被處理.
- > kubectl -n kube-system get pods -o wide | grep dns
- coredns-646bc69b8d-jd22w 1/1 Running 0 57d 172.32.6.239 m1 <none> <none>
- coredns-646bc69b8d-p8pqq 1/1 Running 8 315d 172.32.3.219 m2 <none> <none>
Kubernetes 中 Service 的具體實(shí)現(xiàn)
再查看下對(duì)應(yīng)的 Service, 可以看到, 上述機(jī)器中的 Iptables 其實(shí)就是 Service 的具體實(shí)現(xiàn)方式.
- > kubectl -n kube-system get svc | grep dns
- kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 398d
可能有人會(huì)有疑問(wèn), 現(xiàn)在是 2 個(gè) Pod 可以均分流量, 如果是 3 個(gè), 4 個(gè) Pod, Iptables 是如何做轉(zhuǎn)發(fā)的呢, 正好我有這個(gè)疑問(wèn), 因此我就再加了 2 個(gè) Pod, 看看iptables是怎么實(shí)現(xiàn)對(duì)于 4 個(gè) Pod 均分流量的.
這是最后的實(shí)現(xiàn)方式:
- -A KUBE-SVC-TCOU7JCQXEZGVUNU -m statistic --mode random --probability 0.25000000000 -j KUBE-SEP-HTZHQHQPOHVVNWZS
- -A KUBE-SVC-TCOU7JCQXEZGVUNU -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-3VNFB2SPYQJRRPK6
- -A KUBE-SVC-TCOU7JCQXEZGVUNU -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-Q3HNNZPXUAYYDXW2
- -A KUBE-SVC-TCOU7JCQXEZGVUNU -j KUBE-SEP-BBR3Z5NWFGXGVHEZ
這些語(yǔ)句的意思應(yīng)該是:
- 前 1/4 的流量到一條鏈中, 剩 3/4
- 剩下 3/4 的流量, 1/3到一條鏈, 剩 2/4
- 剩下 2/4 的瀏覽, 1/2到一條鏈, 剩 1/4
- 最后 1/4 到一條鏈
通過(guò)這樣的方式對(duì)流量進(jìn)行了均分, 還是挺巧妙的, 這樣, 5個(gè),10個(gè)也是可以依次去分的.
resolv.conf 中其他參數(shù)解析
- search kube-system.svc.cluster.local svc.cluster.local cluster.local
- options ndots:5
詳細(xì)的介紹可以看這里: resolv.conf 手冊(cè), 我簡(jiǎn)單的說(shuō)下我的理解.
search 參數(shù)
假如沒(méi)有這個(gè)search參數(shù), 我們查找時(shí):
- > ping kube-dns
- ping: kube-dns: Name or service not known
如果增加了search參數(shù)后, 再去查找:
- > ping kube-dns
- PING kube-dns.kube-system.svc.psigor-dev.nease.net (10.96.0.10) 56(84) bytes of data.
可以看到, 解析域名時(shí), 如果給定的域名無(wú)法查找, 會(huì)添加search后面的后綴進(jìn)行查找(假如以.結(jié)尾, 類似kube-dns., 這樣的域名不會(huì)再去嘗試, FQDN域名).
search的工作就是幫我們?nèi)L試, 用在 Kubenetes 中, 配置kube-system.svc.cluster.local svc.cluster.local cluster.local 就會(huì)幫我們嘗試, 我們ping abc, 就會(huì)這樣進(jìn)行查詢
- [INFO] 10.202.37.232:50940 - 51439 "A IN abc.kube-system.svc.cluster.local. udp 51 false 512" NXDOMAIN qr,aa,rd 144 0.000114128s
- [INFO] 10.202.37.232:51823 - 54524 "A IN abc.svc.cluster.local. udp 39 false 512" NXDOMAIN qr,aa,rd 132 0.000124048s
- [INFO] 10.202.37.232:41894 - 15434 "A IN abc.cluster.local. udp 35 false 512" NXDOMAIN qr,aa,rd 128 0.000092304s
- [INFO] 10.202.37.232:40357 - 43160 "A IN abc. udp 21 false 512" NOERROR qr,aa,rd,ra 94 0.000163406s
ndots 以及其優(yōu)化問(wèn)題
search配置需要與ndots一起使用, 默認(rèn)的ndots是 1, 它的作用是: 如果檢查到被查詢的域名中dot的數(shù)量小于該值時(shí), 就會(huì)優(yōu)先嘗試添加search域中的后綴.
- Resolver queries having fewer than
- ndots dots (default is 1) in them will be attempted using
- each component of the search path in turn until a match is
- found.
實(shí)際舉例
假如我們的 DNS 配置如下:
- search kube-system.svc.cluster.local svc.cluster.local cluster.local
- options ndots:2
當(dāng)我們ping abc.123(此域名只有一個(gè) dot ), DNS 服務(wù)器的日志如下, 可以注意到日志中最先嘗試的是abc.123.kube-system.svc.cluster.local., 最后才會(huì)嘗試我們的域名.
- [INFO] 10.202.37.232:33386 - 36445 "A IN abc.123.kube-system.svc.cluster.local. udp 55 false 512" NXDOMAIN qr,aa,rd 148 0.001700129s
- [INFO] 10.202.37.232:51389 - 58489 "A IN abc.123.svc.cluster.local. udp 43 false 512" NXDOMAIN qr,aa,rd 136 0.001117693s
- [INFO] 10.202.37.232:32785 - 4976 "A IN abc.123.cluster.local. udp 39 false 512" NXDOMAIN qr,aa,rd 132 0.001047215s
- [INFO] 10.202.37.232:57827 - 56555 "A IN abc.123. udp 25 false 512" NXDOMAIN qr,rd,ra 100 0.001763186s
那我們ping abc.123.def(此域名有兩個(gè) dot), DNS 服務(wù)器的日志像下面這樣, 注意到日志中最優(yōu)先嘗試的是abc.123.def.
- [INFO] 10.202.37.232:39314 - 794 "A IN abc.123.def. udp 29 false 512" NXDOMAIN qr,rd,ra 104 0.025049846s
- [INFO] 10.202.37.232:51736 - 61456 "A IN abc.123.def.kube-system.svc.cluster.local. udp 59 false 512" NXDOMAIN qr,aa,rd 152 0.001213934s
- [INFO] 10.202.37.232:53145 - 26709 "A IN abc.123.def.svc.cluster.local. udp 47 false 512" NXDOMAIN qr,aa,rd 140 0.001418143s
- [INFO] 10.202.37.232:54444 - 1145 "A IN abc.123.def.cluster.local. udp 43 false 512" NXDOMAIN qr,aa,rd 136 0.001009799s
希望借這個(gè)例子讓大家明白兩點(diǎn):
- 無(wú)論 ndots 是多少, search 參數(shù)中的后綴都會(huì)被以此查找(我們測(cè)試時(shí)使用了一個(gè)不存在的域名, 解析工具嘗試了全部的可能)
- ndots 的不妥當(dāng)設(shè)置, 可能會(huì)給 DNS 服務(wù)器造成壓力(假如域名是存在的, dns查詢會(huì)盡快返回, 不會(huì)繼續(xù)查找了, 會(huì)減少服務(wù)器壓力)
優(yōu)化討論
假如現(xiàn)在 ndots 是 2, 我們想要查詢baidu.com, 由于 dot 數(shù)目為 1 小于配置中的 2, 會(huì)首先添加后綴進(jìn)行查找:
- [INFO] 10.202.37.232:42911 - 55931 "A IN baidu.com.kube-system.svc.cluster.local. udp 57 false 512" NXDOMAIN qr,aa,rd 150 0.000116042s
- [INFO] 10.202.37.232:53722 - 33218 "A IN baidu.com.svc.cluster.local. udp 45 false 512" NXDOMAIN qr,aa,rd 138 0.000075077s
- [INFO] 10.202.37.232:46487 - 50053 "A IN baidu.com.cluster.local. udp 41 false 512" NXDOMAIN qr,aa,rd 134 0.000067313s
- [INFO] 10.202.37.232:48360 - 51853 "A IN baidu.com. udp 27 false 512" NOERROR qr,aa,rd,ra 77 0.000127309s
那么, 我們會(huì)產(chǎn)生 3 個(gè)無(wú)用的 DNS 查詢記錄. 對(duì)于DNS服務(wù)器來(lái)說(shuō), 僅僅是baidu.com這個(gè)域名, 流量就變成了4倍. 假如 n繼續(xù)增大呢, 就像是Kubernetes中默認(rèn)給定的5, 那我們會(huì)產(chǎn)生更多的無(wú)效請(qǐng)求, 因?yàn)椴恢皇莃aidu.com, 就連map.baidu.com, m.map.baidu.com, 這些域名也要從search域中開始嘗試, 會(huì)對(duì) DNS 服務(wù)器造成比較大的壓力.
我個(gè)人建議:
- 如果內(nèi)部服務(wù)之間請(qǐng)求十分頻繁, 也就是我們需要經(jīng)常訪問(wèn)xxx.svc.cluster.local這樣的域名, 那么可以保持 ndots 較大
- 但是內(nèi)部服務(wù)之間請(qǐng)求比較少時(shí), 強(qiáng)烈建議調(diào)小 ndots, 以減少無(wú)用流量的產(chǎn)生, 減輕 dns 服務(wù)器的壓力 我個(gè)人用的話, 改成 2 就好
總結(jié)
很抱歉, 這篇文章的大部分篇幅都是在說(shuō) nameserver 是如何解析的, resolv.conf中的內(nèi)容比較少, 主要原因是我前些天一直在看iptables, 這次正好有, 所以花時(shí)間看下, 可能有種想要炫技的心理吧.
解決問(wèn)題的時(shí)候, 理解后面的參數(shù)是比較重要的, 我也貼了一些自己的實(shí)驗(yàn), 希望能對(duì)大家有所幫助吧, 至少了解了ndots之后再考慮調(diào)優(yōu).