CoreDNS vs NodeLocal DNS Cache: Zníženie Kubernetes DNS Latencie 10x
NodeLocal DNSCache sme benchmarkovali po DNS incidente, ktory nechceme zopakovat. “Prečo každé HTTP volanie pridáva 5ms latenciu?” Každé volanie služby vyžaduje DNS lookup. Vaše pody komunikujú s CoreDNS cez sieť. S NodeLocal DNS Cache to klesne na 0.2ms.
Testované na: Kubernetes 1.28, CoreDNS 1.11, NodeLocal DNSCache 1.22, 50-nodový cluster
DNS Bottleneck
Ako Kubernetes DNS Funguje
Bez NodeLocal DNS Cache:
Pod → kube-dns Service (ClusterIP) → CoreDNS Pod
└─ Sieťový hop (5-20ms) └─ Možno na inom node
DNS cesta:
1. Pod urobí DNS query (UDP)
2. Query ide na kube-dns ClusterIP (10.96.0.10)
3. kube-proxy/iptables smeruje na CoreDNS pod
4. CoreDNS resolvuje (cache hit alebo upstream query)
5. Odpoveď sa vracia rovnakou cestou
Problém
Typický web request DNS lookupy:
1. Service discovery: api.default.svc.cluster.local
2. Database: postgres.db.svc.cluster.local
3. Cache: redis.cache.svc.cluster.local
4. Externé API: api.stripe.com
4 DNS lookupy × 5ms = 20ms pridaná latencia per request!
Pri 1000 RPS:
- 4000 DNS queries/sec na CoreDNS
- CoreDNS sa stáva bottleneckom
- Tail latencia rastie
NodeLocal DNS Cache
Ako Funguje
S NodeLocal DNS Cache:
Pod → NodeLocal DaemonSet → CoreDNS (len pri cache miss)
└─ Lokálne (0.2ms) └─ Sieť (5ms, zriedka)
NodeLocal beží ako DaemonSet:
- Jeden pod per node
- Počúva na link-local IP (169.254.20.10)
- Cachuje odpovede lokálne
- Fallback na CoreDNS pri miss
Inštalácia
# Stiahni NodeLocal DNS manifest
kubectl apply -f https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dns/nodelocaldns/nodelocaldns.yaml
# Alebo s Helm
helm install nodelocaldns stable/nodelocaldns \
--set config.localDNS=169.254.20.10 \
--set config.clusterDNS=10.96.0.10
Konfigurácia
# nodelocaldns-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: node-local-dns
namespace: kube-system
data:
Corefile: |
cluster.local:53 {
errors
cache {
success 9984 30 # Cache 30 sekúnd
denial 9984 5 # Cache NXDOMAIN 5 sekúnd
}
reload
loop
bind 169.254.20.10
forward . __PILLAR__CLUSTER__DNS__ {
force_tcp
}
prometheus :9253
health 169.254.20.10:8080
}
in-addr.arpa:53 {
errors
cache 30
reload
loop
bind 169.254.20.10
forward . __PILLAR__CLUSTER__DNS__ {
force_tcp
}
prometheus :9253
}
.:53 {
errors
cache 30
reload
loop
bind 169.254.20.10
forward . __PILLAR__UPSTREAM__SERVERS__
prometheus :9253
}
Pod Konfigurácia
# Možnosť 1: Modifikuj kubelet na použitie NodeLocal
# /var/lib/kubelet/config.yaml
clusterDNS:
- 169.254.20.10 # NodeLocal prvý
- 10.96.0.10 # Fallback na CoreDNS
# Možnosť 2: Per-pod dnsConfig
apiVersion: v1
kind: Pod
spec:
dnsPolicy: None
dnsConfig:
nameservers:
- 169.254.20.10
searches:
- default.svc.cluster.local
- svc.cluster.local
- cluster.local
options:
- name: ndots
value: "5"
Výsledky Benchmarku
Test Setup
// dns_benchmark.go
package main
import (
"net"
"testing"
"time"
)
func BenchmarkDNSLookup(b *testing.B) {
hosts := []string{
"kubernetes.default.svc.cluster.local",
"kube-dns.kube-system.svc.cluster.local",
}
for i := 0; i < b.N; i++ {
for _, host := range hosts {
_, err := net.LookupHost(host)
if err != nil {
b.Fatal(err)
}
}
}
}
Výsledky
Len CoreDNS (sieťová cesta):
Latencia p50: 5.2ms
Latencia p99: 28.4ms
Latencia p999: 89.2ms
Queries/sec: 8,500
NodeLocal DNS Cache (lokálna cesta):
Latencia p50: 0.18ms (29x rýchlejšie)
Latencia p99: 0.45ms (63x rýchlejšie)
Latencia p999: 1.2ms (74x rýchlejšie)
Queries/sec: 45,000 (5x vyššie)
Cache hit rate: 92% (typická produkcia)
Load Test
# Použitie dnsperf
dnsperf -s 169.254.20.10 -d queries.txt -l 60 -c 100
# Výsledky s NodeLocal:
# Queries sent: 2,812,456
# Queries completed: 2,812,456
# Queries lost: 0 (0.00%)
# Response codes: NOERROR 2,812,456 (100.00%)
# Average latency: 0.21ms
# Maximum latency: 2.34ms
Monitoring
Prometheus Metriky
# Cache hit rate
sum(rate(coredns_cache_hits_total{server="dns://:53"}[5m]))
/
sum(rate(coredns_dns_requests_total{server="dns://:53"}[5m]))
# DNS latencia (NodeLocal)
histogram_quantile(0.99,
sum(rate(coredns_dns_request_duration_seconds_bucket[5m])) by (le)
)
# Upstream forward latencia (CoreDNS)
histogram_quantile(0.99,
sum(rate(coredns_forward_request_duration_seconds_bucket[5m])) by (le)
)
Alert Rules
groups:
- name: dns
rules:
- alert: DNSLatencyHigh
expr: |
histogram_quantile(0.99, sum(rate(coredns_dns_request_duration_seconds_bucket[5m])) by (le))
> 0.01
for: 10m
labels:
severity: warning
annotations:
summary: "DNS p99 latencia > 10ms"
- alert: NodeLocalDNSDown
expr: |
up{job="nodelocaldns"} == 0
for: 5m
labels:
severity: critical
annotations:
summary: "NodeLocal DNS nebeží na {{ $labels.node }}"
Troubleshooting
DNS Nepoužíva NodeLocal
# Skontroluj resolv.conf v pode
kubectl exec -it mypod -- cat /etc/resolv.conf
# Malo by ukázať:
# nameserver 169.254.20.10
# Ak ukazuje 10.96.0.10, skontroluj kubelet config
NodeLocal Pod Crashuje
# Skontroluj logy
kubectl logs -n kube-system -l k8s-app=node-local-dns
# Bežné problémy:
# - Port konflikt (iný proces na 53)
# - Link-local IP už používaná
# - Nedostatočné oprávnenia (potrebuje NET_ADMIN)
Cache Nefunguje
# Skontroluj cache štatistiky
kubectl exec -n kube-system node-local-dns-xxxxx -- \
wget -qO- http://localhost:9253/metrics | grep cache
# Hľadaj:
# coredns_cache_hits_total
# coredns_cache_misses_total
Produkčná Konfigurácia
Optimalizované Nastavenia
# nodelocaldns-configmap.yaml
data:
Corefile: |
cluster.local:53 {
errors
cache {
success 9984 60 # Cache success 60 sekúnd
denial 9984 10 # Cache NXDOMAIN 10 sekúnd
prefetch 10 1m 10% # Prefetch populárnych entries
}
reload
loop
bind 169.254.20.10
forward . __PILLAR__CLUSTER__DNS__ {
force_tcp
max_concurrent 1000 # Vyššia konkurencia
}
prometheus :9253
health 169.254.20.10:8080
ready 169.254.20.10:8181
}
Resource Limity
# DaemonSet resource limity
resources:
requests:
cpu: 25m
memory: 32Mi
limits:
cpu: 100m
memory: 128Mi
ndots Optimalizácia
Problém
# Default ndots=5 v Kubernetes
# Query: api.stripe.com
# DNS search poradie:
1. api.stripe.com.default.svc.cluster.local (NXDOMAIN)
2. api.stripe.com.svc.cluster.local (NXDOMAIN)
3. api.stripe.com.cluster.local (NXDOMAIN)
4. api.stripe.com. (SUCCESS)
# 4 DNS queries pre jedno externé meno!
Riešenie
# Pod spec so zníženým ndots
spec:
dnsConfig:
options:
- name: ndots
value: "2" # Znížené z 5
# Alebo pridaj trailing bodku pre externé mená
# api.stripe.com. (absolútne meno, žiadne search)
Checklist
## NodeLocal DNS Cache Setup
### Inštalácia
- [ ] Deploy NodeLocal DaemonSet
- [ ] Nakonfiguruj kubelet clusterDNS
- [ ] Over že pody používajú 169.254.20.10
### Konfigurácia
- [ ] Nastav vhodné cache TTL
- [ ] Povoľ prefetch pre populárne entries
- [ ] Nakonfiguruj resource limity
### Monitoring
- [ ] Dashboard s cache hit rate
- [ ] Alert na DNS latenciu > 10ms
- [ ] Alert na zlyhania NodeLocal podu
### Optimalizácia
- [ ] Zváž zníženie ndots
- [ ] Použi absolútne DNS mená pre externé služby
- [ ] Monitoruj cache hit rates
Záver
DNS je skrytý Kubernetes bottleneck:
- Každé volanie služby potrebuje DNS lookup
- CoreDNS cez sieť pridáva 5-20ms per query
- NodeLocal cache znižuje na 0.2ms (29x rýchlejšie)
- 92% cache hit rate v produkcii
Nainštaluj NodeLocal DNS Cache a zníž svoju tail latenciu.
Súvisiace články
- K8s CPU Throttling Pitva - Performance tuning
- HTTP Keep-Alive Connection Reset - Network optimalizácia
Súvisiace články
Kubernetes DNS: Latency Daň ndots:5
Každý DNS query v K8s robí 5 neúspešných lookupov pred úspechom. ndots:5 default spôsobuje 100ms+ latenciu. Tu je ako to opraviť.
Kubernetes conntrack Vyčerpanie: Tichý Zabijak Paketov
Náhodné DNS timeouty, dropped spojenia, služby timeout-ujú. Vaša nf_conntrack tabuľka je plná. Ukážem ako diagnostikovať, monitorovať a opraviť tento K8s networking problém.
Go cgo DNS Resolution Thread Explózia: Keď net.LookupHost Spawne Tisíce Threadov
Go aplikácia má zrazu 10,000 threadov konzumujúcich všetku pamäť. Príčina: cgo-based DNS resolution blokujúce v pomalých DNS prostrediach, obchádzajúce Go's goroutine scheduler.
Kubernetes Headless Service DNS: Zastarané Záznamy Po Zmazaní Podu
Requesty idú na neexistujúce pody. Príčina: headless service DNS záznamy pretrvávajú v klient DNS cache po zmazaní podov, pred propagáciou endpoints update.
Citujte tento článok
Ak na článok odkazujete, pridajte pôvodnú URL a uveďte autora.