NodeLocalDNS引起的一个域名解析问题

问题

用户期望在互联网环境中解析域名(以xxx.company.com代替)时得到公网IP;在内网环境中,kubernetes集群的应用中,解析域名时得到的是内网IP。

在coredns的配置文件configmap coredns中添加hosts片段后,发现没有生效,解析到的还是公网IP。已知hosts片段的位置在forward之前,也排除了缓存影响。

排查

排查发现POD中指向的dns地址为节点本地地址:

sh 复制代码
netshoot-node:~# cat /etc/resolv.conf 
nameserver 169.254.20.10
search default.svc.cluster.local svc.cluster.local cluster.local 
options ndots:5

用户使用了 NodeLocalDNS(node-local-dns)可以看作是CoreDNS在节点的本地部署,他们用的配置文件一样,会起到缓存的作用。因此问题的原因是"node-local-dns直接向pod返回了解析结果(解析请求没有到coredns),而这个解析结果是公网IP,是错的"

官网中的示意图:

为什么需要 node-local-dns ?

perl 复制代码
参考自 https://www.lixueduan.com/posts/kubernetes/23-node-local-dns/

处于 ClusterFirst 的 DNS 模式下的 Pod 可以连接到 kube-dns 的 serviceIP 进行 DNS 查询,通过 kube-proxy 组件添加的 iptables 规则将其转换为 CoreDNS 端点,最终请求到 CoreDNS Pod。

通过在每个集群节点上运行 DNS 缓存,NodeLocal DNSCache 可以缩短 DNS 查找的延迟时间、使 DNS 查找时间更加一致,以及减少发送到 kube-dns 的 DNS 查询次数。

在集群中运行 NodeLocal DNSCache 有如下几个好处:

如果本地没有 CoreDNS 实例,则具有最高 DNS QPS 的 Pod 可能必须到另一个节点进行解析,使用 NodeLocal DNSCache 后,拥有本地缓存将有助于改善延迟
跳过 iptables DNAT 和连接跟踪将有助于减少 conntrack 竞争并避免 UDP DNS 条目填满 conntrack 表(上面提到的 5s 超时问题就是这个原因造成的)
从本地缓存代理到 kube-dns 服务的连接可以升级到 TCP,TCP conntrack 条目将在连接关闭时被删除,而 UDP 条目必须超时(默认 nfconntrackudp_timeout 是 30 秒)
将 DNS 查询从 UDP 升级到 TCP 将减少归因于丢弃的 UDP 数据包和 DNS 超时的尾部等待时间,通常长达 30 秒(3 次重试+ 10 秒超时)

node-local-dns和coredns的文件格式和提供方式一样,都是Corefile、Configmap

kubectl -n kube-system edit cm node-local-dns -o yaml,

conf 复制代码
cluster.local:53 {
    errors
    cache {
            success 998430
            denial 9984 5
    }
    reload
    loop
    bind 169.254.20.10
    forward . 172.250.0.2 {
            force_tcp
    }
    prometheus :9253
    health 169.254.20.10:8080
}

...

.:53 {
    errors
    cache 30
    reload
    loop
    bind 169.254.20.10 
    forward . __PILLAR__UPSTREAM__SERVERS__
    prometheus :9253
}
  • bind 169.254.20.10, 在节点上创建了一个虚拟网卡,网卡地址是169.254.20.10;node-cache(node-local-dns的启动程序),它的securityContext.privileged是True,因此监听了169.254.20.10的53端口。
  • forward . 172.250.0.2 这个地址一般是kube-dns的地址(coredns的Service的IP)
  • forward . __PILLAR__UPSTREAM__SERVERS__ 问题在这个占位符。在运行之前,占位符是一定要被替换掉的。

ps发现node-local-dns的启动命令是/node-cache -localip 169.254.20.10 -conf /etc/Corefile -upstreamsvc kube-dns-upstream。集群是通过kubeaz部署的,configmap被挂载到了node-core-dns pod的/etc/coredns/Confile.base, 在运行之前替换占位符,并移动到了/ect/Corefile。

替换的结果是 forward . /etc/resolv.conf。node-local-dns的dnsPolicy是default,因此/etc/resolv.conf正是节点的/etc/resolv.conf.

而节点的/etc/resolv.conf中,有nameserver 223.5.5.5, 阿里的dns服务器。真相大白。

解决:

  1. hosts直接定义在node-local-dns是最直接的解决方式。网上有资料说node-local-dns就是解析集群外的、无法被coredns解析的域名。
  2. 用户的集群规模不大,应用也有连接池,不用node-local-dns也行。不要要注意修改、让pod的/etc/resolv.conf直接指向coredns的Service IP(kube-dns),适当扩容coredns就行了。修改方法在下面dnsPolicy部分。

其他

dnsPolicy

Pod 解析域名时,会使用自身 /etc/resolv.conf 中配置的 nameserver。不同的 dnsPolicy 会决定这个 nameserver 的具体值(是集群 DNS、节点 DNS 还是自定义 DNS)。

dnsPolicy: ClusterFirst(默认)

/etc/resolv.conf 中的 nameserver 一般指向 kube-dns。这个值是由kubelet决定的,可以通过kubelet的启动参数或配置文件修改。

修改kubelet的配置文件:

yaml 复制代码
clusterDNS:
- 169.254.20.10 # node-local-dns
- 172.250.0.2   # kube-dns Service IP

clusterDNS中的顺序和/etc/resolv.conf中的顺序是一致的。nameserver之间是主备关系,不是负载均衡。前面的解析失败采用后面的。

lua 复制代码
netshoot-node:~# cat /etc/resolv.conf 
nameserver 169.254.20.10
nameserver 172.250.0.2
search default.svc.cluster.local svc.cluster.local cluster.local 
options ndots:5

如果不想用node-local-dns, 就在clusterDNS只保留kube-dns的地址。不过要重启应用、慎重。

dnsPolicy: Default

/etc/resolv.conf 中的 nameserver 直接 继承节点的 /etc/resolv.conf

此时可能无法解析集群内部的 Service 或 Pod 域名

dnsPolicy: ClusterFirstWithHostNet

仅用于 hostNetwork: true** 的 Pod(共享节点网络命名空间)

/etc/resolv.conf 中的 nameserver 仍指向集群 DNS,但解析逻辑与 ClusterFirst 类似:内部域名用集群 DNS,外部域名转发到节点 DNS。

dnsPolicy: None + 自定义 dnsConfig

/etc/resolv.conf 中的 nameserver 由用户通过 dnsConfig.nameservers 显式指定(可自定义为任意 DNS 服务器,包括节点 DNS、外部 DNS 等)。

参考:

集群DNS性能瓶颈

相关推荐
超越自己3 小时前
远程连接银河麒麟服务器-xrdp方式
linux·运维·服务器·远程桌面·银河麒麟
sakoba3 小时前
Linux上kafka部署和使用
linux·运维·kafka
lxmyzzs4 小时前
在使用 `resolvconf` 的 Ubuntu 系统上持久化 DNS 设置
linux·运维·ubuntu
熊文豪4 小时前
搭建AI资讯早报:AiOnly全球大模型服务+N8N自动化工作流实战
linux·运维·服务器
wanhengidc5 小时前
云真机和云手机的区别
运维·服务器·游戏·智能手机·云计算
佐杰6 小时前
Jenkins是什么
运维·jenkins
zzzsde6 小时前
【Linux】权限(1):初识权限与使用理解
linux·运维·服务器
正在走向自律7 小时前
影刀RPA完全指南:从零入门到自动化高手(2/10)
运维·人工智能·自动化·rpa·影刀·rpa自动化工具·ai结合影刀
乌萨奇也要立志学C++7 小时前
【Linux】进程间通信(一)匿名管道原理剖析与进程池手动实现全流程
linux·运维·服务器