K8s容器内部dns解析慢解决方案

需求&背景

K8s内,要对做内部域名解析的劫持,解析 *.lol.com 至 172.34.18.12。
通过在coredns的配置文件配置 *.lol.com 的泛域名解析(如下所示),能够解析成功。但是在容器内部解析公网/内部地址慢。正常的http请求花费5-6秒。

template IN A lol.com {
  match .*\.lol\.com
  answer "{{ .Name }} 60 IN A 172.34.18.12"
  fallthrough
}

K8s容器内部dns解析慢解决方案_第1张图片

问题解决

DNS解析慢可能出现的问题在解析链路的各个环节。我们按照解析的路径逐步排查。在K8s内部从发起解析的设备,到K8s的DNS服务(coredns)。

1)在需要解析域名的容器抓包

首先在需要解析域名的容器内抓包,在容器所在宿主机执行以下步骤。
通过describe命令获取到Pod内的container-id

kubectl describe [po]

获取进程pid

docker inspect -f {{.State.Pid}} [container-id]

使用nsenter进入pid命名空间

nsenter -n -t [pid]

抓包53(dns解析使用)端口的流量,并记录timestamp

tcpdump -n -tt -i eth0 port 53
1654670942.436773 IP 11.5.0.87.59372 > 11.6.0.10.domain: 54304+ A? myfoo.lol.com.my-services.svc.cluster.local. (62)
1654670942.439162 IP 11.6.0.10.domain > 11.5.0.87.59372: 54304 NXDomain*- 0/1/0 (155)
1654670942.439269 IP 11.5.0.87.35180 > 11.6.0.10.domain: 1677+ A? myfoo.lol.com.svc.cluster.local. (50)
1654670942.439900 IP 11.6.0.10.domain > 11.5.0.87.35180: 1677 NXDomain*- 0/1/0 (143)
1654670942.440105 IP 11.5.0.87.40185 > 11.6.0.10.domain: 56859+ A? myfoo.lol.com.cluster.local. (46)
1654670942.441976 IP 11.6.0.10.domain > 11.5.0.87.40185: 56859 NXDomain*- 0/1/0 (139)
1654670942.442056 IP 11.5.0.87.43673 > 11.6.0.10.domain: 52888+ A? myfoo.lol.com.localdomain. (44)
1654670944.443202 IP 11.6.0.10.domain > 11.5.0.87.43673: 52888 ServFail- 0/0/0 (44)
1654670944.443329 IP 11.5.0.87.58234 > 11.6.0.10.domain: 52888+ A? myfoo.lol.com.localdomain. (44)
1654670946.444789 IP 11.6.0.10.domain > 11.5.0.87.58234: 52888 ServFail- 0/0/0 (44)
1654670946.444929 IP 11.5.0.87.59003 > 11.6.0.10.domain: 46828+ A? myfoo.lol.com. (32)
1654670946.445715 IP 11.6.0.10.domain > 11.5.0.87.59003: 46828*- 1/0/0 A 172.34.18.12 (62)
1654670946.448576 IP 11.5.0.87.52708 > 11.6.0.10.domain: 58584+ PTR? 12.18.34.172.in-addr.arpa. (43)
1654670948.449842 IP 11.6.0.10.domain > 11.5.0.87.52708: 58584 ServFail- 0/0/0 (43)
1654670948.450019 IP 11.5.0.87.52435 > 11.6.0.10.domain: 58584+ PTR? 12.18.34.172.in-addr.arpa. (43)
1654670950.451448 IP 11.6.0.10.domain > 11.5.0.87.52435: 58584 ServFail- 0/0/0 (43)

以上 11.5.0.87 是业务pod本身ip,11.6.0.10 是coredns svc 的ip。
以上的抓包结果显示 从11.5.0.87 发起dns解析请求至11.6.0.10。11.6.0.10 返回解析后的dns记录
最左边的timestamp显示1654670942 - 1654670946 相差有8秒
从日志看经历了 myfoo.lol.com.my-services.svc.cluster.local. 到 myfoo.lol.com. 最终解析出172.34.18.12的解析过程。
以上日志表明两点:
1.解析过程带了不同的域。
2.从容器内发起的解析请求指向11.6.0.10

coredns 日志

[ERROR] plugin/errors: 2 giaoxa.lol.com.localdomain. A: read udp 11.5.2.154:40494->114.114.114.114:53: i/o timeout
[ERROR] plugin/errors: 2 12.18.34.172.in-addr.arpa. PTR: read udp 11.5.2.154:38740->114.114.114.114:53: i/o timeout
[ERROR] plugin/errors: 2 12.18.34.172.in-addr.arpa. PTR: read udp 11.5.2.154:44143->114.114.114.114:53: i/o timeout

以上日志中,11.5.2.154是coredns Pod的ip。可以看到和 *.lol.com 相关的请求是 i/o timeout,而且114.114.114.114没有给返回,说明尝试通过114.114.114.114对域名进行解析是失败的

抓包coredns所在宿主机

tcpdump -n -tt -i eth0 port 53

1654681471.359635 IP 172.34.57.8.40494 > 114.114.114.114.domain: 1584+ A? giaoxa.lol.com.localdomain. (45)
1654681471.609660 IP 172.34.57.8.36977 > 114.114.114.114.domain: 5934+ AAAA? alauda.cn.localdomain. (39)
1654681471.609671 IP 172.34.57.8.52810 > 114.114.114.114.domain: 1473+ A? alauda.cn.localdomain. (39)
1654681471.624745 IP 172.34.57.8.39735 > 114.114.114.114.domain: 7872+ AAAA? alauda.cn. (27)
1654681471.624758 IP 172.34.57.8.40497 > 114.114.114.114.domain: 59218+ A? alauda.cn. (27)
1654681472.216579 IP 172.34.57.8.42082 > 114.114.114.114.domain: 53658+ A? alauda.cn. (27)
1654681472.216589 IP 172.34.57.8.33765 > 114.114.114.114.domain: 11138+ AAAA? alauda.cn. (27)
1654681472.321413 IP 172.34.57.8.59460 > 114.114.114.114.domain: 56340+ NS? . (17)
1654681472.569026 IP 172.34.57.8.55787 > 114.114.114.114.domain: 33954+ NS? . (17)
1654681473.233810 IP 172.34.57.8.39542 > 114.114.114.114.domain: 24956+ AAAA? alauda.cn.localdomain. (39)
1654681473.233819 IP 172.34.57.8.54779 > 114.114.114.114.domain: 64571+ A? alauda.cn.localdomain. (39)
1654681473.361569 IP 172.34.57.8.56071 > 114.114.114.114.domain: 1584+ A? giaoxa.lol.com.localdomain. (45)
1654681473.611310 IP 172.34.57.8.38455 > 114.114.114.114.domain: 27253+ A? alauda.cn.localdomain. (39)
1654681473.611342 IP 172.34.57.8.53131 > 114.114.114.114.domain: 31824+ AAAA? alauda.cn.localdomain. (39)
1654681473.784304 IP 172.34.57.8.48873 > 114.114.114.114.domain: 13483+ NS? . (17)
1654681474.032091 IP 172.34.57.8.39103 > 114.114.114.114.domain: 34671+ NS? . (17)
1654681474.217868 IP 172.34.57.8.37204 > 114.114.114.114.domain: 6801+ AAAA? alauda.cn. (27)
1654681474.217878 IP 172.34.57.8.40697 > 114.114.114.114.domain: 65501+ A? alauda.cn. (27)
1654681475.235208 IP 172.34.57.8.57250 > 114.114.114.114.domain: 48387+ A? alauda.cn.localdomain. (39)
1654681475.235219 IP 172.34.57.8.34787 > 114.114.114.114.domain: 50884+ AAAA? alauda.cn.localdomain. (39)
1654681475.247316 IP 172.34.57.8.52486 > 114.114.114.114.domain: 54567+ NS? . (17)
1654681475.366260 IP 172.34.57.8.38740 > 114.114.114.114.domain: 16503+ PTR? 12.18.34.172.in-addr.arpa. (43)
1654681475.494900 IP 172.34.57.8.49735 > 114.114.114.114.domain: 41610+ NS? . (17)
1654681475.613035 IP 172.34.57.8.54194 > 114.114.114.114.domain: 27016+ AAAA? alauda.cn. (27)
1654681475.613049 IP 172.34.57.8.47105 > 114.114.114.114.domain: 36162+ A? alauda.cn. (27)
1654681476.710241 IP 172.34.57.8.57710 > 114.114.114.114.domain: 24258+ NS? . (17)
1654681476.957868 IP 172.34.57.8.51551 > 114.114.114.114.domain: 14591+ NS? . (17)
1654681477.237061 IP 172.34.57.8.42955 > 114.114.114.114.domain: 13195+ A? alauda.cn. (27)
1654681477.237085 IP 172.34.57.8.42017 > 114.114.114.114.domain: 62057+ AAAA? alauda.cn. (27)
1654681477.368084 IP 172.34.57.8.44143 > 114.114.114.114.domain: 16503+ PTR? 12.18.34.172.in-addr.arpa. (43)

以上日志是从宿主机172.34.57.8 发送到域名解析服务器 114.114.114.114,可以看到都是
172.34.57.8 -> 114.114.114.114, 没有返回。

解决

改ndots

nameserver 11.6.0.10
search my-services.svc.cluster.local svc.cluster.local cluster.local localdomain
options ndots:5

以上是容器内部的 /etc/resolv.conf
ndots:通俗一点说,如果你的域名请求参数中,点的个数比配置的ndots小,则会按照配置的search内容,依次添加相应的后缀直到获取到域名解析后的地址。如果通过添加了search之后还是找不到域名,则会按照一开始请求的域名进行解析。
我们发现在容器抓包的记录中做了以下域名解析:

  1. myfoo.lol.com.my-services.svc.cluster.local
  2. myfoo.lol.com.svc.cluster.local.
  3. myfoo.lol.com.cluster.local.
  4. myfoo.lol.com.localdomain.
  5. myfoo.lol.com.

直到myfoo.lol.com 才解析出来,说明以上1-4都是无用解析。我们更改ndots配置,略过这些解析步骤即可。如下设置ndots

nameserver 11.6.0.10
search my-services.svc.cluster.local svc.cluster.local cluster.local localdomain
options ndots:1
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
1654686042.988636 IP 11.5.0.87.53253 > 11.6.0.10.domain: 27170+ A? giaoxa.lol.com. (33)
1654686042.990862 IP 11.6.0.10.domain > 11.5.0.87.53253: 27170*- 1/0/0 A 172.34.18.12 (64)
1654686042.992319 IP 11.5.0.87.49080 > 11.6.0.10.domain: 15523+ PTR? 12.18.34.172.in-addr.arpa. (43)
1654686042.992980 IP 11.6.0.10.domain > 11.5.0.87.49080: 15523 ServFail- 0/0/0 (43)
1654686042.993054 IP 11.5.0.87.49690 > 11.6.0.10.domain: 15523+ PTR? 12.18.34.172.in-addr.arpa. (43)
1654686042.994753 IP 11.6.0.10.domain > 11.5.0.87.49690: 15523 ServFail- 0/0/0 (43)

以上抓包记录显示是直接从giaoxa.lol.com开始解析的,只会经历一次114.114.114.114超时,就能解析出172.34.18.12

使用全限定域名

最直接,最有效的优化方式,就是使用 “fully qualified name”,简单来说,使用“完全限定域名”(也叫绝对域名),你访问的域名,必须要以 “.” 为后缀,这样就会避免走 search 域进行匹配
也就是说使用 xxx.lol.com.
但是这种办法不符合大家习惯

只在k8s内部进行解析

我们的集群是在私有化环境中,无公网访问,根据上面的抓包和日志可以看出,发送给公网dns解析服务器114.114.114.114的请求都timeout。既然我们不需要公网解析,给ban掉就行。
根据https://coredns.io/plugins/forward/,coredns forward插件控制 coredns 对于接收到的dns解析请求的转发。我们只需要删除掉forward插件就可以让coredns直接按照templates中的配置进行泛域名解析。
K8s容器内部dns解析慢解决方案_第2张图片
这样改动后,不需要再等待向公网域名解析服务器发请求,直接在coredns返回解析结果。

参考

  1. core dns 配置手册 https://coredns.io/manual/toc/#configuration
  2. core dns 插件 forward https://coredns.io/plugins/forward/
  3. core dns 配置说明 https://help.aliyun.com/document_detail/380963.html
  4. core dns 插件 template https://coredns.io/plugins/template/
  5. dns ptr 是什么 https://www.cloudflare.com/learning/dns/dns-records/dns-ptr-record/
  6. dns 解析常见返回 https://bluecatnetworks.com/blog/the-top-four-dns-response-codes-and-what-they-mean/
  7. resolv.conf 中的 search 和 ndots 配置. 使用 nsenter 在容器网络命名空间抓包 https://cloud.tencent.com/developer/article/1669860
  8. k8s dns 配置,策略,解析等 https://hansedong.github.io/2018/11/20/9/
  9. k8s coredns 日志报 i/o timeout https://github.com/kubernetes/kubernetes/issues/86762
  10. 使用HostAliases向 Pod /etc/hosts 文件添加条目

你可能感兴趣的:(ops,k8s,容器,kubernetes,容器,云原生)