K8s 跨集群通信的“量子糾纏”:當(dāng) DNS 黑洞吞沒你的服務(wù)請求
引言
對于這種案例,你們的處理思路是怎么樣的呢,是否真正的處理過,如果遇到,你們應(yīng)該怎么處理。
我想大多數(shù)人都沒有遇到過。
開始
一、現(xiàn)象:跨集群通信的神秘失效
某金融系統(tǒng)在混合云架構(gòu)中部署了多套 Kubernetes 集群,用于實(shí)現(xiàn)跨地域容災(zāi)。某次業(yè)務(wù)切換演練時(shí),發(fā)現(xiàn)跨集群服務(wù)發(fā)現(xiàn)完全失效,具體表現(xiàn)為:
1. 服務(wù)發(fā)現(xiàn)中斷:
# 在故障 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 的服務(wù)
? nslookup 返回 **SERVFAIL** 錯(cuò)誤,但 CoreDNS 日志無任何異常記錄
2. 核心指標(biāo)異常:
? Prometheus 監(jiān)控顯示 coredns_dns_request_count_total{rcode="SERVFAIL"} 激增
? 服務(wù)網(wǎng)格流量統(tǒng)計(jì)中,跨集群請求失敗率高達(dá) 92%
二、根因分析:DNS 配置的「死亡組合」
1. ndots:5 的「量子糾纏」
問題本質(zhì):
Kubernetes 默認(rèn)在 Pod 的 /etc/resolv.conf 中設(shè)置 options ndots:5。該配置要求:
? 當(dāng)查詢的域名包含 少于 5 個(gè)點(diǎn) 時(shí),DNS 客戶端會嘗試追加所有 searchDomains
? 對于跨集群服務(wù)域名 backend-service.cluster-b.svc.cluster.local(4 個(gè)點(diǎn)),觸發(fā)以下查詢鏈:
# 實(shí)際查詢順序(偽代碼)
for domain in searchDomains:
query = "backend-service.cluster-b.svc.cluster.local.{domain}"
send_to_dns_server(query)
致命沖突:私有 DNS 服務(wù)器(如 AD DNS)無法處理這種帶冗余后綴的查詢,直接返回 SERVFAIL。
2. searchDomains 的「黑洞陷阱」
問題本質(zhì):/etc/resolv.conf 中殘留無效的 searchDomains,例如:
search default.svc.cluster.local svc.cluster.local cluster.local corp.legacy.com # 已廢棄的域
災(zāi)難鏈:
1. 客戶端先嘗試查詢 backend-service.cluster-b.svc.cluster.local.default.svc.cluster.local
2. 私有 DNS 無法解析,耗時(shí) 5 秒(默認(rèn)超時(shí))
3. 繼續(xù)嘗試下一個(gè)后綴,最終耗盡查詢時(shí)間
三、解決方案:四步破解 DNS 黑洞
1. 動態(tài)調(diào)整 ndots 配置
通過 ConfigMap 覆蓋默認(rèn) 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
}
# 關(guān)鍵:調(diào)整 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
# 強(qiáng)制 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 查詢鏈路驗(yàn)證
使用 netshoot 鏡像進(jìn)行全鏈路測試:
# 啟動診斷容器
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
# 檢查實(shí)際查詢順序
cat /etc/resolv.conf
4. 防御體系構(gòu)建
層級 | 工具/策略 | 防護(hù)能力 |
配置校驗(yàn) | OpenPolicyAgent (OPA) | 攔截?zé)o效 |
監(jiān)控預(yù)警 | Prometheus + CoreDNS 指標(biāo) | 實(shí)時(shí)檢測 |
混沌測試 | Chaos Mesh 注入 DNS 延遲 | 提前發(fā)現(xiàn)鏈路脆弱點(diǎn) |
四、核心命令速查表
# 1. 查看 Pod 的 DNS 配置
kubectl exec <pod-name> -- cat /etc/resolv.conf
# 2. 強(qiáng)制刷新 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 查詢拓?fù)鋱D
kubectl get svc -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.clusterIP}{"\n"}{end}' > dns-map.txt
五、經(jīng)驗(yàn)總結(jié)
1. DNS 配置的「蝴蝶效應(yīng)」:一個(gè) ndots 參數(shù)足以引發(fā)跨集群雪崩,理解 Kubernetes DNS 解析鏈(遞歸查詢 → searchDomains 追加 → 超時(shí)控制)是關(guān)鍵。
2. 防御性編碼原則:在 CI/CD 流水線中集成 DNS 策略校驗(yàn)(如 kube-score 檢查 dnsConfig)。
3. 觀測驅(qū)動運(yùn)維:通過指標(biāo) coredns_dns_response_rcode_count 定位異常模式,比日志更早發(fā)現(xiàn)問題。