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

相关推荐
缘的猿2 小时前
云计算划分标准与Kubernetes NetworkPolicy深度解析
容器·kubernetes·云计算
matlab的学徒3 小时前
Kubernetes(K8S)全面解析:核心概念、架构与实践指南
linux·容器·架构·kubernetes
没有口袋啦4 小时前
K8s集群多节点部署(Ubuntu22.04)
docker·云原生·容器·kubernetes
荣光波比5 小时前
K8S(三)—— 基于kubeadm 1.20版本部署Kubernetes集群与Harbor私有仓库实战
云原生·容器·kubernetes
荣光波比5 小时前
K8S(二)—— K8S 1.28 集群部署指南(kubeadm 方式)
云原生·容器·kubernetes
问道飞鱼6 小时前
【Kubernets进阶】Kubernetes VPA (Vertical Pod Autoscaler) 详解与配置指南
云原生·容器·kubernetes·vpa
荣光波比1 天前
K8S(一)—— 云原生与Kubernetes(K8S)从入门到实践:基础概念与操作全解析
云原生·容器·kubernetes
伞啊伞1 天前
K8s概念基础(一)
云原生·容器·kubernetes
hello_2501 天前
k8s基础监控promql
云原生·容器·kubernetes
静谧之心1 天前
在 K8s 上可靠运行 PD 分离推理:RBG 的设计与实现
云原生·容器·golang·kubernetes·开源·pd分离