关键技术:
- Kubernetes: 分布式的容器编排与调度系统,当前公认的云原生技术基础设施
- CoreDNS: DNS and Service Discovery ,当前公认的云原生基础设施之名字服务系统
- CoreDNS-plugins-loop: CoreDNS loop 插件文档
背景
最近有遇到一个客户集群,发现集群中的 CoreDNS 老是异常(loop 插件检测到有回路后进行 panic),因此怀疑是 K8S 集群在交付或者初始化过程中做了一些额外的动作,为了查明真相我们对客户环境进行一次排查和状况模拟,顺便来一起学习一下在 CoreDNS 中 loop 插件的相关知识。
问题现象
在查看 coredns pod 启动日志时,发现有如下对应异常:
|
|
看到该异常时,第一时间想到的是 客户应该在集群中做了一些 dns 的自定义配置(因为我们交付模版中并没有为 CoreDNS 开启 loop 插件),而配置后又触发了一些冲突,进而导致服务异常。
虽然基本已经确定了是客户自行修改的配置导致的异常,但为何或者具体如何出现的该问题呢?我们继续往下看。
问题排查和处理
其实对于 CoreDNS 这种开源界比较优秀的软件,对异常的处理以及修复都已经做的特别好了,比如上述的日志中已经明显提示,对于这种错误如何进行 troubleshooting 了。
我们跟随官方文档,其实就可以知道,对于相关问题已经说的比较明白,我在这里总结以下几点:
-
- loop 插件的作用:
- 该插件会检测简单转发环路,并且当发现回路时会使服务器
停止
-
- 回路的影响:
- 当 CoreDNS 转发中存在环路时,会不断向自己转发,如此形成死循环,会导致资源无穷占用,最终导致主机 OOM
-
- 为何会导致回路:
- CoreDNS直接将请求转发给自己,比如通过 127.0.0.1, ::1, 或者 127.0.0.53
- CoreDNS将请求转发到上游服务器,后者再将请求转发回 CoreDNS
-
- loop 插件生效的条件:
- 回路必须在 coredns 启动时出现
- 回路必须出现在一个
HINFO
类型的查询
如上四个点,看完之后,基本上就知道为何 coredns 启动失败了,此时查看了 coredns 的配置项并无异常,核心配置如下:
|
|
如上配置可以看到,CoreDNS 的确开启了 loop 插件,并且没有显式声明会讲请求转发到 127.0.0.1
或者 127.0.0.53
之类的本地地址。
但是我们也观察到会将请求转发到 /etc/resolv.conf
,而一般情况下,在 K8S 集群中的 workload 的 dnsPolicy
通常为 Default
,也就是当 CoreDNS pod 调度到哪个节点,将会转发到节点的 /etc/resolv.conf
配置中,因此接下来可以去查看节点的配置。
|
|
此时,对于上面 coredns 异常的原因就已经大概清楚了,就是节点上的 /etc/resolv.conf
配置了 127.0.0.53
。
按照 loop
插件的说法,就是启动了 loop
模块,并成功检测到了回路,那此时,把回路清理掉,应该就可以恢复正常,我们可以尝试把对应节点上的 nameserver 127.0.0.53
删除掉。
|
|
根因和解决方案
目前,客户的问题已经解决,但是客户反馈自己没有修改过节点上的配置,并且依然认为是 K8S 集群交付和初始化方做了动作,希望能够找到节点上的 127.0.0.53
是如何来的。
作为平台方,在新增节点或者交付集群时,的确会进行初始化节点,但对于在 /etc/resolv.conf
中增加 127.0.0.53
是肯定不会做的。
最终通过不断查询相关资料,发现客户用的是 Ubuntu
的操作系统,而在 Ubuntu
的操作系统中,默认会使用到systemd-resolved
进行管理 dns server,并且会设置一个 127.0.0.53
的地址用于本地dns 缓存。
经过测试的确是发现 Ubuntu
的操作系统会增加该 name Server ,到这里也就基本上清楚了,节点上的 127.0.0.53
记录的来源。
那看到这里要如何解决呢?
根据该问题,个人认为会有如下方案可供选择:
-
- CoreDNS 关闭
loop
插件,这也是最粗暴直接的
- CoreDNS 关闭
-
- 继续开启
loop
插件,但是尝试对HINFO
类型的请求做干预
- 继续开启
-
- 手动修改节点上的
/etc/resolv.conf
配置,确保没有nameserver 127.0.0.53
- 手动修改节点上的
-
- 修改 coredns 的亲和性和凡亲和性策略,仅调度到非 Ubuntu 节点
对于如上四种方案,前两者选择对 CoreDNS 的配置进行直接干预,来整体影响 CoreDNS 的功能。
而后两种方案则是通过人工干预集群节点和默认的调度行为。
但是,对于 K8S 集群而言,如果不设置特殊的规则(比如label,affinity,nodeSelector)去影响默认的调度策略,默认是无法根据 OS 信息去影响调度的,并且对于开放的 k8s 集群,也不应该禁止用户使用 Ubuntu 操作系统。
那为了最小化的改动并且能够最大限度支撑现有需求,我们可以选择方案2进行问题的兜底。
我们可以使用如下配置来对HINFO
的请求,强制返回 NXDOMAIN
,如此一来也就不回直接产生 HINFO
的异常请求
|
|
总结
至此,我们也算是找到了问题的根因,并且给出了比较合适的解决方案。
同时,也学习到了 CoreDNS 这种比较优秀的开源软件的设计,针对于一些风险检测的规避和和默认行为,能够忍我们更早的发现系统的风险和问题。