4.4 Node本地DNS缓存

由于在Kubernetes集群中配置的DNS服务是一个名为“kube-dns”的Service,所以容器应用都通过其ClusterIP地址(例如169.169.0.100)去执行服务名的DNS域名解析。这对于大规模集群可能引起以下两个问题。

(1)集群DNS服务压力增大(这可以通过自动扩容缓解)。

(2)由于DNS服务的IP地址是Service的ClusterIP地址,所以会通过kube-proxy设置的iptables规则进行转发,可能导致域名解析性能很差,原因是Netfilter在做DNAT转换时可能会引起conntrack冲突,从而导致DNS查询产生5s的延时。

为了解决这两个问题,Kubernetes引入了Node本地DNS缓存(NodeLocal DNSCache)来提高整个集群的DNS域名解析的性能,这在1.18版本时达到Stable阶段。使用Node本地DNS缓存的好处如下。

◎ 在没有本地DNS缓存时,集群DNS服务的Pod很可能在其他节点上,跨主机访问会增加网络延时,使用Node本地DNS缓存可显著减少跨主机查询的网络延时。

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

◎ 本地缓存到集群DNS服务的连接协议可以升级为TCP。TCP conntrack条目将在连接关闭时被删除;默认使用UDP时,conntrack条目只能等到超时时间过后才被删除,操作系统的默认超时时间(nf_conntrack_udp_timeout)为30s。

◎ 将DNS查询从UDP升级为TCP,将减少由于丢弃的UDP数据包和DNS超时而引起的尾部延迟(tail latency),UDP超时时间可能会长达30s(3次重试,每次10s)。

◎ 提供Node级别DNS解析请求的度量(Metrics)和可见性(visibility)。

◎ 可以重新启用负缓存(Negative caching)功能,减少对集群DNS服务的查询数量。

Node本地DNS缓存(NodeLocal DNSCache)的工作流程如图4.6所示,客户端Pod首先会通过本地DNS缓存进行域名解析,当缓存中不存在域名时,会将请求转发到集群DNS服务进行解析。

图4.6 Node本地DNS缓存的工作流程

下面对如何部署Node本地DNS缓存工具进行说明。

配置文件nodelocaldns.yaml的内容如下,主要包括ServiceAccount、Daemonset、ConfigMap和Service几个资源对象。

Service Account的定义如下:

Service的定义如下:

ConfigMap的定义如下:

DaemonSet的定义如下:

ConfigMap Corefile的主要配置参数如下。

◎ bind 169.254.20.10:node-local-dns需要绑定的本地IP地址,建议将其设置为169.254.0.0/16范围,确保不与集群内的其他IP冲突。

◎ forward .169.169.0.100:在node-local-dns缓存中不存在域名记录时,将转发到的上游DNS服务器IP设置为Kubernetes集群DNS服务(kube-dns)的IP,例如169.169.0.100。

◎ health 169.254.20.10:8081:健康检查端口号设置,与Daemonset的livenessProbe一致,需要注意,node-local-dns网络模式设置了hostNetwork=true,这个端口号也会被直接绑定到宿主机上,需要确保不与宿主机的其他应用冲突。

Daemonset node-local-dns的主要配置参数如下。

◎ args:["-localip","169.254.20.10","-conf","/etc/Corefile","-upstreamsvc","kube-dns-upstream"]:将-localip参数设置为node-local-dns绑定的本地IP地址,对其他参数无须修改。

◎ livenessProbe中的健康检查端口号与ConfigMap中的一致。

另外,如果kube-proxy代理模式(--proxy-mode)使用的是ipvs模式,则还需要修改kubelet的启动参数--cluster-dns为node-local-dns绑定的本地IP地址169.254.20.10。

通过kubectl create命令创建node-local-dns服务:

确认在每个Node上都运行了一个node-local-dns Pod:

在客户端Pod内对服务名的解析没有变化,仍然可以直接通过服务名访问其他服务,例如: