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性能瓶颈

相关推荐
grrrr_15 分钟前
【工具类】虚拟机 + Ubuntu 安全部署 OpenClaw,联动 Ollama 零成本解锁云端大模型
linux·运维·ubuntu·#openclaw·#小龙虾
HealthScience5 分钟前
github怎么授权ssh(私人库授权)
运维·ssh·github
HABuo17 分钟前
【linux线程(一)】线程概念、线程控制详细剖析
linux·运维·服务器·c语言·c++·ubuntu·centos
gjc5921 小时前
踩坑实录:MySQL服务器CPU爆高,元凶竟是SELinux的setroubleshootd?
运维·服务器·数据库·mysql·adb
我才是一卓1 小时前
linux 安装简易 git 服务端并使用
linux·运维·git
德彪稳坐倒骑驴1 小时前
MySQL Server 5.5 win端安装,安装SQLyog
运维·服务器
乔宕一2 小时前
windows SSH服务修改SSH登陆后的默认终端
运维·windows·ssh
bwz999@88.com3 小时前
联想SR5507X04安装ubuntu-24.04.4 server,采用 Linux 原生mdadm(mdraid)软 RAID+LVM分区
运维·服务器
Canicer3 小时前
OpenClaw搭配Coze工作流实现全自动发布文章至WordPress网站!
运维·服务器
王小义笔记3 小时前
WSL(Linux)如何安装conda
linux·运维·conda