追踪 Kubernetes 中的 DNS 查询

追踪 Kubernetes 中的 DNS 查询

在过去的文章中,我们曾 追踪过 Kubernetes 中的网络数据包,这篇文章将追踪 Kubernetes 中的 DNS 查询。

让我们以在 Pod 中解析 Service 完全限定域名(FQDN) foo.bar.svc.cluster.local 为例。

在开始之前,先回顾下 DNS 的解析流程。

DNS 的解析流程

简化版的 DNS 处理流程:

  1. DNS 客户端(如浏览器、应用程序或者设备)发送域名 example.com 的查询请求。
  2. DNS 解析器收到请求,查询本地缓存,如果本地有记录且未过期会返回本地的记录。
  3. 如果本地缓存未命中,DNS 解析器将从 DNS 根服务器开始向下查询,首先是顶级域名(Top Level Domain, TLD) DNS 服务器(这里是 .com),一直向下直到可以解析 example.com 的服务器。
  4. 能够解析 example.com 的服务器成为权威 DNS 名称服务器(Authoritative DNS name server),解析器访问该服务器并收到 IP 地址等相关信息,然后返回给给客户端。解析完成。

从流程来看非常重要的一项配置就是上游 DNS 服务器,该配置位于 Pod 中。这里 Kubernetes 的集群 DNS 服务器正是扮演上游 DNS 服务器的角色,比如 kube-dnsCoreDNS,二者均实现了 Kubernetes 的基于 DNS 的服务发现规范。对 CoreDNS 感兴趣的,可以参考上一篇文章 浅析 CoreDNS 的工作机制

Pod DNS 配置

解析 kubelet 源码 一文中,我们曾分析了 kubelet 创建 pod 的流程。kubelet 创建 pod sandbox 配置时 ,其中重要的一项配置就是准备 pod 的 DNS 配置(Pod 的 DNS 配置由 pod 的 dnsPolicydnsConfig 字段进行操作,这里不展开,下面的部分按照 dnsPolicy=ClusterFirst 情况进行说明)。

配置的内容包括如下三个部分:

  • DNS 服务器 nameserver:来自 kubelet 配置(通常位于 /var/lib/kubelet/config.yaml)的 clusterDNS 字段
  • 搜索域 search:包含四种域:命名空间域、服务域、集群域,以及节点 /etc/resolv.conf 中定义的搜索域。集群域来自 kubelet 配置的 clusterDomain 字段,默认为 cluster.local;命名空间域 NS.svc.cluster.local;服务域 svc.cluster.local
  • 选项 options:默认为 ndots:5

然后 kubelet 调用 CRI 接口创建容器,由 CRI 的实现将 DNS 配置写入到容器文件(默认地址 /etc/resolv.conf)中,如 Containerdpkg/cri/server/sandbox_run_linux.go#L272

我们查看命名空间 default 下某个 pod 的 DNS 配置:

cat /etc/resolv.conf
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10
options ndots:5

这里的 nameserver 正是 Service kube-dns 的 cluster IP 地址,也就是集群的 DNS 服务器,即 dnsPolicy=ClusterFirst 的结果。

search 与 ndots

search 用于指定默认的搜索域。当你在使用不完全限定域名(例如,只提供主机名而没有域名)进行域名解析时,系统会尝试在搜索域中找到匹配的完全限定域名。搜索域按照出现的顺序进行搜索,直到找到匹配的域名或搜索完所有的域名。

ndots 用于指定在进行域名解析时,系统自动添加域名的点号个数阈值。当提供的域名中点号的个数达到或超过这个阈值时,系统会将其视为完全限定域名,而不再使用搜索域进行搜索。默认为 1,这里将其设置为 5

注:ndots 的值大小会影响 DNS 解析的性能,为了获得较好的性能,建议使用 FQDN 进行服务访问,以及将 ndots 改为更小的值。

Pod DNS 解析

当在 Pod 中执行 DNS 解析时,查询请求被发到本地(pod 中)的 DNS 解析器。这个解析器先在缓存中查询,如果未命中,则会根据 /etc/resolv.conf 中的配置,将请求发到上游的 DNS 服务器,即集群 DNS 服务器 10.96.0.10 完成域名解析。

根据前面的介绍,假如我们要解析的域名是 foo.bar,会依次进行如下的查询:

  • foo.bar.default.svc.cluster.local
  • foo.bar.svc.cluster.local(匹配到结果)

当我们使用 foo.barfoo.bar.svc 都可以完成解析,但 foo.bar.svc.cluster 不行,因为追加了搜索域后无法匹配到结果。假如请求方与目标服务在同一个命名空间下,只用 foo 也是可以的。

(转载本站文章请注明作者和出处乱世浮生,请勿用于任何商业用途)

comments powered by Disqus