在 Kubernetes 集群中使用 NodeLocal DNSCache

功能状态: Kubernetes v1.18 [稳定]

本页面提供了 Kubernetes 中 NodeLocal DNSCache 功能的概述。

开始之前

你需要有一个 Kubernetes 集群,并且必须配置 kubectl 命令行工具以与你的集群通信。建议在至少有两个节点的集群上运行本教程,且这些节点不能作为控制平面主机。如果你还没有集群,可以通过 minikube 创建一个,或者使用以下 Kubernetes 演练场之一。

要检查版本,请输入 kubectl version

引言

NodeLocal DNSCache 通过在集群节点上作为 DaemonSet 运行 DNS 缓存代理来提升集群 DNS 性能。在当前的架构中,以“ClusterFirst”DNS 模式运行的 Pod 会向 kube-dns 的 serviceIP 发起 DNS 查询。通过 kube-proxy 添加的 iptables 规则,这些查询会被转换为指向 kube-dns/CoreDNS 的端点。有了这种新架构,Pod 将直接向运行在同一节点上的 DNS 缓存代理发起请求,从而避免了 iptables DNAT 规则和连接跟踪。本地缓存代理会在缓存未命中集群主机名(默认后缀为 "cluster.local")时,向 kube-dns 服务发起查询。

动机

  • 在当前的 DNS 架构下,如果本地没有 kube-dns/CoreDNS 实例,DNS 查询 QPS 最高的 Pod 可能不得不访问其他节点。在这样的场景中,拥有本地缓存将有助于改善延迟。

  • 跳过 iptables DNAT 和连接跟踪将有助于减少 conntrack 竞争,并避免 UDP DNS 条目填满 conntrack 表。

  • 从本地缓存代理到 kube-dns 服务的连接可以升级为 TCP。TCP conntrack 条目会在连接关闭时被删除,而 UDP 条目则必须等待超时(默认 nf_conntrack_udp_timeout 为 30 秒)。

  • 将 DNS 查询从 UDP 升级为 TCP 将减少因丢弃 UDP 数据包和 DNS 超时(通常长达 30 秒:3 次重试 + 10 秒超时)导致的尾部延迟。由于本地节点缓存会监听 UDP DNS 查询,应用程序无需进行任何更改。

  • 节点级别的 DNS 请求监控指标与可视化。

  • 可以重新启用负缓存(Negative Caching),从而减少发往 kube-dns 服务的查询数量。

架构图

这是启用 NodeLocal DNSCache 后 DNS 查询遵循的路径

NodeLocal DNSCache flow

Nodelocal DNSCache 流程

该图显示了 NodeLocal DNSCache 如何处理 DNS 查询。

配置

说明

NodeLocal DNSCache 的本地监听 IP 地址可以是任何能够保证不会与集群中现有 IP 冲突的地址。建议使用具有本地作用域的地址,例如 IPv4 的“链路本地”范围 '169.254.0.0/16',或者 IPv6 的“唯一本地地址”范围 'fd00::/8'。

可以通过以下步骤启用此功能

  • 准备一个类似于 nodelocaldns.yaml 的清单文件,并将其保存为 nodelocaldns.yaml

  • 如果使用 IPv6,CoreDNS 配置文件中所有以“IP:Port”格式使用的 IPv6 地址都需要用方括号括起来。如果您使用上述示例清单,则需要修改 配置文件的第 L70 行,如下所示:“health [__PILLAR__LOCAL__DNS__]:8080

  • 将清单文件中的变量替换为正确的值

    kubedns=`kubectl get svc kube-dns -n kube-system -o jsonpath={.spec.clusterIP}`
    domain=<cluster-domain>
    localdns=<node-local-address>
    

    <cluster-domain> 默认为 "cluster.local"。<node-local-address> 是为 NodeLocal DNSCache 选择的本地监听 IP 地址。

    • 如果 kube-proxy 运行在 IPTABLES 模式下

      sed -i "s/__PILLAR__LOCAL__DNS__/$localdns/g; s/__PILLAR__DNS__DOMAIN__/$domain/g; s/__PILLAR__DNS__SERVER__/$kubedns/g" nodelocaldns.yaml
      

      __PILLAR__CLUSTER__DNS____PILLAR__UPSTREAM__SERVERS__ 将由 node-local-dns Pod 填充。在此模式下,node-local-dns Pod 既监听 kube-dns 服务 IP,也监听 <node-local-address>,因此 Pod 可以使用任一 IP 地址查找 DNS 记录。

    • 如果 kube-proxy 运行在 IPVS 模式下

      sed -i "s/__PILLAR__LOCAL__DNS__/$localdns/g; s/__PILLAR__DNS__DOMAIN__/$domain/g; s/,__PILLAR__DNS__SERVER__//g; s/__PILLAR__CLUSTER__DNS__/$kubedns/g" nodelocaldns.yaml
      

      在此模式下,node-local-dns Pod 仅监听 <node-local-address>node-local-dns 接口无法绑定 kube-dns 集群 IP,因为用于 IPVS 负载均衡的接口已经使用了该地址。__PILLAR__UPSTREAM__SERVERS__ 将由 node-local-dns Pod 填充。

  • 运行 kubectl create -f nodelocaldns.yaml

  • 如果以 IPVS 模式运行 kube-proxy,则需要修改 kubelet 的 --cluster-dns 参数,使其使用 NodeLocal DNSCache 正在监听的 <node-local-address>。否则,无需修改 --cluster-dns 参数的值,因为 NodeLocal DNSCache 同时监听 kube-dns 服务 IP 和 <node-local-address>

启用后,node-local-dns Pod 将在每个集群节点上的 kube-system 命名空间中运行。此 Pod 以缓存模式运行 CoreDNS,因此不同插件暴露的所有 CoreDNS 指标都将以节点为单位提供。

您可以通过删除 DaemonSet(使用 kubectl delete -f <manifest>)来禁用此功能。您还应还原对 kubelet 配置所做的任何更改。

StubDomains 和上游服务器配置

kube-system 命名空间中 kube-dns ConfigMap 指定的 StubDomains 和上游服务器会自动被 node-local-dns Pod 拾取。ConfigMap 内容需要遵循 示例 中所示的格式。node-local-dns ConfigMap 也可以直接使用 Corefile 格式的 stubDomain 配置进行修改。某些云服务提供商可能不允许直接修改 node-local-dns ConfigMap。在这种情况下,可以更新 kube-dns ConfigMap。

设置内存限制

node-local-dns Pod 使用内存来存储缓存条目和处理查询。由于它们不监视 Kubernetes 对象,因此集群规模或 Service / EndpointSlice 的数量不会直接影响内存使用量。内存使用量受 DNS 查询模式影响。根据 CoreDNS 文档

默认缓存大小为 10000 个条目,完全填满时大约占用 30 MB 内存。

这就是每个服务器块的内存占用量(如果缓存完全填满)。通过指定较小的缓存大小可以减少内存使用量。

并发查询数与内存需求有关,因为用于处理查询的每个额外 Goroutine 都需要一定量的内存。您可以使用 forward 插件中的 max_concurrent 选项设置上限。

如果 node-local-dns Pod 尝试使用的内存超过了可用资源(由于系统总资源限制或配置的 资源限制),操作系统可能会关闭该 Pod 的容器。如果发生这种情况,被终止(“OOMKilled”)的容器不会清理它在启动时添加的自定义数据包过滤规则。node-local-dns 容器应该会重启(因为它是由 DaemonSet 管理的),但这会导致每次容器失败时出现短暂的 DNS 停机:数据包过滤规则会将 DNS 查询指向一个不健康的本地 Pod。

您可以通过在不设置限制的情况下运行 node-local-dns Pod 并测量峰值使用量来确定合适的内存限制。您还可以设置并使用处于 推荐模式 (recommender mode)VerticalPodAutoscaler,然后检查其建议值。


最后修改时间:2025 年 1 月 16 日下午 4:14 PST:修复 nodelocaldns.md 中的 md 格式 (2cb6686fc4)