CoreDNS CrashLoopBackOff问题排查之loop detected

背景

今天遇到一个奇怪的问题,集群中有个节点在重启后,调度到该节点上的CoreDNS就一直处于CrashLoopBackOff状态

查看CoreDNS pod的日志有报错

bash 复制代码
CoreDNS-1.9.3
linux/amd64, go1.18.2, 45b0a11
[FATAL] plugin/loop: Loop (127.0.0.1:38718 -> :53) detected for zone ".", see https://coredns.io/plugins/loop#troubleshooting. Query: "HINFO 1602357022762538710.2777015015780658687."

排查流程

1、根据错误日志提供的文档描述,这个报错是在loop插件发现了循环解析的问题,意味着CoreDNS forward给上游的请求还是回到了自身。

2、查看CoreDNS的配置,找到forward的上游是来自/etc/resolv.conf

arduino 复制代码
    .:53 {
                errors
        health {
            lameduck 5s
        }
        ready
        kubernetes cluster.local in-addr.arpa ip6.arpa {
          pods insecure
          fallthrough in-addr.arpa ip6.arpa
        }
        prometheus :9153
        forward . /etc/resolv.conf {
          prefer_udp
          max_concurrent 1000
        }
        cache 30

        loop
        reload
        loadbalance
    }

3、现在我们需要知道容器里面的文件内容/etc/resolv.conf,最简单的方式就是exec到容器里面,但这个pod启动就crash了,没法exec进入容器,那应该如何debug。

常见思路

a、调整容器的启动命令改成sleep 3600,让容器处于运行状态,但coredns是核心组件,这么改服务就烂了,不可取。

b、复制pod的内容,改启动命令,并指定启动节点,这个思路在当前场景下是可行的。

这里我提供另一个思路,因为resolv.conf配置内容是容器创建时生成好再挂载到容器里面,所以在异常节点上是能直接查找容器resolv.conf对应在宿主机上的路径。

查找流程

shell 复制代码
# 先找到异常节点上coredns对应pod的id
$ sudo crictl pods |grep coredns
a70dbd1526493       37 minutes ago      Ready               coredns-676c5c79f-k74zq                              kube-system         0                   (default)
# 解析出resolv.conf在主机上的路径
$ sudo crictl inspectp a70dbd1526493 | jq '.info.runtimeSpec.mounts[] | select(.destination == "/etc/resolv.conf") | .source'
"/var/lib/containerd/io.containerd.grpc.v1.cri/sandboxes/a70dbd15264930d9969a684dbcd0429a4846d747410726859052e710a2930611/resolv.conf"
# 查看内容
$ sudo cat /var/lib/containerd/io.containerd.grpc.v1.cri/sandboxes/a70dbd15264930d9969a684dbcd0429a4846d747410726859052e710a2930611/resolv.conf
search xxxx.com
nameserver 127.0.0.53  ## 这里证实coredns forward的地址确实是本地的
options edns0 trust-ad

对比正常运行的coredns容器, 发现正常节点会forward到其他地址

bash 复制代码
cat /var/lib/containerd/io.containerd.grpc.v1.cri/sandboxes/aef05855960d32e3bc2559cb93fe626a67a18e45b90a12bc19a15a70e6e810a6/resolv.conf
search xxxx.com
nameserver 169.254.25.10
nameserver 8.8.8.8

排查到这里,原因基本清晰了,因为而这个127.0.0.53是本地回环IP,所以coredns forward给这个地址的请求又会回到自身,从而导致循环。

答疑解惑

为什么会出现resolv.conf不一致的内容

对比排查后发现,异常CoreDNS的resolv.conf内容来源和宿主机/etc/resolv.conf内容是相同,而正常的CoreDNS的resolv.conf内容来源和宿主机/run/systemd/resolve/resolv.conf内容是相同。

而控制这个配置来源在kubelet/etc/kubernetes/kubelet-config.yaml配置文件里面

makefile 复制代码
# 异常节点上
clusterDNS:
- 169.254.25.10
resolvConf: "/etc/resolv.conf"
# 正常节点
clusterDNS:
- 169.254.25.10
resolvConf: "/run/systemd/resolve/resolv.conf"

为什么异常节点上的业务pod的dns解析是正常的

根据上面的结论,如果pod没有使用host网络,那dns请求到127.0.0.53会导致pod服务解析域名,但排查过程中发现异常节点上的业务pod是能正常进行域名解析的。 通过查看业务pod容器里面的resolv.conf, 配置内容如下

lua 复制代码
search monitoring.svc.cluster.local svc.cluster.local cluster.local xxxx.com
nameserver 169.254.25.10
options ndots:5

熟悉pod配置的小伙伴应该反应过来了,这是因为pod的dnsPolicy不一样.

CoreDNS配置的是dnsPolicy: Default, 使用的dns配置内容来自kubeletresolvConf

而业务pod的配置是dnsPolicy: ClusterFirst, 对应的配置dns配置内容来自kubeletclusterDNS

修复方案

如果宿主机使用systemd-resolved.service来管理节点的dns解析配置,那kubelet里面配置的resolvConf需要还原为/run/systemd/resolve/resolv.conf,然后delete掉异常的coredns pod后就恢复正常了。

为什么节点kubelet配置会被改错

因为k8s集群的管理是通过kubespray维护,所有节点的配置按说应该都一样,为什么有些节点的配置不对呢?

相关推荐
颜淡慕潇6 小时前
【K8S问题系列 | 9】如何监控集群CPU使用率并设置告警?
后端·云原生·容器·kubernetes·问题解决
运维&陈同学6 小时前
【模块一】kubernetes容器编排进阶实战之k8s基础概念
运维·docker·云原生·容器·kubernetes·云计算
葡萄皮Apple6 小时前
[CKS] K8S RuntimeClass SetUp
java·容器·kubernetes
斯普信专业组15 小时前
Kubernetes网络揭秘:从DNS到核心概念,一站式综述
网络·容器·kubernetes
颜淡慕潇18 小时前
【K8S系列 】在K8S集群怎么查看各个pod占用的资源大小与详细解决方案【已解决】
后端·云原生·容器·kubernetes·问题解决
葡萄皮Apple18 小时前
[CKS] K8S Dockerfile和yaml文件安全检测
安全·容器·kubernetes
管理大亨18 小时前
K8S之Prometheus 部署(二十)
docker·kubernetes·prometheus
颜淡慕潇18 小时前
【K8S问题系列 | 10】在K8S集群怎么查看各个pod占用的资源大小?【已解决】
后端·云原生·容器·kubernetes·问题解决
运维小文18 小时前
K8S资源介绍之configmap
docker·云原生·容器·kubernetes
小安运维日记18 小时前
CKA认证 | Day1 k8s核心概念与集群搭建
运维·云原生·容器·kubernetes·云计算·k8s