K8s 跨集群通信的“量子纠缠”:当 DNS 黑洞吞没你的服务请求

发布于:2025-03-24 ⋅ 阅读:(12) ⋅ 点赞:(0)

 

引言

对于这种案例,你们的处理思路是怎么样的呢,是否真正的处理过,如果遇到,你们应该怎么处理。

我想大多数人都没有遇到过。

开始

一、现象:跨集群通信的神秘失效

某金融系统在混合云架构中部署了多套 Kubernetes 集群,用于实现跨地域容灾。某次业务切换演练时,发现跨集群服务发现完全失效,具体表现为:

  1. 服务发现中断
    # 在故障 Pod 中测试解析  
    kubectl exec -it frontend-pod -- nslookup backend-service.cluster-b.svc.cluster.local  
    ;; Got SERVFAIL reply from 10.96.0.10, trying next server  
    ;; connection timed out; no servers could be reached
    • 集群 A 的 Pod 无法通过 service-name.cluster-b.svc.cluster.local 访问集群 B 的服务
    • nslookup 返回 **SERVFAIL** 错误,但 CoreDNS 日志无任何异常记录
  2. 核心指标异常
    • Prometheus 监控显示 coredns_dns_request_count_total{rcode="SERVFAIL"} 激增
    • 服务网格流量统计中,跨集群请求失败率高达 92%

二、根因分析:DNS 配置的「死亡组合」

1. ndots:5 的「量子纠缠」

问题本质

Kubernetes 默认在 Pod 的 /etc/resolv.conf 中设置 options ndots:5。该配置要求:

  • 当查询的域名包含 少于 5 个点 时,DNS 客户端会尝试追加所有 searchDomains
  • 对于跨集群服务域名 backend-service.cluster-b.svc.cluster.local(4 个点),触发以下查询链:
    # 实际查询顺序(伪代码)
    for domain in searchDomains:
        query = "backend-service.cluster-b.svc.cluster.local.{domain}"
        send_to_dns_server(query)

致命冲突
私有 DNS 服务器(如 AD DNS)无法处理这种带冗余后缀的查询,直接返回 SERVFAIL

2. searchDomains 的「黑洞陷阱」

问题本质
/etc/resolv.conf 中残留无效的 searchDomains,例如:

search default.svc.cluster.local svc.cluster.local cluster.local corp.legacy.com # 已废弃的域

灾难链

  1. 客户端先尝试查询 backend-service.cluster-b.svc.cluster.local.default.svc.cluster.local
  2. 私有 DNS 无法解析,耗时 5 秒(默认超时)
  3. 继续尝试下一个后缀,最终耗尽查询时间

三、解决方案:四步破解 DNS 黑洞

1. 动态调整 ndots 配置

通过 ConfigMap 覆盖默认 DNS 策略:

# coredns-configmap.yaml  
apiVersion: v1  
kind: ConfigMap  
metadata:  
  name: coredns-custom  
  namespace: kube-system  
data:  
  Corefile: |  
    cluster.local:53 {  
      errors  
      health  
      ready  
      kubernetes cluster.local in-addr.arpa ip6.arpa {  
        pods insecure  
        fallthrough in-addr.arpa ip6.arpa  
      }  
      # 关键:调整 ndots 为 3  
      template IN A {  
        match "^([^\.]+)\.([^\.]+)\.svc\.cluster\.local$"  
        answer "{{ .Name }}.{{ .Match.2 }}.svc.cluster.local 5 IN A $SERVICE_IP"  
        fallthrough  
      }  
      forward . /etc/resolv.conf {  
        policy sequential  
        prefer_udp  
      }  
      cache 30  
      reload 15s  
      # 强制 ndots=3  
      loop  
      reload  
      loadbalance  
    }  
2. 清理无效 searchDomains

在 Pod 模板中注入 DNS 配置:

# deployment-patch.yaml  
spec:  
  template:  
    spec:  
      dnsConfig:  
        searches:  # 仅保留有效域  
        - cluster-b.svc.cluster.local  
        - svc.cluster.local  
        - cluster.local  
        options:  
        - name: ndots  
          value: "3"  
3. DNS 查询链路验证

使用 netshoot 镜像进行全链路测试:

# 启动诊断容器  
kubectl run dns-debug --image=nicolaka/netshoot --rm -it --restart=Never -- /bin/sh  

# 分步测试解析  
dig +trace backend-service.cluster-b.svc.cluster.local  
nslookup -debug backend-service.cluster-b.svc.cluster.local  
# 检查实际查询顺序  
cat /etc/resolv.conf  
4. 防御体系构建
层级 工具/策略 防护能力
配置校验 OpenPolicyAgent (OPA) 拦截无效 searchDomains
监控预警 Prometheus + CoreDNS 指标 实时检测 SERVFAIL 率
混沌测试 Chaos Mesh 注入 DNS 延迟 提前发现链路脆弱点

四、核心命令速查表

# 1. 查看 Pod 的 DNS 配置  
kubectl exec <pod-name> -- cat /etc/resolv.conf  

# 2. 强制刷新 CoreDNS 缓存  
kubectl delete pod -n kube-system -l k8s-app=kube-dns  

# 3. 抓取跨集群 DNS 包  
kubectl debug <pod-name> -it --image=nicolaka/netshoot -- tcpdump -i any -nn port 53  

# 4. 生成 DNS 查询拓扑图  
kubectl get svc -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.clusterIP}{"\n"}{end}' > dns-map.txt  

五、经验总结

  1. DNS 配置的「蝴蝶效应」:一个 ndots 参数足以引发跨集群雪崩,理解 Kubernetes DNS 解析链(递归查询 → searchDomains 追加 → 超时控制)是关键。
  2. 防御性编码原则:在 CI/CD 流水线中集成 DNS 策略校验(如 kube-score 检查 dnsConfig)。
  3. 观测驱动运维:通过指标 coredns_dns_response_rcode_count 定位异常模式,比日志更早发现问题。

“在分布式系统中,DNS 从来不是简单的域名解析,而是连接所有组件的神经系统。”
—— 某跨国企业 SRE 团队故障复盘报告

结语

以上就是我们今天的内容,希望可以帮助到大家,在面试中游刃有余,主动出击。


 

往期回顾


网站公告

今日签到

点亮在社区的每一天
去签到