侧边栏壁纸
博主头像
VanLiuZhi博主等级

今天也是充满希望的一天!

  • 累计撰写 8 篇文章
  • 累计创建 5 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

K8s 网络调试与DNS解析过慢分析

Administrator
2024-04-06 / 0 评论 / 0 点赞 / 64 阅读 / 26185 字

在k8s中运行 netshoot 进行抓包

busybox 虽然很小,但是命令不全,可以使用 netshoot 来抓包,或者 praqma/network-multitool

补充一张 netshoot 的图:

image-zfeo.png

启动一个临时容器,可以调试整个容器网络

kubectl run --generator=run-pod/v1 tmp-shell --rm -i --tty --image nicolaka/netshoot -- /bin/bash

再开一个 shell: kubectl exec -it tmp-shell -- /bin/bash

或者启动一个临时容器,调试主机网络

kubectl run tmp-shell --generator=run-pod/v1 --rm -i --tty --overrides='{"spec": {"hostNetwork": true}}' --image nicolaka/netshoot -- /bin/bash

执行 tcpdump -nn -i any,再另外一个 shell 中,ping一个可解析的地址,抓包结果如下

bash-5.1# tcpdump -nn -i any
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
05:52:58.482205 eth0  Out IP 10.244.21.244.60478 > 172.16.0.10.53: 32600+ A? eos.h3c.com.default.svc.cluster.local. (55)
05:52:58.482390 eth0  Out IP 10.244.21.244.60478 > 172.16.0.10.53: 32818+ AAAA? eos.h3c.com.default.svc.cluster.local. (55)
05:52:58.483641 eth0  In  IP 172.16.0.10.53 > 10.244.21.244.60478: 32600 NXDomain*- 0/1/0 (148)
05:52:58.483657 eth0  In  IP 172.16.0.10.53 > 10.244.21.244.60478: 32818 NXDomain*- 0/1/0 (148)
05:52:58.483696 eth0  Out IP 10.244.21.244.48575 > 172.16.0.10.53: 28447+ A? eos.h3c.com.svc.cluster.local. (47)
05:52:58.483797 eth0  Out IP 10.244.21.244.48575 > 172.16.0.10.53: 28617+ AAAA? eos.h3c.com.svc.cluster.local. (47)
05:52:58.485032 eth0  In  IP 172.16.0.10.53 > 10.244.21.244.48575: 28447 NXDomain*- 0/1/0 (140)
05:52:58.485044 eth0  In  IP 172.16.0.10.53 > 10.244.21.244.48575: 28617 NXDomain*- 0/1/0 (140)
05:52:58.485078 eth0  Out IP 10.244.21.244.45182 > 172.16.0.10.53: 42126+ A? eos.h3c.com.cluster.local. (43)
05:52:58.485144 eth0  Out IP 10.244.21.244.45182 > 172.16.0.10.53: 42288+ AAAA? eos.h3c.com.cluster.local. (43)
05:52:58.485946 eth0  In  IP 172.16.0.10.53 > 10.244.21.244.45182: 42288 NXDomain*- 0/1/0 (136)
05:52:58.486019 eth0  In  IP 172.16.0.10.53 > 10.244.21.244.45182: 42126 NXDomain*- 0/1/0 (136)
05:52:58.486055 eth0  Out IP 10.244.21.244.58772 > 172.16.0.10.53: 34146+ A? eos.h3c.com. (29)
05:52:58.486119 eth0  Out IP 10.244.21.244.58772 > 172.16.0.10.53: 34350+ AAAA? eos.h3c.com. (29)
05:52:58.488728 eth0  In  IP 172.16.0.10.53 > 10.244.21.244.58772: 34146* 1/0/0 A 10.64.252.13 (56)
05:52:58.488744 eth0  In  IP 172.16.0.10.53 > 10.244.21.244.58772: 34350* 0/1/0 (99)
05:52:58.489020 eth0  Out IP 10.244.21.244 > 10.64.252.13: ICMP echo request, id 38727, seq 1, length 64
05:52:58.490880 eth0  In  IP 10.64.252.13 > 10.244.21.244: ICMP echo reply, id 38727, seq 1, length 64
05:52:58.490951 eth0  Out IP 10.244.21.244.51005 > 172.16.0.10.53: 2157+ PTR? 13.252.64.10.in-addr.arpa. (43)
05:52:58.493904 eth0  In  IP 172.16.0.10.53 > 10.244.21.244.51005: 2157 NXDomain* 0/1/0 (121)
05:53:03.487789 eth0  In  ARP, Request who-has 10.244.21.244 tell 10.244.21.1, length 28
05:53:03.487792 eth0  Out ARP, Request who-has 10.244.21.1 tell 10.244.21.244, length 28
05:53:03.487797 eth0  Out ARP, Reply 10.244.21.244 is-at 82:ba:03:94:44:9b, length 28
05:53:03.487811 eth0  In  ARP, Reply 10.244.21.1 is-at b2:b1:f0:a6:cd:fb, length 28
  1. 首先,系统尝试通过DNS解析eos.h3c.com的IP地址。它向DNS服务器(IP地址为172.16.0.10,端口53)发送了一系列的DNS查询请求,尝试解析eos.h3c.com在不同的Kubernetes域中的地址。这些查询包括:

    • eos.h3c.com.default.svc.cluster.local

    • eos.h3c.com.svc.cluster.local

    • eos.h3c.com.cluster.local

    • eos.h3c.com

    对于每个查询,系统都发送了两个请求:一个是A记录(IPv4地址),另一个是AAAA记录(IPv6地址)。

  2. DNS服务器回复了这些查询,大部分查询返回了NXDomain(表示域名不存在)。但是,对于eos.h3c.com的查询,DNS服务器返回了一个A记录,IP地址为10.64.252.13。

  3. 接下来,系统使用ICMP协议向IP地址10.64.252.13发送了一个echo请求(ping请求)。这是一个用于测试网络连通性的标准操作。

  4. IP地址10.64.252.13回复了一个ICMP echo回复(ping回复),表示网络连通性良好。

  5. 然后,系统尝试通过反向DNS解析(PTR记录)查询IP地址10.64.252.13的主机名。DNS服务器返回了NXDomain,表示没有找到与该IP地址关联的主机名。

  6. 最后,系统与网关(IP地址为10.244.21.1)进行了ARP通信,以获取网关的MAC地址。这是一个正常的网络操作,用于在本地网络中找到目标设备的物理地址。

补充:

1 中测试了很多域名地址,这和搜索域配置有关系。

5 可能不是很理解,RTP是一种通过ip反向查询主机名的解析,我们平时执行很多网络分析命令,可以选择是否显示主机名,就是 RTP 通过反查记录的。

6 最后 ARP获取MAC地址

5,6不一定是必须的,看你网络设置

通过容器 Network Namespace 抓包

  1. 查看指定 pod 运行在哪个宿主机上: kubctl describe pod <pod> -n mservice

  2. 获得容器的 pid: docker inspect -f {{.State.Pid}} <container>

  3. 进入该容器的 network namespace: nsenter --target <PID> -n

  4. 使用宿主机的tcpdump 抓包, 指定 eth0 网卡: tcpdump -i eth0 tcp and port 80 -vvv

  5. 或者直接抓包并导出到文件: tcpdump -i eth0 -w /tmp/out.cap

  6. 从远程 scp 到本地: scp ipaddr:/tmp/out.cap ./

  7. 之后在 Wireshark 中可以打开文件非常直观的查看过滤抓到的数据

k8s DNS 解析过多导致请求慢问题

发现应用程序,如果请求集群外的地址,出现非常慢的情况,就是要等一个2,3秒,很多使用域名做rpc地址的服务都遇到了这个问题,改成svc内部地址就好了,难道是网关太慢?2,3秒可不是慢的问题了,今天通过抓包来详细分析这个问题

这个是dns resolve.conf 配置的问题,pod 可以设置 dns 策略,一般是 dnsPolicy: ClusterFirst

找一个容器,以下是pod内的 resolve.conf 配置:

root@/# cat /etc/resolv.conf
nameserver 172.16.0.10
search eos-system.svc.cluster.local svc.cluster.local cluster.local search h3c.com huawei-3com.com
options ndots:5

nameserver 指定dns解析服务器(nameserver表示解析域名时使用该地址指定的主机为域名服务器。其中域名服务器是按照文件中出现的顺序来查询的,且只有当第一个nameserver没有反应时才查询下面的nameserver,一般不要指定超过3个服务器)

search 是搜索域

option 是配置项,这里配置了 ndots 5

因为k8s默认 ndots 5,所以会生成3个搜索域 eos-system.svc.cluster.local svc.cluster.local cluster.local,然后从主机拿2个 h3c.com huawei-3com.com

此时主机的 cat /etc/resolv.conf 配置为:

search h3c.com huawei-3com.com h3c.huawei-3com.com srv.huawei-3com.com ipa-h3c.com
nameserver 10.72.66.37
nameserver 10.72.66.36

如果我们注释了search:

#search h3c.com huawei-3com.com h3c.huawei-3com.com srv.huawei-3com.com ipa-h3c.com
nameserver 10.72.66.37
nameserver 10.72.66.36

那么容器内部为:

nameserver 172.16.0.10
search eos-system.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

回到正题,现在搜索域如下:

search eos-mid-public.svc.cluster.local svc.cluster.local cluster.local search h3c.com huawei-3com.com
在这个配置下,如果我们请求非k8s内部地址,就会拼接这样的地址去解析dns地址

  • eos.h3c.com.eos-system.svc.cluster.local

  • eos.h3c.com.svc.cluster.local

  • eos.h3c.com.cluster.local

  • eos.h3c.com.h3c.com

  • eos.h3c.com.huawei-3com.com

  • eos.h3c.com

到第六次,终于拿到解析地址了,大家可以抓包验证一下

例子:

给业务容器,加一个 netshoot,进入到 netshoot中执行抓包: kubectl -n eos-mid-public exec -it data-ease-v1-6b68dc7599-9rwm5 -c netshoot -- sh

Search Line limits were exceeded 错误事件

Search Line limits were exceeded, some search paths have been omitted, the applied search line is: eos-system.svc.cluster.local svc.cluster.local cluster.local search h3c.com huawei-3com.com

你会在pod事件在看到这个异常,主要还是搜索域配置问题,下面是比较官方一点的解答:

/etc/resolv.conf文件中,search关键字用于指定一系列的搜索域,这些域会被用于DNS解析没有指定完全限定域名(FQDN)的主机名。如果文件中有多个search行,通常只有最后一个search行会被使用。

在这个例子中,有两个search关键字,每个关键字后面都跟着一些域名。这种写法在语法上是合法的,但实际上,只有最后一个search行(即search h3c.com huawei-3com.com h3c.huawei-3com.com srv.huawei-3com.com ipa-h3c.com)会被使用。

然而,看到的警告信息表明,搜索路径的长度超过了限制,因此一些搜索路径被省略了。这个限制是由Linux系统的DNS解析器强制的,搜索路径的总长度(包括所有的域名和空格)不能超过256个字符,搜索路径中的域名数量不能超过6个。

在这个例子中,搜索路径的长度可能超过了这个限制,因此Kubernetes只保留了前几个域名,并显示了这个警告信息。被省略的域名将不会被用于DNS解析。

如果需要使用被省略的域名进行DNS解析,可能需要调整搜索路径,使其长度不超过限制。例如,可以移除一些不需要的域名,或者将一些域名缩短。请注意,这可能需要修改Kubernetes的DNS配置,或者在创建Pod时指定自定义的DNS策略。

也就是说搜索域太长了,主要还是主机的配置加上k8s自身的配置导致的。另外通过抓包,发现2个search也是有作用的:


tcpdump -nn -i any host 172.16.0.10
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
07:27:48.006823 eth0  Out IP 10.244.38.246.52863 > 172.16.0.10.53: 39793+ A? eos.h3c.com.eos-mid-public.svc.cluster.local. (62)
07:27:48.007042 eth0  Out IP 10.244.38.246.52863 > 172.16.0.10.53: 40184+ AAAA? eos.h3c.com.eos-mid-public.svc.cluster.local. (62)
07:27:48.008818 eth0  In  IP 172.16.0.10.53 > 10.244.38.246.52863: 40184 NXDomain*- 0/1/0 (155)
07:27:48.008830 eth0  In  IP 172.16.0.10.53 > 10.244.38.246.52863: 39793 NXDomain*- 0/1/0 (155)
07:27:48.008867 eth0  Out IP 10.244.38.246.38655 > 172.16.0.10.53: 5074+ A? eos.h3c.com.svc.cluster.local. (47)
07:27:48.009010 eth0  Out IP 10.244.38.246.38655 > 172.16.0.10.53: 5321+ AAAA? eos.h3c.com.svc.cluster.local. (47)
07:27:48.009886 eth0  In  IP 172.16.0.10.53 > 10.244.38.246.38655: 5321 NXDomain*- 0/1/0 (140)
07:27:48.009892 eth0  In  IP 172.16.0.10.53 > 10.244.38.246.38655: 5074 NXDomain*- 0/1/0 (140)
07:27:48.009929 eth0  Out IP 10.244.38.246.49129 > 172.16.0.10.53: 19272+ A? eos.h3c.com.cluster.local. (43)
07:27:48.009994 eth0  Out IP 10.244.38.246.49129 > 172.16.0.10.53: 19552+ AAAA? eos.h3c.com.cluster.local. (43)
07:27:48.010661 eth0  In  IP 172.16.0.10.53 > 10.244.38.246.49129: 19552 NXDomain*- 0/1/0 (136)
07:27:48.010688 eth0  In  IP 172.16.0.10.53 > 10.244.38.246.49129: 19272 NXDomain*- 0/1/0 (136)
07:27:48.010719 eth0  Out IP 10.244.38.246.58992 > 172.16.0.10.53: 25097+ A? eos.h3c.com.search. (36)
07:27:48.010780 eth0  Out IP 10.244.38.246.58992 > 172.16.0.10.53: 25300+ AAAA? eos.h3c.com.search. (36)
07:27:50.014100 eth0  In  IP 172.16.0.10.53 > 10.244.38.246.58992: 25300 NXDomain 0/1/0 (143)
07:27:50.014143 eth0  In  IP 172.16.0.10.53 > 10.244.38.246.58992: 25097 NXDomain 0/1/0 (143)
07:27:50.014200 eth0  Out IP 10.244.38.246.33191 > 172.16.0.10.53: 7012+ A? eos.h3c.com.h3c.com. (37)
07:27:50.014425 eth0  Out IP 10.244.38.246.33191 > 172.16.0.10.53: 7264+ AAAA? eos.h3c.com.h3c.com. (37)
07:27:50.018603 eth0  In  IP 172.16.0.10.53 > 10.244.38.246.33191: 7012 NXDomain* 0/1/0 (107)
07:27:50.018619 eth0  In  IP 172.16.0.10.53 > 10.244.38.246.33191: 7264 NXDomain* 0/1/0 (107)
07:27:50.018666 eth0  Out IP 10.244.38.246.58819 > 172.16.0.10.53: 34729+ A? eos.h3c.com.huawei-3com.com. (45)
07:27:50.018755 eth0  Out IP 10.244.38.246.58819 > 172.16.0.10.53: 34926+ AAAA? eos.h3c.com.huawei-3com.com. (45)
07:27:50.020462 eth0  In  IP 172.16.0.10.53 > 10.244.38.246.58819: 34729 NXDomain* 0/1/0 (147)
07:27:50.021529 eth0  In  IP 172.16.0.10.53 > 10.244.38.246.58819: 34926 NXDomain* 0/1/0 (147)
07:27:50.021571 eth0  Out IP 10.244.38.246.52231 > 172.16.0.10.53: 60607+ A? eos.h3c.com. (29)
07:27:50.021644 eth0  Out IP 10.244.38.246.52231 > 172.16.0.10.53: 60831+ AAAA? eos.h3c.com. (29)
07:27:50.023140 eth0  In  IP 172.16.0.10.53 > 10.244.38.246.52231: 60831* 0/1/0 (99)
07:27:50.024305 eth0  In  IP 172.16.0.10.53 > 10.244.38.246.52231: 60607* 1/0/0 A 10.64.252.13 (56)

其实这个影响特别大,在多次ping 测试中,至少要等待2到3秒以后,才开始响应 ICMP 请求,时间都花在解析域名上了

把刚才那个pod,启动2个实例,然后另外一个实例,注释了主机的搜索域,现在的搜索域配置为

search eos-mid-public.svc.cluster.local svc.cluster.local cluster.local

再次抓包,并且测试ping,发现很快就响应ICMP了,因为少了 h3c.com huawei-3com.com ,这2个不是集群内部的,之前的2到3秒的耗时就是因为拼接解析地址,然后耗时在这2个上

~ #  tcpdump -nn -i any host 172.16.0.10
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
07:32:45.904074 eth0  Out IP 10.244.9.4.37992 > 172.16.0.10.53: 61923+ A? eos.h3c.com.eos-mid-public.svc.cluster.local. (62)
07:32:45.904448 eth0  Out IP 10.244.9.4.37992 > 172.16.0.10.53: 62647+ AAAA? eos.h3c.com.eos-mid-public.svc.cluster.local. (62)
07:32:45.906207 eth0  In  IP 172.16.0.10.53 > 10.244.9.4.37992: 62647 NXDomain*- 0/1/0 (155)
07:32:45.906213 eth0  In  IP 172.16.0.10.53 > 10.244.9.4.37992: 61923 NXDomain*- 0/1/0 (155)
07:32:45.906318 eth0  Out IP 10.244.9.4.44893 > 172.16.0.10.53: 491+ A? eos.h3c.com.svc.cluster.local. (47)
07:32:45.906475 eth0  Out IP 10.244.9.4.44893 > 172.16.0.10.53: 854+ AAAA? eos.h3c.com.svc.cluster.local. (47)
07:32:45.908170 eth0  In  IP 172.16.0.10.53 > 10.244.9.4.44893: 854 NXDomain*- 0/1/0 (140)
07:32:45.908177 eth0  In  IP 172.16.0.10.53 > 10.244.9.4.44893: 491 NXDomain*- 0/1/0 (140)
07:32:45.908284 eth0  Out IP 10.244.9.4.33141 > 172.16.0.10.53: 64130+ A? eos.h3c.com.cluster.local. (43)
07:32:45.908483 eth0  Out IP 10.244.9.4.33141 > 172.16.0.10.53: 64592+ AAAA? eos.h3c.com.cluster.local. (43)
07:32:45.909628 eth0  In  IP 172.16.0.10.53 > 10.244.9.4.33141: 64592 NXDomain*- 0/1/0 (136)
07:32:45.909634 eth0  In  IP 172.16.0.10.53 > 10.244.9.4.33141: 64130 NXDomain*- 0/1/0 (136)
07:32:45.909717 eth0  Out IP 10.244.9.4.58102 > 172.16.0.10.53: 62819+ A? eos.h3c.com. (29)
07:32:45.909894 eth0  Out IP 10.244.9.4.58102 > 172.16.0.10.53: 63062+ AAAA? eos.h3c.com. (29)
07:32:45.913220 eth0  In  IP 172.16.0.10.53 > 10.244.9.4.58102: 63062* 0/1/0 (99)
07:32:45.913460 eth0  In  IP 172.16.0.10.53 > 10.244.9.4.58102: 62819* 1/0/0 A 10.64.252.13 (56)

如果是请求集群内部地址呢?ping 一个 eos-project-blue.eos-system

~ #  tcpdump -nn -i any host 172.16.0.10
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
07:40:13.472584 eth0  Out IP 10.244.9.4.59303 > 172.16.0.10.53: 23490+ A? eos-project-blue.eos-system.eos-mid-public.svc.cluster.local. (78)
07:40:13.472962 eth0  Out IP 10.244.9.4.59303 > 172.16.0.10.53: 24048+ AAAA? eos-project-blue.eos-system.eos-mid-public.svc.cluster.local. (78)
07:40:13.474561 eth0  In  IP 172.16.0.10.53 > 10.244.9.4.59303: 23490 NXDomain*- 0/1/0 (171)
07:40:13.474614 eth0  In  IP 172.16.0.10.53 > 10.244.9.4.59303: 24048 NXDomain*- 0/1/0 (171)
07:40:13.474666 eth0  Out IP 10.244.9.4.46662 > 172.16.0.10.53: 35395+ A? eos-project-blue.eos-system.svc.cluster.local. (63)
07:40:13.475014 eth0  Out IP 10.244.9.4.46662 > 172.16.0.10.53: 35807+ AAAA? eos-project-blue.eos-system.svc.cluster.local. (63)
07:40:13.476326 eth0  In  IP 172.16.0.10.53 > 10.244.9.4.46662: 35807*- 0/1/0 (156)
07:40:13.476331 eth0  In  IP 172.16.0.10.53 > 10.244.9.4.46662: 35395*- 1/0/0 A 172.16.162.110 (124)

由于svc不响应ICMP协议,但是不影响我们测试域名解析,抓包中看到第二次就解析到了

如何解决?

我们搞懂了这个问题的原理,知道是因为主机配置了搜索域,那么根据自己集群网络情况来,这里我们用一个比较简单的办法,调整搜索次数,在yaml中,指定dns配置

spec:
  dnsConfig:
    options:
    - name: ndots
      value: "2"

发布后,新的容器已经启动,配置也变化了,虽然搜索域还是5个,但是 ndots:2 调整了

~ # cat /etc/resolv.conf
nameserver 172.16.0.10
search eos-mid-public.svc.cluster.local svc.cluster.local cluster.local search h3c.com huawei-3com.com
options ndots:2

再次请求抓包,测试了 ping 集群外,和集群内

~ # tcpdump -nn -i any host 172.16.0.10
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
08:04:19.628042 eth0  Out IP 10.244.38.247.38433 > 172.16.0.10.53: 49804+ A? eos.h3c.com. (29)
08:04:19.628242 eth0  Out IP 10.244.38.247.38433 > 172.16.0.10.53: 50094+ AAAA? eos.h3c.com. (29)
08:04:19.629431 eth0  In  IP 172.16.0.10.53 > 10.244.38.247.38433: 49804* 1/0/0 A 10.64.252.13 (56)
08:04:19.629443 eth0  In  IP 172.16.0.10.53 > 10.244.38.247.38433: 50094* 0/1/0 (99)
08:04:19.631592 eth0  Out IP 10.244.38.247.54515 > 172.16.0.10.53: 3396+ PTR? 13.252.64.10.in-addr.arpa. (43)
08:04:19.634487 eth0  In  IP 172.16.0.10.53 > 10.244.38.247.54515: 3396 NXDomain* 0/1/0 (121)
08:04:43.561728 eth0  Out IP 10.244.38.247.33567 > 172.16.0.10.53: 60025+ A? eos-project-blue.eos-system.eos-mid-public.svc.cluster.local. (78)
08:04:43.561911 eth0  Out IP 10.244.38.247.33567 > 172.16.0.10.53: 60442+ AAAA? eos-project-blue.eos-system.eos-mid-public.svc.cluster.local. (78)
08:04:43.564030 eth0  In  IP 172.16.0.10.53 > 10.244.38.247.33567: 60442 NXDomain*- 0/1/0 (171)
08:04:43.564045 eth0  In  IP 172.16.0.10.53 > 10.244.38.247.33567: 60025 NXDomain*- 0/1/0 (171)
08:04:43.564096 eth0  Out IP 10.244.38.247.50751 > 172.16.0.10.53: 16478+ A? eos-project-blue.eos-system.svc.cluster.local. (63)
08:04:43.564181 eth0  Out IP 10.244.38.247.50751 > 172.16.0.10.53: 16886+ AAAA? eos-project-blue.eos-system.svc.cluster.local. (63)
08:04:43.564904 eth0  In  IP 172.16.0.10.53 > 10.244.38.247.50751: 16886*- 0/1/0 (156)
08:04:43.564913 eth0  In  IP 172.16.0.10.53 > 10.244.38.247.50751: 16478*- 1/0/0 A 172.16.162.110 (124)

发现集群外的,直接返回了,这里要特别注意ndots:2 不是说在搜索域中拼接2次的意思。

在进行域名的 DNS 解析时,操作系统先判断其是否是一个 FQDN(Fully qualified domain name,即完整域名,指以 . 结尾的),如果是,则会直接查询 DNS 服务器;如果不是,则就要根据 search 和 ndots 的设置进行 FQDN 的拼接再将其发到 DNS 服务器进行解析。

ndots 表示的是完整域名中必须出现的 . 的个数,如果域名中的 . 的个数不小于 ndots,则该域名会被认为是一个 FQDN,操作系统会直接将其发给 DNS 服务器进行查询;否则,操作系统会在 search 搜索域中依次查询。

例如上面的例子,ndots 为 5,查询的域名 eos.h3c.com 不以 . 结尾,且 . 的个数少于 5,因此操作系统会依次在 default.svc.cluster.local svc.cluster.local cluster.local 三个域中进行搜索,这 3 个搜索域都是由 Kubernetes 注入的。

所以情况就是:

eos-project-blue.eos-system < ndots:2 在搜索域中找,第二个找到

eos.h3c.com > ndots:2,直接请求 eos.h3c.com,不再去搜索域中拼接地址

Kubernetes 为什么要使用搜索域?

目的是为了使 Pod 可以解析内部域名,比如通过 Service name 访问 Service。

例如 default namespace 下的 Pod a 需要访问同 namespace 中的 Service service-b 时,直接使用 service-b 就可以访问了,这就是通过在 default.svc.cluster.local 搜索域中搜索完成的。同理 svc.cluster.local 支持了对不同 namespace 下的 Service 访问,如 service-c.sre(意为 sre namespace 下的 service-c)。

Kubernetes 默认配置下 ndots 的值是 5,其原因官方在 issue 33554 中做了解释:

Kubernetes 需要一个标志来识别集群内的域名,因此 svc 是必须包含在域名内的。

有些人需要配置集群 $zone 的后缀以支持多集群,所以一个完整的 Service 的域名为 $service.$namespace.svc.$zone,为了不在代码中配置完整的域名,就需要设置 ndots 和 search。

同 namespace 下的 Service 的请求是最常用的,因此需要解析 $service,此时需 ndots >= 1,且 search 列表中第一个应为 $namespace.D.$zone。

跨 namespace 的 Service 也经常会被请求,因此需要解析 $service.$namespace,此时需 ndots >= 2,且 search 列表中第二个应为 svc.$zone。

为了解析 $service.$namespace.svc,此时需 ndots >= 3,且 search 列表包含 $zone。

在 Kubernetes 1.4 之前,StatefulSet 为 PetSet,当每个 Pet 被创建时,它会获得一个匹配的 DNS 子域,域格式为 $petname.$service.$namespace.svc.$zone,此时需 ndots >= 4。

Kubernetes 还支持 SRV 记录,因此 _$port.$proto.$service.$namespace.svc.$zone 需要可以解析,此时 ndots = 5。

这就是为什么 ndots 为 5。总结来说是为了支持更复杂的 Pod 内的域名解析,但通常情况下群脉只会用到同 namespace 下的 Service(形如 service-b)和跨 namespace 下 Service(形如 service-c.sre)的访问,因此 ndots 的默认值设为 2 便可满足业务需求并避免大量无效的解析请求。

或者调整配置,之前我们是因为2个不在集群内的地址,解析耗时,可以快速失败,或者修改主机搜索域(一般业务都用不到这个功能,可以改主机搜索域)

options 其他选项的补充说明

  • timeout:设置等待 DNS 服务器返回的超时时间,默认为 5,单位为秒。这个有点高了,为了 fail fast,我们设为了 2。

  • attempt:解析失败时的重试次数,默认为 2。为了提高成功率,我们设为了 3。

  • single-request:默认情况下会并行执行 IPv4 and IPv6 的解析,但某些 DNS 服务器可能无法正确处理这些查询使请求超时。该选项可以禁用此行为,并依次执行 IPv6 and IPv4 的解析。

  • rotate:采用轮询方式访问 nameserver。

  • no-check-names:禁止对传入的主机名和邮件地址进行无效字符检查。

  • use-vc:强制使用 TCP 进行 DNS 解析。

Kubernetes DNS 策略

None

表示空的DNS设置

这种方式一般用于想要自定义 DNS 配置的场景,而且,往往需要和 dnsConfig 配合一起使用达到自定义 DNS 的目的。

Default

有人说 Default 的方式,是使用宿主机的方式,这种说法并不准确。

这种方式,其实是,让 kubelet 来决定使用何种 DNS 策略。而 kubelet 默认的方式,就是使用宿主机的 /etc/resolv.conf(可能这就是有人说使用宿主机的DNS策略的方式吧),但是,kubelet 是可以灵活来配置使用什么文件来进行DNS策略的,我们完全可以使用 kubelet 的参数:–resolv-conf=/etc/resolv.conf 来决定你的DNS解析文件地址。

ClusterFirst

这种方式,表示 POD 内的 DNS 使用集群中配置的 DNS 服务,简单来说,就是使用 Kubernetes 中 kubedns 或 coredns 服务进行域名解析。如果解析不成功,才会使用宿主机的 DNS 配置进行解析。

ClusterFirstWithHostNet

在某些场景下,我们的 POD 是用 HOST 模式启动的(HOST模式,是共享宿主机网络的),一旦用 HOST 模式,表示这个 POD 中的所有容器,都要使用宿主机的 /etc/resolv.conf 配置进行DNS查询,但如果你想使用了 HOST 模式,还继续使用 Kubernetes 的DNS服务,那就将 dnsPolicy 设置为 ClusterFirstWithHostNet。

参考资料:

Kubernetes Pod DNS 解析优化 - 知乎 (zhihu.com)

coredns 原理

域名服务器,本质就是一个key-value记录,在上面的分析中,外部地址在k8s内访问是能解析的,从抓包来看,都是请求到了 coredns。

k8s默认pod的dns策略是 ClusterFirst,也就是指向 coredns 的 svc 地址,全部的域名解析请求都交给 coredns,而 coredns的dns策略是 Default,意思是从所在Node继承DNS服务器,对于无法解析的外部域名,kube-dns会继续向集群外部的dns进行查询,kube-dns只能解析集群内部地址,而集群外部地址应该发给外部DNS服务器进行解析。

所以k8s能否解析外网,一般看coredns主机的配置,或者我们修改一个指定配置,另外在 coredns 的configmap中,还可以添加自定义解析记录,可以根据实际情况,灵活配置

kubectl 插件 sniff 抓包

sniff 是一个集成tcpdump等工具的抓包插件,安装它,首先要先安装krew,一个类似brew的包管理工具

(
  set -x; cd "$(mktemp -d)" &&
  OS="$(uname | tr '[:upper:]' '[:lower:]')" &&
  ARCH="$(uname -m | sed -e 's/x86_64/amd64/' -e 's/\(arm\)\(64\)\?.*/\1\2/' -e 's/aarch64$/arm64/')" &&
  KREW="krew-${OS}_${ARCH}" &&
  curl -fsSLO "http://github.com/kubernetes-sigs/krew/releases/latest/download/${KREW}.tar.gz" &&
  tar zxvf "${KREW}.tar.gz" &&
  ./"${KREW}" install krew
)

根据提示再配置一下环境变量,然后按照 sniff

kubectl krew install sniff

参考资料:

eldadru/ksniff: Kubectl plugin to ease sniffing on kubernetes pods using tcpdump and wireshark (github.com)

一文读懂网络报文分析神器Tshark: 100+张图、100+个示例轻松掌握-腾讯云开发者社区-腾讯云 (tencent.com)

重定向Kubernetes pod中的tcpdump输出 - charlieroro - 博客园 (cnblogs.com)

wireshark远程抓包-CSDN博客

0

评论区