在 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 规则和连接跟踪。本地缓存代理将查询 kube-dns 服务以获取集群主机名(默认情况下为“cluster.local”后缀)的缓存未命中。

动机

  • 使用当前的 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 秒超时))的尾部延迟。由于 nodelocal 缓存侦听 UDP DNS 查询,因此应用程序不需要更改。

  • 指标和对节点级 DNS 请求的可见性。

  • 可以重新启用否定缓存,从而减少对 kube-dns 服务的查询次数。

体系结构图

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

NodeLocal DNSCache flow

Nodelocal DNSCache 流

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

配置

可以使用以下步骤启用此功能

  • 准备类似于示例 nodelocaldns.yaml 的清单,并将其保存为 nodelocaldns.yaml。

  • 如果使用 IPv6,则 CoreDNS 配置文件需要将所有 IPv6 地址括在方括号中,如果它们用于“IP:Port”格式。如果您正在使用上一条中的示例清单,则需要修改 配置行 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 指标都将在每个节点的基础上可用。

您可以通过使用 kubectl delete -f <manifest> 删除 DaemonSet 来禁用此功能。您还应该撤消对 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 对象,因此集群大小或服务/EndpointSlices 的数量不会直接影响内存使用情况。内存使用情况受 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 并测量峰值使用率来确定合适的内存限制。您还可以设置和使用 推荐模式 下的 VerticalPodAutoscaler,然后检查其推荐。

上次修改时间:2023 年 1 月 11 日,太平洋标准时间下午 11:12:更新 /tasks/administer-cluster 部分中的页面权重 (b1202c78ff)