Skip to content

K8s 集群 CoreDNS 解析故障分析报告


快速参考

故障特征: Pod 访问 Service 域名失败,但 IP 直连正常
根本原因: hosts 插件 fallthrough 配置限制 zone,拦截正向域名
修复方案: 将 fallthrough in-addr.arpa ip6.arpa 改为 fallthrough .

官方文档参考:


一、故障概述

1.1 故障背景

K8s 集群版本为 1.16.5,核心 DNS 服务依赖 CoreDNS 提供。本次故障源于 hosts 插件中 fallthrough in-addr.arpa ip6.arpa 配置项的错误使用,导致集群网络异常。

故障现象:

  1. Pod 内访问 Service 域名(如 kubernetes.default.svc.cluster.local)失败,但直接访问 IP 地址可正常通信
  2. CoreDNS 的 hosts 无解析时,集群网络可通讯
  3. 将 hosts 插件的 fallthrough in-addr.arpa ip6.arpa 修改为 fallthroughfallthrough . 后,集群网络可恢复正常

1.2 核心疑问

为何 hosts 插件配置 fallthrough in-addr.arpa ip6.arpa 会导致集群内网络问题?修改为无限制的 fallthrough 后又能恢复?本文将深入分析故障根因。


二、CoreDNS 核心原理铺垫

2.1 CoreDNS 的插件化架构

CoreDNS 是 K8s 集群默认的 DNS 服务,其核心能力由插件链实现。所有 DNS 解析请求会按 Corefile 配置的从上到下的书写顺序,依次经过不同插件处理,每个插件负责一类特定功能。

插件分类说明:

分类作用典型插件
核心插件处理 DNS 查询的核心逻辑,包括服务发现、转发、静态映射等kubernetes、hosts、forward
辅助插件提供非业务逻辑功能,如日志、监控、健康检查、缓存等errors、prometheus、health、cache
扩展插件增强 DNS 处理能力,如域名重写、负载均衡、访问控制等rewrite、loadbalance、acl

集群核心插件执行逻辑:

插件名称核心功能终止逻辑
kubernetes对接 K8s APIServer,实时同步 SVC/Endpoint 数据,处理集群内域名解析解析成功则返回结果并终止链;解析失败则触发 fallthrough 判断
hosts加载自定义静态域名-IP 映射,类似系统 hosts 文件匹配到域名则直接返回结果并终止链;无匹配则触发 fallthrough 判断
forward将无法解析的请求转发到上游 DNS 服务器,如 /etc/resolv.conf 配置的 DNS无论成功或失败,均返回结果并终止链
cache缓存解析结果,提升解析效率不独立终止链,配合其他插件工作
errors输出解析错误日志,便于排查不独立终止链,配合其他插件工作

2.2 fallthrough 的本质:插件链的接力开关

fallthrough 不是独立插件,而是 hosts/kubernetes 等插件的配置参数。其核心作用是:当当前插件无法解析请求的域名(返回 NXDOMAIN,即域名不存在)时,决定是否将请求传递给下一个插件继续处理。

fallthrough 的三种配置形式及效果:

配置形式作用范围效果说明
无 fallthrough当前插件直接返回解析失败,整个插件链终止
fallthrough zone1 zone2指定域名范围,如 in-addr.arpa ip6.arpa仅当请求域名属于指定 zone 时,才传递给下一个插件;否则返回失败并终止链
fallthrough 或 fallthrough .所有域名(. 代表根域)不限制范围,所有解析失败的请求都传递给下一个插件

三、故障根因深度解析

3.1 故障配置与正常配置对比

故障配置示例:

yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system
data:
  Corefile: |
    .:53 {
      errors
      health
      kubernetes cluster.local in-addr.arpa ip6.arpa {
        pods insecure
        fallthrough in-addr.arpa ip6.arpa
      }
      # 故障核心:hosts插件的fallthrough限制zone
      hosts {
        192.168.1.100 custom-service.example.com
        192.168.1.101 api-server.example.com
        fallthrough in-addr.arpa ip6.arpa  # 错误配置:仅允许反向解析域名接力
      }
      prometheus :9153
      forward . /etc/resolv.conf
      cache 30
      loop
      reload
      loadbalance
    }

正常配置示例:

yaml
hosts {
  192.168.1.100 custom-service.example.com
  192.168.1.101 api-server.example.com
  fallthrough .  # 正确配置:允许所有解析域名接力
}

3.2 故障触发的完整链路分析

以 Pod 解析 kubernetes.default.svc.cluster.local(集群正向 SVC 域名)为例,分析故障配置下的请求处理流程:

故障配置下的请求链路:

Step 1: Pod 发起 DNS 请求
        请求域名: kubernetes.default.svc.cluster.local
        
Step 2: kubernetes 插件处理
        该插件负责处理 cluster.local 域名
        由于配置了 fallthrough in-addr.arpa ip6.arpa
        正向域名不属于 fallthrough 范围,但 kubernetes 插件本身会处理 cluster.local
        
Step 3: 假设请求先到达 hosts 插件(实际取决于 Corefile 配置顺序)
        hosts 插件无匹配条目
        检查 fallthrough 配置: in-addr.arpa ip6.arpa
        正向域名 kubernetes.default.svc.cluster.local 不属于这两个 zone
        请求被拦截,链路终止
        结果: 解析失败

正常配置下的请求链路:

Step 1: Pod 发起 DNS 请求
        请求域名: kubernetes.default.svc.cluster.local
        
Step 2: 请求到达 hosts 插件
        hosts 插件无匹配条目
        fallthrough . 允许所有域名接力
        请求传递给下一个插件
        
Step 3: kubernetes 插件处理
        成功解析 cluster.local 域名
        返回解析结果
        结果: 解析成功

3.3 关键验证点(可复现故障)

通过以下测试可以验证故障原因:

测试场景测试域名解析结果原因分析
故障配置kubernetes.default.svc.cluster.local(正向 SVC)失败hosts 插件拦截,未传递给 kubernetes 插件
故障配置10.96.0.10.in-addr.arpa(反向解析)成功符合 fallthrough 的 zone 范围,请求传递给 kubernetes 插件
清空 hostskubernetes.default.svc.cluster.local(正向 SVC)成功hosts 插件跳过,请求到达 forward 插件
正常配置my-service.example.com(自定义域名)成功hosts 插件匹配到条目,优先返回
正常配置kubernetes.default.svc.cluster.local(正向 SVC)成功hosts 插件未匹配,传递给 kubernetes 插件

四、故障排查决策树

当遇到 Pod 域名解析问题时,按以下步骤排查:

Pod 域名解析失败
       |
       v
+------------------+
| IP 直连是否正常? |
+------------------+
       |
       +-- 否 --> 检查网络连通性 (CNI/防火墙/路由)
       |
       +-- 是 --> 继续排查 DNS
                    |
                    v
           +---------------------+
           | 解析外部域名是否正常? |
           +---------------------+
                    |
                    +-- 否 --> 检查 forward 插件配置
                    |
                    +-- 是 --> 问题在集群内域名解析
                               |
                               v
                      +----------------------+
                      | 检查 CoreDNS Pod 状态 |
                      +----------------------+
                               |
                               v
                      +---------------------------+
                      | kubectl logs 查看 DNS 日志 |
                      +---------------------------+
                               |
                               v
                      +-------------------------------+
                      | 检查 Corefile 中 fallthrough 配置 |
                      +-------------------------------+
                               |
                               +-- hosts 插件 fallthrough 限制 zone?
                               |         |
                               |         +-- 是 --> 修改为 fallthrough .
                               |
                               +-- kubernetes 插件配置问题?
                                         |
                                         +-- 检查 zone 声明和 fallthrough

五、常见错误配置对照表

错误配置问题正确配置
hosts 无 fallthrough所有未匹配域名被拦截fallthrough .
fallthrough in-addr.arpa ip6.arpa正向域名被拦截fallthrough .
kubernetes 在 hosts 之后自定义域名覆盖集群域名调整顺序:kubernetes 先执行
forward 无上游 DNS外部域名无法解析配置有效上游 DNS
缺少 cache 插件DNS 查询压力大添加 cache 30

六、修复操作步骤

6.1 备份当前 CoreDNS 配置

在修改配置前,先备份当前配置以便回滚:

bash
kubectl get configmap coredns -n kube-system -o yaml > coredns-config-backup.yaml

6.2 查看当前 CoreDNS 配置

bash
kubectl get configmap coredns -n kube-system -o yaml

6.3 修改 CoreDNS ConfigMap

使用 kubectl edit 命令编辑 CoreDNS 配置:

bash
kubectl edit configmap coredns -n kube-system

或者创建新的配置文件并应用:

推荐的通用 CoreDNS 配置(适用于大多数 K8s 集群):

yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system
data:
  Corefile: |
    .:53 {
        errors
        health
        ready
        kubernetes cluster.local in-addr.arpa ip6.arpa {
          pods insecure
          fallthrough in-addr.arpa ip6.arpa
          ttl 30
        }
        # hosts 插件配置(如需添加自定义域名映射)
        hosts {
          # 在此添加自定义域名映射,例如:
          # 192.168.1.100 my-service.example.com
          fallthrough .  # 关键配置:允许所有解析域名接力
        }
        prometheus :9153
        forward . /etc/resolv.conf {
          max_concurrent 1000
        }
        cache 30
        loop
        reload
        loadbalance
    }

配置说明:

配置项说明
errors输出错误日志
health健康检查端点
ready就绪检查端点
kubernetes处理集群内 Service 域名解析
hosts自定义域名映射,fallthrough . 表示未匹配时传递给下一个插件
prometheus指标采集端点
forward转发无法解析的请求到上游 DNS
cache缓存解析结果
loop检测 DNS 解析循环
reload自动重载配置
loadbalance负载均衡 DNS 响应

6.4 应用配置

如果使用配置文件方式:

bash
kubectl apply -f coredns-config.yaml

6.5 重启 CoreDNS Pod 使配置生效

方式一:删除 Pod 自动重建

bash
kubectl delete pods -n kube-system -l k8s-app=kube-dns

方式二:使用 rollout restart(推荐)

bash
kubectl rollout restart deployment coredns -n kube-system

6.6 验证配置生效

验证 CoreDNS Pod 状态:

bash
kubectl get pods -n kube-system -l k8s-app=kube-dns

验证集群内 Service 域名解析:

bash
# 进入测试 Pod
kubectl run test-dns --image=busybox:1.28 --rm -it --restart=Never -- nslookup kubernetes.default.svc.cluster.local

# 预期输出:
# Server:    10.96.0.10
# Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
# 
# Name:      kubernetes.default.svc.cluster.local
# Address 1: 10.96.0.1 kubernetes.default.svc.cluster.local

验证自定义域名解析(如已配置 hosts):

bash
kubectl run test-dns --image=busybox:1.28 --rm -it --restart=Never -- nslookup my-service.example.com

查看 CoreDNS 日志:

bash
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=50

七、故障总结与生产建议

7.1 核心故障结论

直接原因: hosts 插件配置 fallthrough in-addr.arpa ip6.arpa,仅允许反向解析域名(in-addr.arpa/ip6.arpa)失败后接力,集群核心的正向 SVC 域名(cluster.local)被拦截,无法传递给 kubernetes 插件。

间接原因: hosts 插件的执行特性导致请求在上游被阻断,下游的 forward 插件完全无法参与解析。

关键澄清: 本次故障中 kubernetes 插件本身配置正常,问题完全出在 hosts 插件的请求拦截。

7.2 生产环境配置规范

配置规范:

  1. hosts 插件:添加自定义域名时,fallthrough 优先配置为无 zone 限制(fallthrough 或 fallthrough .)
  2. kubernetes 插件:直接使用 fallthrough(无 zone 限制),保证正向/反向解析失败都能传递给 forward 插件兜底
  3. 插件顺序:保持 kubernetes -> hosts -> forward 的顺序

运维规范:

  1. 配置前备份:修改 CoreDNS 配置前,先执行 kubectl get configmap coredns -n kube-system -o yaml > backup.yaml 备份
  2. 小范围验证:配置修改后,先在测试 Pod 验证自定义域名和集群 SVC 域名的解析,再全量生效
  3. 灰度重启:分批重启(kubectl rollout restart deployment coredns -n kube-system),避免 DNS 服务中断

排障规范:

  1. 优先检查 hosts 插件:集群 SVC 不通但 IP 通时,优先查看 fallthrough 配置
  2. 查看 CoreDNS 日志:通过 kubectl logs -n kube-system -l k8s-app=kube-dns 定位插件拦截点,关键错误示例:no next plugin for zone "cluster.local"
  3. 直接测试插件链:在 CoreDNS Pod 内直接测试解析(kubectl exec -it <coredns-pod-name> -n kube-system -- nslookup kubernetes.default.svc.cluster.local 127.0.0.1),判断是否为 CoreDNS 自身问题

八、技术验证说明

本文核心技术内容已经过官方文档验证:

  1. fallthrough 机制描述与 CoreDNS 官方文档一致
  2. 故障根因分析符合技术逻辑
  3. 修复方案符合最佳实践
  4. 补充说明:CoreDNS 插件链按 Corefile 配置顺序执行,而非固定优先级

九、总结

本次故障是因对 hosts 插件的 fallthrough 参数作用范围理解偏差导致。fallthrough in-addr.arpa ip6.arpa 仅开放了反向解析域名的接力能力,却阻断了集群核心的正向 SVC 域名解析链路。将其修改为无限制的 fallthrough(或 fallthrough .),恢复 hosts 插件到 kubernetes 插件的完整请求链路,既保留自定义域名的解析,又保证集群 SVC 的正常访问,故障即可彻底解决。


十、实战技巧速查

10.1 常用诊断命令

bash
# 查看 CoreDNS Pod 状态
kubectl get pods -n kube-system -l k8s-app=kube-dns -o wide

# 查看 CoreDNS 配置
kubectl get configmap coredns -n kube-system -o yaml

# 测试集群内域名解析
kubectl run test-dns --image=busybox:1.28 --rm -it --restart=Never -- nslookup kubernetes.default

# 测试外部域名解析
kubectl run test-dns --image=busybox:1.28 --rm -it --restart=Never -- nslookup www.baidu.com

# 查看 CoreDNS 日志
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=100

# 进入 CoreDNS 容器调试
kubectl exec -it -n kube-system deployment/coredns -- sh

10.2 关键日志关键词

日志关键词含义处理建议
no next plugin for zone请求被插件链拦截检查 fallthrough 配置
SERVFAILDNS 服务错误检查上游 DNS 连通性
NXDOMAIN域名不存在检查域名拼写或配置
timeout查询超时检查网络或上游 DNS

10.3 配置变更检查清单

  • [ ] 备份当前 CoreDNS ConfigMap
  • [ ] 确认 fallthrough 配置正确
  • [ ] 确认插件顺序合理
  • [ ] 验证自定义域名解析
  • [ ] 验证集群 SVC 域名解析
  • [ ] 验证外部域名解析
  • [ ] 监控 CoreDNS Pod 状态
  • [ ] 记录变更内容