最近在处理Kuberntes中的DNS解析问题, 正好借这个机会学习下Kubernetes中的DNS服务器工作原理, 处理的dns服务器问题会稍后再水一篇博客介绍.
我对解析过程的了解也比较粗浅, 仅介绍下配置中的内容.
众所周知, DNS服务器用于将域名转换为IP(具体为啥要转换建议复习下7层网络模型). Linux服务器中, dns解析配置位于/f
, 在pod中也不例外, 下面是某个Pod中的配置:
1 2 3 | nameserver 10.96.0.10 search kube-system.svc.cluster.local svc.cluster.local cluster.local options ndots:5 |
假如我们平时想要修改自己本机上的dns服务器, 比如想要修改为8.8.8.8
, 就会这么去修改:
1 2 | nameserver 8.8.8.8 nameserver 8.8.4.4 |
如果想要调试DNS服务器, 测试返回结果, 可以使用dig工具:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | > dig baidu @8.8.8.8; <<>> DiG 9.16.10 <<>> baidu @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. IN A;; ANSWER SECTION: baidu. 159 IN A 39.156.69.79 baidu. 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 |
我们先从nameserver 10.96.0.10
来看, 为什么请求这个地址可以进行DNS解析. 这个答案就是iptables
, 我仅截取udp的53端口, 以下内容可以通过iptables-save
获得.
1 2 | -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 # 简单解释下, 这条规则表示, 如果目标地址是 10.96.0.10的udp53端口, 那么就会跳转到这条链上`KUBE-SVC-TCOU7JCQXEZGVUNU` |
我们再看下这条链KUBE-SVC-TCOU7JCQXEZGVUNU
:
1 2 3 4 5 6 7 8 | -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# 联系之前的规则, 这几条规则完整的意思是: # 本机中, 发给10.96.0.10:53的流量, 一半转发到172.32.3.219:53, 另一半转发到172.32.6.239:53 |
再看下我们的kubernetes中pod的IP地址, 也就是说, dns请求实际上会到我们的coredns容器中被处理.
1 2 3 | > 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> |
再查看下对应的service, 可以看到, 上述机器中的iptables其实就是service的具体实现方式.
1 2 | > kubectl -n kube-system get svc | grep dns kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 398d |
可能有人会有疑问, 现在是2个pod可以均分流量, 如果是3个, 4个pod, iptables是如何做转发的呢, 正好我有这个疑问, 因此我就再加了2个pod, 看看iptables
是怎么实现对于4个pod均分流量的.
这是最后的实现方式:
1 2 3 4 | -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 |
这些语句的意思应该是:
通过这样的方式对流量进行了均分, 还是挺巧妙的, 这样, 5个,10个也是可以依次去分的.
1 2 | search kube-system.svc.cluster.local svc.cluster.local cluster.local options ndots:5 |
详细的介绍可以看这里: f手册, 我简单的说下我的理解.
假如没有这个search
参数, 我们查找时:
1 2 | > ping kube-dns ping: kube-dns: Name or service not known |
如果增加了search
参数后, 再去查找:
1 2 | > ping kube-dns PING kube-dns.kube-system.ase (10.96.0.10) 56(84) bytes of data. |
可以看到, 解析域名时, 如果给定的域名无法查找, 会添加search
后面的后缀进行查找(假如以.
结尾, 类似kube-dns.
, 这样的域名不会再去尝试, FQDN域名).
search
的工作就是帮我们去尝试, 用在kubenetes中, 配置kube-system.svc.cluster.local svc.cluster.local cluster.local
就会帮我们尝试, 我们ping abc
, 就会这样进行查询
1 2 3 4 | [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 |
search
配置需要与ndots
一起使用, 默认的ndots
是1, 它的作用是: 如果检查到被查询的域名中dot
的数量小于该值时, 就会优先尝试添加search
域中的后缀.
1 2 3 4 | 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. |
实际举例
假如我们的dns配置如下:
1 2 | search kube-system.svc.cluster.local svc.cluster.local cluster.local options ndots:2 |
当我们ping abc.123
(此域名只有一个dot), dns服务器的日志如下, 可以注意到日志中最先尝试的是abc.123.kube-system.svc.cluster.local.
, 最后才会尝试我们的域名.
1 2 3 4 | [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
(此域名有两个dot), dns服务器的日志像下面这样, 注意到日志中最优先尝试的是abc.123.def.
1 2 3 4 | [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 |
希望借这个例子让大家明白两点:
优化讨论
假如现在ndots是2, 我们想要查询baidu
, 由于dot数目为1小于配置中的2, 会首先添加后缀进行查找:
1 2 3 4 | [INFO] 10.202.37.232:42911 - 55931 "A IN baidu.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.svc.cluster.local. udp 45 false 512" NXDOMAIN qr,aa,rd 138 0.000075077s [INFO] 10.202.37.232:46487 - 50053 "A IN baidu.cluster.local. udp 41 false 512" NXDOMAIN qr,aa,rd 134 0.000067313s [INFO] 10.202.37.232:48360 - 51853 "A IN baidu. udp 27 false 512" NOERROR qr,aa,rd,ra 77 0.000127309s |
那么, 我们会产生3个无用的dns查询记录. 对于DNS服务器来说, 仅仅是baidu
这个域名, 流量就变成了4倍. 假如n继续增大呢, 就像是Kubernetes
中默认给定的5, 那我们会产生更多的无效请求, 因为不只是baidu
, 就连map.baidu
, m.map.baidu
, 这些域名也要从search域中开始尝试, 会对DNS服务器造成比较大的压力.
我个人建议:
- 如果内部服务之间请求十分频繁, 也就是我们需要经常访问
xxx.svc.cluster.local
这样的域名, 那么可以保持ndots较大- 但是内部服务之间请求比较少时, 强烈建议调小ndots, 以减少无用流量的产生, 减轻dns服务器的压力 我个人用的话, 改成2就好
很抱歉, 这篇文章的大部分篇幅都是在说nameserver
是如何解析的, iptables
, 这次正好有, 所以花时间看下, 可能有种想要炫技的心理吧.
解决问题的时候, 理解后面的参数是比较重要的, 我也贴了一些自己的实验, 希望能对大家有所帮助吧, 至少了解了ndots之后再考虑调优.
原文作者: corvofeng
原文链接: /
许可协议: 知识共享署名-非商业性使用 4.0 国际许可协议
本文发布于:2024-02-04 16:53:59,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170712122257545.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |