在过去的文章中,我们曾 追踪过 Kubernetes 中的网络数据包[1],这篇文章将追踪 Kubernetes 中的 DNS 查询。
让我们以在 Pod 中解析 Service 完全限定域名(FQDN) foo.bar.svc.cluster.local
为例。
在开始之前,先回顾下 DNS 的解析流程。
DNS 的解析流程
简化版的 DNS 处理流程:
DNS 客户端(如浏览器、应用程序或者设备)发送域名 example.com
的查询请求。DNS 解析器收到请求,查询本地缓存,如果本地有记录且未过期会返回本地的记录。 如果本地缓存未命中,DNS 解析器将从 DNS 根服务器开始向下查询,首先是顶级域名(Top Level Domain, TLD) DNS 服务器(这里是 .com
),一直向下直到可以解析example.com
的服务器。能够解析 example.com
的服务器成为权威 DNS 名称服务器(Authoritative DNS name server),解析器访问该服务器并收到 IP 地址等相关信息,然后返回给给客户端。解析完成。
从流程来看非常重要的一项配置就是上游 DNS 服务器,该配置位于 Pod 中。这里 Kubernetes 的集群 DNS 服务器正是扮演上游 DNS 服务器的角色,比如 kube-dns[2]、CoreDNS[3],二者均实现了 Kubernetes 的基于 DNS 的服务发现规范[4]。对 CoreDNS 感兴趣的,可以参考上一篇文章 浅析 CoreDNS 的工作机制[5]。
Pod DNS 配置
在 解析 kubelet 源码[6] 一文中,我们曾分析了 kubelet 创建 pod 的流程。kubelet 创建 pod sandbox 配置时[7] ,其中重要的一项配置就是准备 pod 的 DNS 配置[8](Pod 的 DNS 配置由 pod 的 dnsPolicy
和 dnsConfig
字段进行操作,这里不展开,下面的部分按照 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
)中,如 Containerd[9] 的 pkg/cri/server/sandbox_run_linux.go#L272[10]。
我们查看命名空间 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.bar
、foo.bar.svc
都可以完成解析,但 foo.bar.svc.cluster
不行,因为追加了搜索域后无法匹配到结果。假如请求方与目标服务在同一个命名空间下,只用 foo
也是可以的。
参考资料
追踪过 Kubernetes 中的网络数据包: https://atbug.com/tracing-network-packets-in-kubernetes/
[2]kube-dns: https://github.com/kubernetes/dns
[3]CoreDNS: https://coredns.io
[4]Kubernetes 的基于 DNS 的服务发现规范: https://github.com/kubernetes/dns/blob/master/docs/specification.md
[5]浅析 CoreDNS 的工作机制: https://atbug.com/analysis-of-the-working-mechanism-of-coredns/
[6]解析 kubelet 源码: https://atbug.com/how-kubelete-container-runtime-work-with-cni/#创建-pod
[7]创建 pod sandbox 配置时: https://github.com/kubernetes/kubernetes/blob/release-1.24/pkg/kubelet/kuberuntime/kuberuntime_manager.go#L861
[8]pod 的 DNS 配置: https://github.com/kubernetes/kubernetes/blob/release-1.24/pkg/kubelet/kuberuntime/kuberuntime_sandbox.go#L93
[9]Containerd: https://github.com/containerd/containerd
[10]pkg/cri/server/sandbox_run_linux.go#L272: https://github.com/containerd/containerd/blob/a05d175400b1145e5e6a735a6710579d181e7fb0/pkg/cri/server/sandbox_run_linux.go#L272
《Docker中Image、Container与Volume的迁移》
免责声明:本文内容来源于网络,所载内容仅供参考。转载仅为学习和交流之目的,如无意中侵犯您的合法权益,请及时联系Docker中文社区!
温馨提示:文章内容系作者个人观点,不代表Docker中文社区对观点赞同或支持。
版权声明:本文为转载文章,来源于 张晓辉 ,版权归原作者所有,欢迎分享本文,转载请保留出处!
发表评论