一步一步排查 K8S 集群 DNS 解析异常

1,757 阅读3分钟

我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第 6 篇文章,点击查看活动详情

知道苹果为什么掉地上比被不被苹果砸到更重要,虽然即便知道了也还可能被苹果砸。

                                      -- 来自张三的觉悟

1. 事件背景

我在 Hugo 动态数据这么玩,嘿嘿一文中解决了业务人员编写 Markdown 的窘境,但在部署上线时发现,只要请求 Hugo 页面,整个服务就会 Crash 掉,分析异常信息得到提示,调用远程接口异常,可我工作电脑访问后端 API 接口返回正常。

通过工具 Attach 到 Pod 中执行 Ping 命令,提示 host unreachable。仔细排查发现,DNS 解析出来的地址竟然是主机网段内的空 IP。病因找到了,DNS 解析异常。

2. 异常分析

kubesphere 集群中 DNS 组件逻辑关系图。看不懂没关系,跟着思路再来回顾即可。

coredns_nodelocaldns.png

2.1 查看 Pod DNS 解析

$ cat /etc/resolv.conf

nameserver 169.254.25.10
search wxwork.svc.alpha.pm.k8s svc.alpha.pm.k8s alpha.pm.k8s
options ndots:5

169.254.25.10Node Local DNS Cache 默认绑定的 DNS 服务地址。 Node Local DNS Cache 在 k8s 集群中以 Daemonset 形式运行,Pods 可以访问在同一节点上运行的 DNS 缓存代理,从而避免 iptables DNAT 规则和连接跟踪,进而大幅度提高集群内部 DNS 解析性能。Daemonset 形式并非高可用架构,所以要注意 Node 节点资源预留。

2.2 查看 NodeLocalDNSCache ConfigMap

apiVersion: v1
data:
  Corefile: |
    alpha.pm.k8s:53 {
        errors
        cache {
            success 9984 30
            denial 9984 5
        }
        reload
        loop
        bind 169.254.25.10
        forward . 10.233.0.3 {  # 如未命中,回源
            force_tcp
        }
        prometheus :9253
        health 169.254.25.10:9254
    }
    in-addr.arpa:53 {
        errors
        cache 30
        reload
        loop
        bind 169.254.25.10
        forward . 10.233.0.3 {  # 如未命中,回源
            force_tcp
        }
        prometheus :9253
    }
    ip6.arpa:53 {
        errors
        cache 30
        reload
        loop
        loop
        bind 169.254.25.10
        forward . 10.233.0.3 {  # 如未命中,回源
            force_tcp
        }
        prometheus :9253
    }
    .:53 {
        errors
        cache 30
        reload
        loop
        bind 169.254.25.10
        forward . 10.233.0.3 {  # 如未命中,回源
          force_tcp
        }
        prometheus :9253
    }
kind: ConfigMap
...   # 此处省略其他字段

从 Corefile 配置可以看到,所有的域名解析,如果未命中缓存,则回源到 10.233.0.3 这个地址解析,而且强制使用 TCP 协议。回源地址正是 CoreDNS 在集群中的 ClusterIP,我们顺藤摸瓜往上追踪。

将 DNS 查询从 UDP 切换 TCP 将减少由于被丢弃的 UDP 包和 DNS 超时而带来的等待时间;这类延时通常长达 30 秒(3 次重试 + 10 秒超时)。

2.3 查看 CoreDNS 配置

apiVersion: v1
data:
  Corefile: |
    .:53 {
        errors
        health {
           lameduck 5s
        }
        ready
        kubernetes alpha.pm.k8s in-addr.arpa ip6.arpa {
           pods insecure
           fallthrough in-addr.arpa ip6.arpa
           ttl 30
        }
        prometheus :9153
        forward . /etc/resolv.conf {
           max_concurrent 1000
        }
        cache 30
        loop
        reload
        loadbalance
    }
    xxx.xxx.xxx:53 {    # 重点在这里
      errors
      cache 30
      forward . xxx.xxx.xxx.xxx
    }
kind: ConfigMap
...   # 此处省略公共信息

在 CoreDNS 配置中发现一段特殊配置,让我想想,这或许是张三不知道啥时候添加的,虽然他打死不承认是他干的。CoreDNS 的回源地址,是个内部早已废弃的 DNS 服务器。虫子抓到了,这虫子还是自己人养的。

总结

排查问题的过程很简单,但其背后涉及的工作原理却很复杂。如果各位对 NodeLocalDNSCache 感兴趣,还可以看看,它是如何避免 Conntrack 5 秒延迟的。相信此时,你已经看懂开篇那副图了,赶紧登录自己的 k8s 集群,看看是不是这么回事儿 !

任何配置的变更,都要有迹可循。关注大飞哥,后续更新 Gitops 系列大课程。