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维护,所有节点的配置按说应该都一样,为什么有些节点的配置不对呢?

相关推荐
刘叨叨趣味运维10 小时前
解剖K8s控制平面(上):API Server与etcd如何成为集群的“大脑“与“记忆“?
平面·kubernetes·etcd
-dcr10 小时前
56.kubernetes弹性伸缩
云原生·容器·kubernetes
Hui Baby10 小时前
K8S联邦负载
java·容器·kubernetes
qq_3129201110 小时前
K8s Ingress实战:七层负载均衡流量治理
容器·kubernetes·负载均衡
海鸥8110 小时前
k8s中Jenkins 配置文件「 更新不了 」
java·kubernetes·jenkins
Cyber4K10 小时前
【Kubernetes专项】K8s 常见持久化存储方案及存储类动态 PV
云原生·容器·kubernetes
噎住佩奇1 天前
k8s-配置管理
云原生·容器·kubernetes
程序媛Dev1 天前
K8s 太重、虚拟机太旧,Sealos 找到了基础架构的最优解
云原生·容器·kubernetes
索荣荣1 天前
Java定时任务与Kubernetes CronJob、AWS EventBridge的集成方案指南
java·开发语言·kubernetes·aws
回忆是昨天里的海1 天前
k8s-部署spring cloud微服务
spring cloud·微服务·kubernetes