DNS Debugging và Performance Tuning
Tại Sao DNS Debug Khó
DNS failure thường không hiển thị rõ ràng. Application thấy "connection timeout" hay "connection refused", không thấy "DNS lookup failed". Hệ quả là developer đi debug network connectivity trong khi vấn đề thực sự ở DNS layer.
Thêm vào đó, DNS failures trong Kubernetes có nhiều lớp và nguồn gốc:
- Pod layer:
/etc/resolv.confsai, dnsPolicy sai - Cluster DNS layer: CoreDNS overloaded, pod crash, configuration error
- Node layer: conntrack exhaustion, network namespace issues
- Cloud DNS layer: zone sync delay, peering misconfiguration
- Upstream layer: external DNS unreachable, firewall blocking
Debug hiệu quả cần hiểu layers và test từng layer theo thứ tự — không nhảy vào giả định nguyên nhân.
Debug Workflow — Từ Pod Ra Ngoài
Layer 1: Verify /etc/resolv.conf
Bước đầu tiên luôn là kiểm tra cấu hình DNS của Pod:
# Xem resolv.conf
kubectl exec -it <pod-name> -- cat /etc/resolv.conf
# Expected output với NodeLocal DNSCache:
# nameserver 169.254.20.10
# search default.svc.cluster.local svc.cluster.local cluster.local
# options ndots:5
# Expected output với kube-dns (không có NodeLocal DNSCache):
# nameserver 10.96.0.10
# search default.svc.cluster.local svc.cluster.local cluster.local
# options ndots:5
# Expected output với Cloud DNS (không có NodeLocal DNSCache):
# nameserver 169.254.169.254
# ...Nếu nameserver trỏ sai (ví dụ: 0.0.0.0 hoặc empty), dnsPolicy bị misconfigure hoặc kubelet có vấn đề.
Layer 2: Test Basic DNS Resolution
# Chạy busybox trong cluster để test DNS
kubectl run dns-debug --image=busybox:1.36 \
--rm -it --restart=Never -- sh
# Trong busybox shell:
# Test cluster-internal DNS
nslookup kubernetes.default.svc.cluster.local
# Test external DNS
nslookup google.com
# Test cross-namespace (phải specify namespace)
nslookup payment-service.backend.svc.cluster.local
# Test với FQDN (trailing dot - bypass search domains)
nslookup payment-service.backend.svc.cluster.local.Nếu kubernetes.default.svc.cluster.local resolve được nhưng external domain không, forward chain bị broken. Nếu cả hai fail, CoreDNS/Cloud DNS unreachable.
Layer 3: Trace Toàn Bộ Query Path
# dig cho phép xem chi tiết hơn nslookup
# -x: verbose, +search: show expanded search domains
kubectl exec -it <pod> -- dig +search payment-service
# Xem tất cả DNS queries bao gồm failed attempts
kubectl exec -it <pod> -- dig -debug payment-service 2>&1
# Test time DNS lookup mất bao lâu
kubectl exec -it <pod> -- time nslookup payment-service.backend.svc.cluster.local
# Verify ndots behavior
# Tên có ít dấu chấm sẽ trigger search domain expansion
kubectl exec -it <pod> -- dig api.example.com +stats 2>&1 | grep "Query time"
kubectl exec -it <pod> -- dig api.example.com. +stats 2>&1 | grep "Query time"
# Cái có trailing dot (FQDN) sẽ nhanh hơn đáng kểLayer 4: Kiểm Tra CoreDNS Pods
# Verify CoreDNS pods running
kubectl get pods -n kube-system -l k8s-app=kube-dns
# Với Cloud DNS for GKE, check controller
kubectl get pods -n kube-system | grep dns
# Xem logs của CoreDNS
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=100
# Filter errors
kubectl logs -n kube-system -l k8s-app=kube-dns | grep -E "REFUSED|SERVFAIL|ERROR"
# Xem NodeLocal DNSCache pods
kubectl get pods -n kube-system -l k8s-app=node-local-dns
kubectl logs -n kube-system -l k8s-app=node-local-dns --tail=100Layer 5: CoreDNS Metrics
CoreDNS expose Prometheus metrics ở port 9153. Quan trọng nhất:
# Port-forward đến CoreDNS pod
kubectl port-forward -n kube-system deployment/coredns 9153:9153
# Xem metrics
curl -s http://localhost:9153/metrics | grep -E "coredns_(dns_requests_total|dns_responses_total|forward_requests_total|cache_hits_total|dns_request_duration)"Metrics quan trọng:
| Metric | Ý nghĩa | Alert khi |
|---|---|---|
coredns_dns_requests_total | Tổng queries nhận được | Tăng đột biến |
coredns_dns_responses_total{rcode="NXDOMAIN"} | NXDOMAIN responses | >20% total requests |
coredns_forward_requests_total | Queries forward đến upstream | Tăng cao bất thường |
coredns_dns_request_duration_seconds_p99 | P99 latency | >100ms |
coredns_cache_hits_total | Cache hits | Hit rate thấp (<80%) |
coredns_forward_requests_duration_seconds_p99 | Upstream latency | >200ms |
Layer 6: Conntrack Table Status (Node Level)
Đây là layer thường bị bỏ qua nhưng là nguyên nhân của DNS drops:
# SSH vào node (hoặc dùng node debugging pod)
kubectl debug node/<node-name> -it --image=ubuntu
# Kiểm tra conntrack table size và usage
cat /proc/sys/net/netfilter/nf_conntrack_max # Max entries
cat /proc/sys/net/netfilter/nf_conntrack_count # Current entries
# Nếu count gần max → conntrack exhaustion đang xảy ra
# Xem conntrack entries related to DNS (port 53)
conntrack -L | grep "dport=53" | wc -l
# Xem conntrack full stats
conntrack -SNếu nf_conntrack_count gần nf_conntrack_max, đây là nguyên nhân DNS drops. Solution: enable NodeLocal DNSCache, hoặc increase table size (short-term fix).
Playbook Chẩn Đoán Theo Symptom
Symptom: "DNS lookup timeout" sau 5 giây
Nguyên nhân phổ biến nhất: Conntrack table exhaustion hoặc CoreDNS pods overloaded.
# Step 1: Check conntrack (trên node chạy pod bị ảnh hưởng)
kubectl debug node/<node> -it --image=busybox -- cat /proc/sys/net/netfilter/nf_conntrack_count
kubectl debug node/<node> -it --image=busybox -- cat /proc/sys/net/netfilter/nf_conntrack_max
# Step 2: Check CoreDNS latency metrics
kubectl port-forward -n kube-system deployment/coredns 9153:9153
curl http://localhost:9153/metrics | grep duration
# Step 3: Check CoreDNS pod resource usage
kubectl top pods -n kube-system -l k8s-app=kube-dns
# Solution path:
# - Conntrack full → Enable NodeLocal DNSCache
# - CoreDNS overloaded → Scale CoreDNS Deployment, check NXDOMAIN rateSymptom: High NXDOMAIN Rate — ndots:5 Lookup Storm
# Verify NXDOMAIN rate
kubectl port-forward -n kube-system deployment/coredns 9153:9153
curl -s http://localhost:9153/metrics | grep 'coredns_dns_responses_total{rcode="NXDOMAIN"}'
# Xác định pod nào đang generate nhiều NXDOMAIN
# CoreDNS logs với plugin errors:
kubectl logs -n kube-system -l k8s-app=kube-dns | grep NXDOMAIN | awk '{print $4}' | sort | uniq -c | sort -rn | head -20
# Verify ndots trong pod bị suspect
kubectl exec -it <suspect-pod> -- cat /etc/resolv.conf | grep ndots
# Solution: Override ndots cho pods với nhiều external callsSau khi identify pods với high external DNS traffic, override ndots:
spec:
dnsConfig:
options:
- name: ndots
value: "2" # Giảm từ 5 xuống 2Với ndots:2, api.example.com (2 dấu chấm) được query như FQDN trực tiếp — không có search domain expansion.
Symptom: Cross-Namespace Service Không Resolve
# Test từ pod nguồn
kubectl exec -it <pod-in-namespace-a> -- \
nslookup service-name.namespace-b.svc.cluster.local
# Common mistake: thiếu namespace trong service name
kubectl exec -it <pod> -- nslookup service-name # Fail vì search domains không cover namespace-b
kubectl exec -it <pod> -- nslookup service-name.namespace-b # Đúng
kubectl exec -it <pod> -- nslookup service-name.namespace-b.svc.cluster.local # FQDN đầy đủSymptom: DNS Resolution Chậm Cho External Hostnames
# Đo latency với và không có trailing dot
kubectl exec -it <pod> -- sh -c 'time nslookup api.external.com'
kubectl exec -it <pod> -- sh -c 'time nslookup api.external.com.'
# Nếu có trailing dot nhanh hơn đáng kể → ndots:5 lookup storm
# Kiểm tra số queries thực tế với strace
kubectl exec -it <pod> -- strace -e trace=sendto,recvfrom \
nslookup api.external.com 2>&1 | grep "53" | wc -lPerformance Tuning
Override ndots Per-Pod/Per-Deployment
Cách tốt nhất để reduce NXDOMAIN storm cho services với nhiều external calls:
# Deployment với nhiều external HTTP calls
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
dnsConfig:
options:
- name: ndots
value: "1" # Hoặc "2" tùy pattern
containers:
- name: app
...Khi nào dùng ndots gì:
ndots:5(mặc định): Phù hợp cho services chủ yếu gọi cluster-internal namesndots:2: Phù hợp cho services mix giữa internal và external (short internal names + external với ≥2 dots)ndots:1: Phù hợp cho services gần như chỉ gọi external services
Lưu ý: Nếu giảm ndots quá thấp, short internal service names có thể không resolve được. Test kỹ trước khi rollout.
CoreDNS Cache Tuning
CoreDNS cache plugin trong Corefile:
cache {
success 9984 # Max entries cho successful responses (mặc định: unbounded)
denial 9984 # Max entries cho NXDOMAIN/NODATA responses
ttl 30 # Max TTL cho cached responses
servfail 5 # TTL cho SERVFAIL responses
}Tăng success và denial cache size → ít queries đến upstream hơn → better performance. Trade-off: memory usage tăng.
Với 9984 entries mỗi loại, memory usage ~30-40MB per CoreDNS pod. Với 100,000 entries: ~300MB.
Scale CoreDNS Horizontally
Mặc định GKE tự scale CoreDNS nhưng có thể override:
# Xem CoreDNS Deployment
kubectl get deployment coredns -n kube-system
# Không nên manual scale trong GKE — GKE tự manage
# Nhưng có thể check autoscaling config
kubectl get configmap coredns-autoscaler -n kube-system -o yamlGKE dùng DNS Autoscaling dựa trên số nodes. Cấu hình trong ConfigMap coredns-autoscaler.
NodeLocal DNSCache Cache Sizing
# Xem config của NodeLocal DNS
kubectl get configmap -n kube-system node-local-dns -o yaml
# Corefile trong ConfigMap có cache settings
# Mặc định: cache 30 (30 giây max TTL, unbounded entries)
# Để giới hạn entries:
# cache 30 {
# success 9984
# denial 9984
# }Connection Pooling Cho Upstream
Forward plugin max_concurrent ảnh hưởng đến throughput upstream:
forward . 169.254.169.254 {
max_concurrent 2000 # Tăng từ 1000 mặc định
expire 10s # Expire idle connections sau 10s
health_check 5s # Health check upstream interval
}max_concurrent cao hơn cho phép nhiều concurrent upstream queries nhưng tốn memory và FDs hơn.
CoreDNS Logs — Enable Query Logging
Mặc định CoreDNS không log từng DNS query (quá nhiều). Khi debug, có thể bật tạm thời:
# Edit ConfigMap để thêm log plugin
kubectl edit configmap coredns -n kube-system
# Thêm plugin 'log' vào server block:
# .:53 {
# log # Log tất cả queries
# errors
# ...
# }
# CẢNH BÁO: log plugin rất verbose trong production cluster
# Chỉ bật tạm thời để debug, disable ngay sau khi xongLog output mẫu:
[INFO] 10.0.1.5:47832 - 12345 "A IN payment-service.backend.svc.cluster.local. udp 62 false 512" NOERROR qr,aa,rd 106 0.000234s
[INFO] 10.0.1.5:47833 - 12346 "A IN api.external.com. udp 45 false 512" NOERROR qr,rd,ra 89 0.002341sFormat: [client-ip] - [query-id] [type] [name] [transport] [RCODE] [flags] [response-size] [latency]
Checklist Verification Sau DNS Config Changes
Sau mọi thay đổi DNS configuration (thêm stub domain, thay đổi upstream, update Cloud DNS scope), verify theo thứ tự:
#!/bin/bash
# DNS health check script
echo "1. CoreDNS pods running?"
kubectl get pods -n kube-system -l k8s-app=kube-dns
echo "2. NodeLocal DNS pods running?"
kubectl get pods -n kube-system -l k8s-app=node-local-dns
echo "3. Cluster-internal DNS working?"
kubectl run dns-check --image=busybox:1.36 --rm -it --restart=Never -- \
nslookup kubernetes.default.svc.cluster.local
echo "4. External DNS working?"
kubectl run dns-check --image=busybox:1.36 --rm -it --restart=Never -- \
nslookup google.com
echo "5. NXDOMAIN rate check (< 5% threshold)?"
kubectl port-forward -n kube-system deployment/coredns 9153:9153 &
sleep 2
TOTAL=$(curl -s http://localhost:9153/metrics | grep 'coredns_dns_requests_total' | awk '{sum+=$2} END {print sum}')
NXDOMAIN=$(curl -s http://localhost:9153/metrics | grep 'NXDOMAIN' | awk '{sum+=$2} END {print sum}')
echo "NXDOMAIN rate: $(echo "scale=2; $NXDOMAIN * 100 / $TOTAL" | bc)%"
kill %1 # Kill port-forward