最近在处理Kubernetes中的DNS解析问题。正好借此机会学习了下Kubernetes中DNS服务器的工作原理。DNS服务器问题稍后会在博客中介绍。我对解析过程的理解比较肤浅,只介绍配置中的内容。Pod中的DNS概述是众所周知的。DNS服务器用于将域名转换为IP(具体建议查看下7层网络模型进行转换)。Linux服务器中的DNS解析配置位于/etc/resolv.conf,在Pod中也不例外。下面是一个Pod中的配置:nameserver10.96.0.10searchkube-system.svc.cluster.localsvc.cluster.localcluster.localoptionsndots:5如果我们平时想修改我们本地机器上的DNS服务器,比如我们想要改成8.8.8.8,我们修改成这样:nameserver8.8.8.8nameserver8.8.4.4如果要调试DNS服务器,测试返回结果,可以使用dig工具:>digbaidu.com@8.8.8.8;<<>>DiG9.16.10<<>>baidu.com@8.8.8.8;;globaloptions:+cmd;;Goanswer:;;->>HEADER<<-opcode:QUERY,status:NOERROR,id:5114;;flags:qrrdra;QUERY:1,ANSWER:2,AUTHORITY:0,ADDITIONAL:1;;OPTPSEUDOSECTION:;EDNS:version:0,flags:;udp:512;;QUESTIONSECTION:;baidu.com.INA;;ANSWERSECTION:baidu.com.159INA39.156.69.79baidu.com.159INA220.181.38.148;;Querytime:10msec;;SERVER:8.8.8.8#53(8.8.8.8);;时间:TueJan1209:26:13HKT2021;;MSGSIZERcvd:70DNSserver–nameserver先来看nameserver10.96.0.10,为什么请求这个地址可以进行DNS解析。答案是iptables,我只拦截UDP53端口,通过iptables-save可以得到以下内容。-AKUBE-SERVICES-d10.96.0.10/32-pudp-mcomment--comment"kube-system/kube-dns:dnsclusterIP"-mudp--dport53-jKUBE-SVC-TCOU7JCQXEZGVUNU#简单解释一下,这条规则的意思是如果目标地址是10.96.0.10的udp53端口,那么就会跳转到这条链`KUBE-SVC-TCOU7JCQXEZGVUNU`让我们看一下这款链条又一个链,kube-svc-tcou7jcqxezgvunu:-akube-svc-tcou7jcqxezgvunu-mstatistic-mstatistic-mstatistic-moderom-moderom--probibality-probibality-50000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Y00000000000000000000来-Q3HNNZPXUAYYDXW2-pudp-mudp-jDNAT--to-destination172.32.3.219:53-AKUBE-SEP-BBR3Z5NWFGXGVHEZ-pudp-mudp-jDNAT--to-destination172.32.6.239:53#联系前面的规则,完成这些规则的含义是:#在本机中,发送到10.96.0.10:53的一半流量转发到172.32.3.219:53,另一半转发到172.32.6.239:53KubernetesDeploymentandthen查看我们Kubernetes中Pod的IP地址,也就是说DNS请求实际上会在我们的Coredns容器中处理>kubectl-nkube-systemgetpods-owide|grepdnscoredns-646bc69b8d-jd22w1/1Running057d172.32.6.239m1coredns-646bc69b8d-p8pqq1/1Running8315d172.32.3.219m2Service在Kubernetes中的具体实现再查看对应的Service,可以看到Iptables中的上面的machine其实就是Service的具体实现方法。>kubectl-nkube-systemgetsvc|grepdnskube-dnsClusterIP10.96.0.1053/UDP,53/TCP,9153/TCP398d可能有人会有疑问,现在2Pod可以平分对于流量,如果有3个或4个Pod,Iptables是怎么转发的呢?我正好有这个疑问,所以我又加了2个Pod,看看iptables是如何在4个Pod之间平均分流的。这是最终的实现:-AKUBE-SVC-TCOU7JCQXEZGVUNU-mstatistic--moderandom--probability0.25000000000-jKUBE-SEP-HTZHQHQPOHVVNWZS-AKUBE-SVC-TCOU7JCQXEZGVUNU-mstatistic--moderandom--probability0.3334V-AVKEKF323334-HTZHQHQPOHVVNWZS-TCOU7JCQXEZGVUNU-MSTATISTIS-MODERANDOM--PROBIABIES0.500000000-JKUBE-JKUBE-SEP-Q3HHNNNZPXUAYYDXW2-AKUBE-SVC-TCC-TCCCQXEZGCXEZGVUNU-JKBUBE-JKBUBE-SEP-SSEP-BBR3Z5NWZ5NWZ5NWFGGVHEY是4left3/4trafficleft,1/3toachain,2/4left2/4browsing,1/2toachain,1/4left最后1/4to这样交通均匀。这样,5或10也可以为了分析.resolv.confsearchkube-system.svc.cluster.localsvc.cluster.localcluster.localoptionsndots:5中其他参数的详细介绍可以看这里:resolv.conf手册,我简单说明一下我的理解。搜索参数如果没有这个搜索参数,我们搜索的时候:>pingkube-dnsping:kube-dns:Nameorservicenotknown如果添加了搜索参数,那么搜索:>pingkube-dnsPINGkube-dns.kube-system.svc.psigor-dev.Nease.net(10.96.0.10)56(84)字节的数据。可以看出,在解析域名时,如果找不到给定的域名,会在search之后加上后缀进行搜索(如果以.结尾,类似于kube-dns.,这样的域名不会被tryedagain,fqdndomainname).search的工作就是帮我们试试,在kubenetes中使用,配置kube-system.svc.cluster.localsvc.cluster.localcluster.local会帮我们试试,wepingabc,we将这样查询[INFO]10.202.37.232:50940-51439"AINabc.kube-system.svc.cluster.local.udp51false512"NXDOMAINqr,aa,rd1440.000114128s[INFO]10.202.37.232:51823-54524"AINabc.svc.cluster.local.udp39false512“nxDomainqr,aa,rd1320.000124048s[info]10.202.37.232:41894-15434“ainabc.cluster.local.udp35false512"AINabc.udp21false512"NOERRORqr,aa,rd,ra940.000163406sndots及其优化问题搜索配置需要和ndots一起使用,默认ndots为1,其作用是:如果查询域名中的点数小于该值,它会先尝试在搜索域中添加后缀。包含少于n个点(默认为1)的解析器查询将依次使用搜索路径的每个组件进行尝试,直到找到匹配项。比如我们的DNS配置如下:searchkube-system.svc.cluster.localsvc.cluster.localcluster.localoptionsndots:2当我们pingabc.123(这个域名只有一个点)时,DNS服务器日志如下如下,可以注意到日志中第一次尝试的是abc.123.kube-system.svc.cluster.local.,我们的域名会最后尝试。[信息]10.202.37.232:33386-36445"AINabc.123.kube-system.svc.cluster.local.udp55false512"NXDOMAINqr,aa,rd1480.001700129s[信息]10.202.37.232:51389-584local3.AINabc.12.udp43false512"NXDOMAINqr,aa,rd1.001117693s[信息]10.202.37.232:32785-4976"AINabc.123.cluster.local.udp39false512"NXDOMAINqr,aa,rd1320.001047215s[信息]10.202.37.232:57827-56555"AINabc.123.cluster.local.udp39false512",ra1000.001763186s,然后我们pingabc.123.def(这个域名有两个点),DNS服务器的日志如下,注意日志中的优先级是abc.123.def.[INFO]10.202.37.232:39314-794"AINabc.123.def.udp29false512"NXDOMAINqr,rd,ra1040.025049846s[信息]10.202.37.232:51736-61456"AINabc.123.def.kube-system.svc.cluster.local.udp51Nalse5",aa,rd1520.001213934s[信息]10.202.37.232:53145-26709"AINabc.123.def.svc.cluster.local.udp47false512"NXDOMAINqr,aa,rd1400.001418143s[信息]10.202.34"abc.1235".def.cluster.local.udp43false512"NXDOMAINqr,aa,rd1360.001009799s希望通过这个例子让大家明白两点:不管有多少个ndot,搜索参数中的后缀都会被这个搜索到(我们在测试中使用了一个不存在的域名,解析工具试过了allpossibility)ndots不能正确设置可能会对DNS服务器造成压力(如果域名存在,dns查询会尽快返回,不会继续搜索,减轻服务器压力)优化讨论如果当前ndots为2,我们要查询baidu.com,由于配置中的点数为1小于2,所以会先添加后缀进行搜索:[INFO]10.202.37.232:42911-55931"AINbaidu.com.kube-system.svc.cluster.local.udp57false512"NXDOMAINqr,aa,rd1500.000116042s[INFO]10.202.37.232:53722-33218"AINbaidu.com.svc.cluster.local.udp45false512"NXDOMAINqr,aa,rd1380.000075077s[信息]10.202.37.232:46487.INcbaid3.udp41false512"NXDOMAINqr,aa,rd1340.000067313s[信息]10.202.37.232:48360-51853"AINbaidu.com.udp27false512"NOERRORqr,aa,rd,ra770.000127309s然后,我们会生成3条无用的DNS查询记录。对于DNS服务器,只有域名baidu.com,流量变成4倍。如果n继续增加,像Kubernetes中默认的5,那么我们就会产生更多的无效请求,因为不仅有baidu.com,还有map.baidu.com,m.map。baidu.com,这些域名也要从搜索域尝试,这样会给DNS服务器带来很大的压力。我个人的建议:如果内部服务之间有频繁的请求,也就是我们需要经常访问xxx.svc.cluster。对于local这样的域名,可以保持ndots大一些,但是当内部服务之间的请求较少时,强烈建议减少ndots,以减少无用流量的产生,减轻dns服务器的压力。如果我个人用的话,改成2。总结的很好抱歉,这篇文章大部分是讲nameserver是怎么解析的,resolv.conf里面的内容比较少,主要是我一直在看前几天的iptables,这次刚好有,所以抽空看了下,可能有种想炫技的心理。解决问题的时候,更重要的是了解后面的参数。我也发布了一些我自己的实验。希望对大家有所帮助。至少在理解了ndots之后再考虑调优。