bigywater.tech
Kubernetes · 70

CoreDNS 与 ndots:一次解析为什么发了五次查询

为什么解析一个域名,CoreDNS 会收到好几次查询?ndots:5 到底改变了什么?末尾加点有用吗?这篇给 CoreDNS 开 log,在 Pod 里用 wget 发出各种写法的访问,把每条请求的名字和结果按时间顺序列出来。

8 条
ndots:5 的 Pod 解析 example.com 发出的 DNS 请求数(4 个名字 × A/AAAA),其中 6 条是 NXDOMAIN
2 条
写成 example.com. 或把 ndots 调到 1 时的请求数
2 → 8+
集群内 Service 的不同写法(s1 → 完整域名)对应的请求数

一个域名为什么 8 次请求

实测 · 本机执行输出
  wget http://example.com(ndots:5):共 8 条 DNS 请求(A 与 AAAA 各算一条),按时间顺序的名字:
    example.com.k64.svc.cluster.local              NXDOMAIN  ×2
    example.com.svc.cluster.local                  NXDOMAIN  ×2
    example.com.cluster.local                      NXDOMAIN  ×2
    example.com                                    NOERROR   ×2
  不同的名字依次是:['example.com.k64.svc.cluster.local', 'example.com.svc.cluster.local', 'example.com.cluster.local', 'example.com'];NXDOMAIN 的有 6 条,最终成功的 2 条

Pod 里的 /etc/resolv.conf 是 search k64.svc.cluster.local svc.cluster.local cluster.local 加 options ndots:5:名字里点数少于 5,就先依次拼上 search 域去查,都失败了才按原名查。example.com 只有 1 个点,所以 CoreDNS 依次收到 example.com.k64.svc.cluster.local、example.com.svc.cluster.local、example.com.cluster.local(都是 NXDOMAIN),最后才是 example.com(NOERROR)。每个名字还有 A 和 AAAA 两条,总共 8 条请求,其中 6 条白查。

让它少查

实测 · 本机执行输出
  wget http://example.com.:共 2 条 DNS 请求(A 与 AAAA 各算一条),按时间顺序的名字:
    example.com                                    NOERROR   ×2
  对比:2 条(带点)

名字末尾加一个点(example.com.)就是绝对域名,不走 search,只有 A 和 AAAA 共 2 条。在 Pod 的 dnsConfig 里把 ndots 调成 1,访问 example.com 同样只有 2 条——点数 1 不小于 ndots 1,先按绝对域名查。

调低 ndots 的副作用

实测 · 本机执行输出
  Pod cli1(dnsConfig ndots:1)访问 example.com:共 2 条 DNS 请求(A 与 AAAA 各算一条),按时间顺序的名字:
    example.com                                    NOERROR   ×2
  Pod cli1(ndots:1)访问集群内的 s1.k64(只有 1 个点,≥ 1):共 6 条 DNS 请求(A 与 AAAA 各算一条),按时间顺序的名字:
    s1.k64                                         NXDOMAIN  ×2
    s1.k64.k64.svc.cluster.local                   NXDOMAIN  ×2
    s1.k64.svc.cluster.local                       NOERROR   ×2

ndots:1 的 Pod 访问集群内的 s1.k64(1 个点)时,会先把 s1.k64 当绝对域名查(NXDOMAIN),再试 s1.k64.k64.svc.cluster.local(NXDOMAIN),最后 s1.k64.svc.cluster.local 才成功,共 6 条请求。ndots 把代价从外部名字转给了集群内的“带命名空间”的短名字,没有免费的午餐。

集群内的不同写法

实测 · 本机执行输出
  cli(ndots:5)访问 s1:共 2 条 DNS 请求(A 与 AAAA 各算一条),按时间顺序的名字:
    s1.k64.svc.cluster.local                       NOERROR   ×2
  cli(ndots:5)访问 s1.k64:共 4 条 DNS 请求(A 与 AAAA 各算一条),按时间顺序的名字:
    s1.k64.k64.svc.cluster.local                   NXDOMAIN  ×2
    s1.k64.svc.cluster.local                       NOERROR   ×2
  cli(ndots:5)访问 s1.k64.svc:共 6 条 DNS 请求(A 与 AAAA 各算一条),按时间顺序的名字:
    s1.k64.svc.k64.svc.cluster.local               NXDOMAIN  ×2
    s1.k64.svc.svc.cluster.local                   NXDOMAIN  ×2
    s1.k64.svc.cluster.local                       NOERROR   ×2
  cli(ndots:5)访问 s1.k64.svc.cluster.local:共 8 条 DNS 请求(A 与 AAAA 各算一条),按时间顺序的名字:
    s1.k64.svc.cluster.local.k64.svc.cluster.local NXDOMAIN  ×2
    s1.k64.svc.cluster.local.svc.cluster.local     NXDOMAIN  ×2
    s1.k64.svc.cluster.local.cluster.local         NXDOMAIN  ×2
    s1.k64.svc.cluster.local                       NOERROR   ×2

ndots:5 的 Pod 访问同一个 Service:s1 只要 2 条(第一个 search 域就命中);s1.k64 要 4 条;s1.k64.svc 要 6 条;写成完整的 s1.k64.svc.cluster.local(3 个点,仍小于 5)反而是 8 条以上,先拼 search 域,失败后才查原名,实测序列后半段还重复了一遍(wget 重试了解析,原因我没有深究)。最省的写法是只写 Service 名,或者在名字后面加点。

分步演示

ndots
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / kind(Docker 里的单节点或多节点真实集群,节点是 Docker Desktop 虚拟机里的容器)/ kubectl;用空的 kubeconfig 之外的独立 kubeconfig,不碰用户自己的集群;计时用 date +%s%N / kubectl 事件时间戳,数字每次运行会有小幅抖动。三节点 kind 集群 kx-main(Kubernetes v1.37.0,CoreDNS 默认两个副本);实验时临时在 Corefile 的 errors 之后加上 log 插件,等两个副本都出现新的 Reloading complete 后再测,结束后已恢复原 Corefile;请求来自 busybox:1.36 的 wget(glibc 的 getaddrinfo),按 CoreDNS 日志时间戳排序,只统计来源 Pod IP 的请求;每种写法各一次
    • 没有验证:musl(Alpine)和 Go 解析器的行为差异(它们对 search 与 ndots 的处理不同);CoreDNS 的 cache 和 autopath 插件对请求数的影响;NodeLocal DNSCache;dnsPolicy 其他取值;dnsConfig 里加 searches 与 single-request;外部域名解析在 NXDOMAIN 之外可能出现的 SERVFAIL 与重试;连接是否真正成功(wget 访问的目标端口是否有后端)
    京ICP备2026067502号-1京公网安备11010502063487号