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

相关推荐
GreenMountainEcho6 小时前
Kubernetes 入门篇之 Node 安装与部署
云原生·容器·kubernetes
ghostwritten8 小时前
Rancher Backup
kubernetes·rancher
alden_ygq9 小时前
k8s statefulset pod重启顺序
云原生·容器·kubernetes
ghostwritten9 小时前
k8s黑科技:Linux+Vagrant+VirtualBox开启Kubernetes奇幻之旅
linux·科技·kubernetes
云上艺旅12 小时前
K8S学习之基础七十二:Ingress基于Https代理pod
学习·云原生·容器·https·kubernetes
liux352812 小时前
k8s之Ingress讲解
云原生·容器·kubernetes
小刘爱喇石( ˝ᗢ̈˝ )16 小时前
玛卡巴卡的k8s知识点问答题(六)
云原生·容器·kubernetes
rider18916 小时前
【1】搭建k8s集群系列(二进制部署)之系统初始化
云原生·容器·kubernetes
小刘爱喇石( ˝ᗢ̈˝ )18 小时前
玛卡巴卡的k8s知识点问答题(七)
云原生·容器·kubernetes
小哈里19 小时前
【运维】云计算的发展历程,云原生时代的运维理念&工具技术栈,高可用系统的云运维 —— 以K8S集群调度算法与命令为例
运维·云原生·kubernetes·云计算·架构设计