Linux DNS 查询剖析
我将详情容器如何完成 DNS 查询。你想的没错,也不是那么简单。
1) Docker 和 DNS
在 Linux DNS 查询剖析(第三部分)[3] 中,我们详情了 dnsmasq,其工作方式如下:将 DNS 查询指向到 localhost 地址 127.0.0.1,同时启动一个进程监听 53 端口并解决查询请求。
在按上述方式配置 DNS 的主机上,假如运行了一个 Docker 容器,容器内的 /etc/resolv.conf 文件会是怎么的呢?
我们来动手实验一下吧。
按照默认 Docker 创立流程,可以看到如下的默认输出:
- $ docker run ubuntu cat /etc/resolv.conf
- # Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
- # DO NOT EDIT THIS FILE BY HAND — YOUR CHANGES WILL BE OVERWRITTEN
- # 127.0.0.53 is the systemd-resolved stub resolver.
- # run “systemd-resolve –status” to see details about the actual nameservers.
- search home
- nameserver 8.8.8.8
- nameserver 8.8.4.4
奇怪!
地址 8.8.8.8 和 8.8.4.4 从何而来呢?
当我思考容器内的 /etc/resolv.conf 配置时,我的第一反应是继承主机的 /etc/resolv.conf。但只需略微进一步分析,就会发现这样并不总是有效的。
假如在主机上配置了 dnsmasq,那么 /etc/resolv.conf 文件总会指向 127.0.0.1这个回环地址loopback address。假如这个地址被容器继承,容器会在其本身的网络上下文networking context中使用;因为容器内并没有运行(在 127.0.0.1 地址的)DNS 服务器,因而 DNS 查询都会失败。
“有了!”你可能有了新主意:将 主机的 的 IP 地址用作 DNS 服务器地址,其中这个 IP 地址可以从容器的默认路由default route中获取:
- root@79a95170e679:/# ip route
- default via 172.17.0.1 dev eth0
- 172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.2
使用主机 IP 地址真的可行吗?
从默认路由中,我们可以找到主机的 IP 地址 172.17.0.1,进而可以通过手动指定 DNS 服务器的方式进行测试(你也可以升级 /etc/resolv.conf 文件并使用 ping 进行测试;但我觉得这里很适合详情新的 dig 工具及其 @ 参数,后者用于指定需要查询的 DNS 服务器地址):
- root@79a95170e679:/# dig @172.17.0.1 google.com | grep -A1 ANSWER.SECTION
- ;; ANSWER SECTION:
- google.com. 112 IN A 172.217.23.14
但是还有一个问题,这种方式仅适用于主机配置了 dnsmasq 的情况;假如主机没有配置 dnsmasq,主机上并不存在用于查询的 DNS 服务器。
在这个问题上,Docker 的处理方案是忽略所有可能的复杂情况,即无论主机中使用什么 DNS 服务器,容器内都使用 Google 的 DNS 服务器 8.8.8.8 和 8.8.4.4 完成 DNS 查询。
我的经历:在 2013 年,我遇到了使用 Docker 以来的第一个问题,与 Docker 的这种 DNS 处理方案密切相关。我们公司的网络屏蔽了 8.8.8.8 和 8.8.4.4,导致容器无法解析域名。
这就是 Docker 容器的情况,但对于包括 Kubernetes 在内的容器 编排引擎orchestrators,情况又有些不同。
2) Kubernetes 和 DNS
在 Kubernetes 中,最小部署单元是 pod;它是一组相互协作的容器,共享 IP 地址(和其它资源)。
Kubernetes 面临的一个额外的挑战是,将 Kubernetes 服务请求(例如,myservice.kubernetes.io)通过对应的解析器resolver,转发到具体服务地址对应的内网地址private network。这里提到的服务地址被称为归属于“集群域cluster domain”。集群域可由管理员配置,根据配置可以是 cluster.local 或者 myorg.badger 等。
在 Kubernetes 中,你可以为 pod 指定如下四种 pod 内 DNS 查询的方式。
Default
在这种(名称容易让人误会)的方式中,pod 与其所在的主机采用相同的 DNS 查询路径,与前面详情的主机 DNS 查询一致。我们说这种方式的名称容易让人误会,由于该方式并不是默认选项!ClusterFirst 才是默认选项。
假如你希望覆盖 /etc/resolv.conf 中的条目,你可以增加到 kubelet 的配置中。
ClusterFirst
在 ClusterFirst 方式中,遇到 DNS 查询请求会做有选择的转发。根据配置的不同,有以下两种方式:
第一种方式配置相对古老但更简明,即采用一个规则:假如请求的域名不是集群域的子域,那么将其转发到 pod 所在的主机。
第二种方式相对新少量,你可以在内部 DNS 中配置选择性转发。
下面给出示例配置并从 Kubernetes 文档[4]中选取一张图说明流程:
- apiVersion: v1
- kind: ConfigMap
- metadata:
- name: kube-dns
- namespace: kube-system
- data:
- stubDomains: |
- {“acme.local”: [“1.2.3.4”]}
- upstreamNameservers: |
- [“8.8.8.8”, “8.8.4.4”]
在 stubDomains 条目中,可以为特定域名指定特定的 DNS 服务器;而 upstreamNameservers 条目则给出,待查询域名不是集群域子域情况下用到的 DNS 服务器。
这是通过在一个 pod 中运行我们熟知的 dnsmasq 实现的。

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » Linux DNS 查询剖析