2. Kubernetes DNS 架构基础:CoreDNS 工作原理、Pod DNS 解析流程、kubelet DNS 缓存机制

在深入排查证书轮换引发的 DNS 故障之前,必须首先理解 Kubernetes 集群内 DNS 的完整工作链路。本章将拆解三个核心组件:CoreDNS(集群 DNS 服务端)、Pod DNS 解析流程(客户端请求路径)以及 kubelet DNS 缓存机制(节点级缓存策略)。这三者构成了 Pod 访问 Service 名称或外部域名的全部依赖链。

2.1 CoreDNS 工作原理

CoreDNS 是 Kubernetes 1.13 及之后版本的默认集群 DNS 组件,以 Deployment 形式运行在 kube-system 命名空间下,通常由两个副本构成高可用。其核心架构基于插件链(Plugin Chain),每个 DNS 查询请求会依次经过多个插件处理。

关键设计点: CoreDNS 并非传统 DNS 服务器(如 BIND),它通过 Corefile 配置插件栈,每个插件负责一个独立功能(如 Kubernetes 服务发现、缓存、转发、健康检查)。
CoreDNS 插件链与 DNS 查询处理流程 DNS 查询入站 whoami (日志/审计) kubernetes (Service 解析) cache (TTL 缓存) forward (外部 DNS) DNS 响应出站 插件链执行顺序由 Corefile 定义,常见生产配置顺序: 1. whoami(记录查询来源) → 2. kubernetes(集群内 Service/Pod 解析) → 3. cache(降低上游压力) → 4. forward(未匹配域名转发至上游 DNS) 注意:如果 kubernetes 插件返回 NXDOMAIN,cache 和 forward 插件仍会处理;如果返回 SERVFAIL,则直接返回错误。

CoreDNS 的 kubernetes 插件负责将 Service 名称解析为 Cluster IP。它支持三种查询类型:

  • Service 查询:my-svc.my-namespace.svc.cluster.local → Cluster IP
  • Pod 查询:10-244-1-5.my-namespace.pod.cluster.local → Pod IP
  • ExternalName 查询:返回 CNAME 记录
排查要点: 证书轮换期间,如果 CoreDNS Pod 因资源争抢被 OOMKill 或重启,kubernetes 插件将无法响应查询。此时应检查 CoreDNS 的 whoami 插件日志,确认请求是否到达插件链。

2.2 Pod DNS 解析流程

每个 Pod 内的 DNS 解析行为由 /etc/resolv.conf 控制,该文件由 kubelet 在 Pod 启动时注入。解析流程遵循标准的 ndots 规则和 search 域 列表。

配置项 默认值 说明
nameserver 10.96.0.10(Cluster IP of kube-dns) Pod 发送 DNS 查询的目标地址
search <ns>.svc.cluster.local svc.cluster.local cluster.local 自动追加的域名后缀列表
ndots 5 域名中点数少于该值时,优先尝试 search 域
timeout 5 单次查询超时时间(秒)
attempts 2 查询失败后的重试次数

当 Pod 内应用执行 curl http://my-svc 时,glibc 解析器会按以下顺序尝试:

  1. 检查 my-svc 是否包含足够多的点(.)。由于默认 ndots=5,而 my-svc 只有 0 个点,因此优先拼接 search 域。
  2. 依次查询 my-svc.<ns>.svc.cluster.local、my-svc.svc.cluster.local、my-svc.cluster.local。
  3. 如果所有 search 域查询均返回 NXDOMAIN,最后查询 my-svc(域名形式)。
  4. 每次查询都发送 UDP 请求到 10.96.0.10:53(CoreDNS Service IP)。
常见陷阱: 当 ndots 值较大时(如默认 5),短域名(如 my-svc)会触发最多 4 次 DNS 查询(3 次 search 域 + 1 次域名)。如果 CoreDNS 响应缓慢或丢包,应用层会感受到明显的延迟累积。证书轮换期间,kubelet 资源争抢可能加剧这一延迟。
Pod DNS 解析流程(ndots=5, search 域示例) 应用:curl http://my-svc glibc 解析器(ndots 检查) 查询顺序(按 search 域依次尝试,直到收到非 NXDOMAIN 响应) ① my-svc.default.svc.cluster.local → ② my-svc.svc.cluster.local ③ my-svc.cluster.local → ④ my-svc(域名,无 search 域拼接) 每次查询均发送 UDP 到 10.96.0.10:53;超时或失败则按 attempts 重试。 CoreDNS(10.96.0.10:53)

2.3 kubelet DNS 缓存机制

kubelet 在节点上运行一个 本地 DNS 缓存(通常以 node-cache 或 kube-dns 缓存形式部署),其核心目的是减少对 CoreDNS 的直接压力,并降低 DNS 查询延迟。在证书轮换场景下,kubelet 的资源争抢可能直接影响缓存进程的健康状态。

Kubernetes 社区推荐的 NodeLocal DNSCache 架构在节点上以 DaemonSet 形式运行一个缓存代理,监听 169.254.20.10:53(或类似链路本地地址),Pod 的 resolv.conf 中的 nameserver 被修改为指向该缓存地址。

缓存模式 部署方式 缓存位置 对 CoreDNS 的影响
无缓存(默认) Pod 直接请求 CoreDNS Cluster IP 无 CoreDNS 承受全部查询压力
NodeLocal DNSCache DaemonSet + iptables/IPVS 重定向 节点本地(内存) 缓存命中时 CoreDNS 零负载;未命中时转发
kubelet 内置缓存(实验性) kubelet 启动参数 --dns-cache-ttl kubelet 进程内存 仅缓存 kubelet 自身发起的 DNS 查询
证书轮换关联: 当 kubelet 因证书轮换触发大量并发操作(如重新创建 Pod、更新 Secret 挂载),其 CPU 和内存使用率会飙升。如果 NodeLocal DNSCache 与 kubelet 共享同一 cgroup 资源池,缓存进程可能因资源争抢而延迟响应或 OOM 退出,导致 Pod 的 DNS 查询直接穿透到 CoreDNS,形成“缓存雪崩”。

NodeLocal DNSCache 的典型工作流程如下:

  1. Pod 发起 DNS 查询,目标为 169.254.20.10:53(链路本地地址)。
  2. 节点上的 node-cache 进程检查本地缓存:
    • 缓存命中:直接返回响应,TTL 剩余时间递减。
    • 缓存未命中:向上游 CoreDNS(10.96.0.10:53)发起查询,缓存结果后返回。
  3. 缓存条目遵循 TTL 过期策略,默认与上游 DNS 响应中的 TTL 一致。
排查建议: 在证书轮换故障期间,检查节点上 node-cache 的指标(如 dns_cache_hits_total、dns_cache_misses_total)。如果命中率突然下降且 CoreDNS 负载飙升,说明缓存层可能已失效。同时检查 kubelet 的 --dns-cache-ttl 参数是否被意外覆盖。