最近在处理 Kuberntes 中的 DNS 解析问题, 正好借这个机会学习下 Kubernetes 中的 DNS 服务器工作原理, 处理的 DNS 服务器问题会稍后再水一篇博客介绍.
我对解析过程的了解也比较粗浅, 仅介绍下配置中的内容.
Pod 中的 DNS 概览
众所周知, DNS 服务器用于将域名转换为 IP (具体为啥要转换建议复习下 7 层网络模型). Linux 服务器中 DNS 解析配置位于/etc/resolv.conf
, 在 Pod 中也不例外, 下面是某个 Pod 中的配置:
1 | nameserver 10.96.0.10 |
假如我们平时想要修改自己本机上的 DNS 服务器, 比如想要修改为8.8.8.8
, 就会这么去修改:
1 | nameserver 8.8.8.8 |
如果想要调试 DNS 服务器, 测试返回结果, 可以使用 dig 工具:
1 | > dig baidu.com @8.8.8.8 |
DNS 服务器 – nameserver
我们先从nameserver 10.96.0.10
来看, 为什么请求这个地址可以进行 DNS 解析. 这个答案就是 iptables
, 我仅截取 UDP 的 53 端口, 以下内容可以通过iptables-save
获得.
1 | -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 |
我们再看下这条链KUBE-SVC-TCOU7JCQXEZGVUNU
:
1 | -A KUBE-SVC-TCOU7JCQXEZGVUNU -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-Q3HNNZPXUAYYDXW2 |
Kubernetes 的 Deployment
再看下我们的 Kubernetes 中 Pod 的 IP 地址, 也就是说, DNS 请求实际上会到我们的 Coredns 容器中被处理.
1 | > kubectl -n kube-system get pods -o wide | grep dns |
Kubernetes 中 Service 的具体实现
再查看下对应的 Service, 可以看到, 上述机器中的 Iptables 其实就是 Service 的具体实现方式.
1 | > kubectl -n kube-system get svc | grep dns |
可能有人会有疑问, 现在是 2 个 Pod 可以均分流量, 如果是 3 个, 4 个 Pod, Iptables 是如何做转发的呢, 正好我有这个疑问, 因此我就再加了 2 个 Pod, 看看iptables
是怎么实现对于 4 个 Pod 均分流量的.
这是最后的实现方式:
1 | -A KUBE-SVC-TCOU7JCQXEZGVUNU -m statistic --mode random --probability 0.25000000000 -j KUBE-SEP-HTZHQHQPOHVVNWZS |
这些语句的意思应该是:
- 前 1/4 的流量到一条链中, 剩 3/4
- 剩下 3/4 的流量, 1/3到一条链, 剩 2/4
- 剩下 2/4 的浏览, 1/2到一条链, 剩 1/4
- 最后 1/4 到一条链
通过这样的方式对流量进行了均分, 还是挺巧妙的, 这样, 5个,10个也是可以依次去分的.
resolv.conf 中其他参数解析
1 | search kube-system.svc.cluster.local svc.cluster.local cluster.local |
详细的介绍可以看这里: resolv.conf手册, 我简单的说下我的理解.
search 参数
假如没有这个search
参数, 我们查找时:
1 | > ping kube-dns |
如果增加了search
参数后, 再去查找:
1 | > ping kube-dns |
可以看到, 解析域名时, 如果给定的域名无法查找, 会添加search
后面的后缀进行查找(假如以.
结尾, 类似kube-dns.
, 这样的域名不会再去尝试, FQDN域名).
search
的工作就是帮我们去尝试, 用在 Kubenetes 中, 配置kube-system.svc.cluster.local svc.cluster.local cluster.local
就会帮我们尝试, 我们ping abc
, 就会这样进行查询
1 | [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 |
ndots 以及其优化问题
search
配置需要与ndots
一起使用, 默认的ndots
是 1, 它的作用是: 如果检查到被查询的域名中dot
的数量小于该值时, 就会优先尝试添加search
域中的后缀.
1 | Resolver queries having fewer than |
实际举例
假如我们的 DNS 配置如下:
1 | search kube-system.svc.cluster.local svc.cluster.local cluster.local |
当我们ping abc.123
(此域名只有一个 dot ), DNS 服务器的日志如下, 可以注意到日志中最先尝试的是abc.123.kube-system.svc.cluster.local.
, 最后才会尝试我们的域名.
1 | [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 |
那我们ping abc.123.def
(此域名有两个 dot), DNS 服务器的日志像下面这样, 注意到日志中最优先尝试的是abc.123.def.
1 | [INFO] 10.202.37.232:39314 - 794 "A IN abc.123.def. udp 29 false 512" NXDOMAIN qr,rd,ra 104 0.025049846s |
希望借这个例子让大家明白两点:
- 无论 ndots 是多少, search 参数中的后缀都会被以此查找(我们测试时使用了一个不存在的域名, 解析工具尝试了全部的可能)
- ndots 的不妥当设置, 可能会给 DNS 服务器造成压力(假如域名是存在的, dns查询会尽快返回, 不会继续查找了, 会减少服务器压力)
优化讨论
假如现在 ndots 是 2, 我们想要查询baidu.com
, 由于 dot 数目为 1 小于配置中的 2, 会首先添加后缀进行查找:
1 | [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 |
那么, 我们会产生 3 个无用的 DNS 查询记录. 对于DNS服务器来说, 仅仅是baidu.com
这个域名, 流量就变成了4倍. 假如 n继续增大呢, 就像是Kubernetes
中默认给定的5, 那我们会产生更多的无效请求, 因为不只是baidu.com
, 就连map.baidu.com
, m.map.baidu.com
, 这些域名也要从search域中开始尝试, 会对 DNS 服务器造成比较大的压力.
我个人建议:
- 如果内部服务之间请求十分频繁, 也就是我们需要经常访问
xxx.svc.cluster.local
这样的域名, 那么可以保持 ndots 较大- 但是内部服务之间请求比较少时, 强烈建议调小 ndots, 以减少无用流量的产生, 减轻 dns 服务器的压力 我个人用的话, 改成 2 就好
总结
很抱歉, 这篇文章的大部分篇幅都是在说 nameserver
是如何解析的, resolv.conf
中的内容比较少, 主要原因是我前些天一直在看iptables
, 这次正好有, 所以花时间看下, 可能有种想要炫技的心理吧.
解决问题的时候, 理解后面的参数是比较重要的, 我也贴了一些自己的实验, 希望能对大家有所帮助吧, 至少了解了ndots之后再考虑调优.
本文转载自:「 我的小米粥分你一半 」,原文:https://tinyurl.com/yynhvbvz ,版权归原作者所有。欢迎投稿,投稿邮箱: editor@hi-linux.com。