在Kubernetes中部署工作负载的主要优势之一是无缝应用程序发现。服务的概念使群集内通信变得容易,服务的概念代表了支持一组Pod IP的虚拟IP。例如,如果香草服务需要与巧克力服务通话,则可以直接使用虚拟IP访问巧克力服务。现在的问题是谁解决了巧克力的DNS查询,如何解决?
DNS解析是通过CoreDNS在Kubernetes集群中配置的。 kubelet将每个Pod的/etc/resolv.conf配置为使用coredns pod作为名称服务器。您可以在任何pod中看到/etc/resolv.conf的内容,它们的外观类似于:
search hello.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.152.183.10
options ndots:5
DNS客户端使用此配置将DNS查询转发到DNS服务器。 resolv.conf是解析程序配置文件,其中包含以下信息:
- nameserver:DNS查询转发到的位置。在我们的例子中,这是CoreDNS服务的地址。
- search:表示特定域的搜索路径。有趣的是google.com或mrkaran.dev不是FQDN(完全合格的域名)。大多数DNS解析器遵循的标准约定是,如果域以结尾.(代表根区域),该域被认为是FQDN。一些解析器试图采取明智的行动,并附加.他们自己。因此,mrkaran.dev. 是FQDN,但mrkaran.dev不是。
- ndots:这是最有趣的值,也是这篇文章的重点。 ndots代表查询名称中的点数阈值,以将其视为“完全合格”域名。稍后,我们会发现DNS查找的流程。
让我们检查一下在pod中查询mrkaran.dev时会发生什么。
$ nslookup mrkaran.dev
Server: 10.152.183.10
Address: 10.152.183.10#53
Non-authoritative answer:
Name: mrkaran.dev
Address: 157.230.35.153
Name: mrkaran.dev
Address: 2400:6180:0:d1::519:6001
在此实验中,我还将CoreDNS日志记录级别设置为所有级别,这使其变得非常冗长。让我们看一下coredns pod的日志:
[INFO] 10.1.28.1:35998 - 11131 "A IN mrkaran.dev.hello.svc.cluster.local. udp 53 false 512" NXDOMAIN qr,aa,rd 146 0.000263728s
[INFO] 10.1.28.1:34040 - 36853 "A IN mrkaran.dev.svc.cluster.local. udp 47 false 512" NXDOMAIN qr,aa,rd 140 0.000214201s
[INFO] 10.1.28.1:33468 - 29482 "A IN mrkaran.dev.cluster.local. udp 43 false 512" NXDOMAIN qr,aa,rd 136 0.000156107s
[INFO] 10.1.28.1:58471 - 45814 "A IN mrkaran.dev. udp 29 false 512" NOERROR qr,rd,ra 56 0.110263459s
[INFO] 10.1.28.1:54800 - 2463 "AAAA IN mrkaran.dev. udp 29 false 512" NOERROR qr,rd,ra 68 0.145091744s
因此,以下两件事值得我们注意:
- 该查询将遍历所有搜索路径,直到答案包含NOERROR代码(DNS客户端将其理解并存储为结果)。 NXDOMAIN仅表示未找到该域名的记录。由于mrkaran.dev不是FQDN(根据ndots = 5设置),因此解析程序会查看搜索路径并确定查询顺序。
- A和AAAA记录并行触发。这是因为/etc/resolv.conf中的单请求选项具有默认配置以执行并行IPv4和IPv6查找。您可以使用单请求选项禁用此功能。
注意:可以将glibc配置为按顺序发送这些请求,但是musl无法发送,因此Alpine用户必须注意。
研磨ndots
让我们测试一下改变ndots之后的变化。这个想法很简单,通过此ndots设置,DNS客户端可以知道某个域是否是绝对的。例如,如果您仅查询google,DNS客户端将如何知道这是否是绝对域。如果您将ndots设置为1,DNS客户端会说:“哦,google连一个1点都没有。让我尝试遍历搜索列表。但是,如果您查询google.com,则搜索列表将被完全忽略,因为查询名称满足ndots阈值(至少一个点)。
我们可以通过实际操作看到它:
$ cat /etc/resolv.conf
options ndots:1
$ nslookup mrkaran
Server: 10.152.183.10
Address: 10.152.183.10#53
** server can't find mrkaran: NXDOMAIN
CoreDNS 日志:
[INFO] 10.1.28.1:52495 - 2606 "A IN mrkaran.hello.svc.cluster.local. udp 49 false 512" NXDOMAIN qr,aa,rd 142 0.000524939s
[INFO] 10.1.28.1:59287 - 57522 "A IN mrkaran.svc.cluster.local. udp 43 false 512" NXDOMAIN qr,aa,rd 136 0.000368277s
[INFO] 10.1.28.1:53086 - 4863 "A IN mrkaran.cluster.local. udp 39 false 512" NXDOMAIN qr,aa,rd 132 0.000355344s
[INFO] 10.1.28.1:56863 - 41678 "A IN mrkaran. udp 25 false 512" NXDOMAIN qr,rd,ra 100 0.034629206s
由于mrkaran没有指定任何内容。因此使用搜索列表来找到答案。
注意:ndots的值默认为15,在Kubernetes中默认为5。
生产环境实践
如果您的应用程序具有进行大量外部网络调用的性质,那么在流量繁忙的情况下,DNS可能会成为瓶颈,因为在触发真正的DNS查询之前还会进行很多额外的查询。看到应用程序在域名中附加根区域的情况很少见,但这可以视为黑客。因此,您可以将应用程序硬编码为包含api.twitter.com.,而不是使用api.twitter.com。这将迫使DNS客户端直接在绝对域上进行权威性查询。
或者,自K8s 1.14起,dnsConfig和dnsPolicy功能门已变得稳定。因此,在部署Pod时,您可以将ndots设置指定为较小的值(例如3),或者如果您想表现出积极性,则可以将其设置为1。其结果是,每个节点内通信现在都必须包含完整的域。这是经典的权衡之一,您必须在性能和可移植性之间进行选择。如果应用程序不需要极低的延迟,我想您根本不必担心这一点,因为DNS结果也是在内部缓存的。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。