CoreDNS Prometheus ile Metrik İzleme
Kubernetes ortamında DNS sorunlarını debug etmeye çalışırken “acaba CoreDNS ne yapıyor?” diye düşündüğünüz oldu mu? Ben bu soruyu kendime ayda en az birkaç kez soruyordum, ta ki Prometheus ile düzgün bir metrik izleme kurulumu yapana kadar. Artık bir şey patlamadan önce neler döndüğünü görebiliyorum ve bu yazıda bunu nasıl yaptığımı paylaşacağım.
CoreDNS Metrik Sistemi Nasıl Çalışır?
CoreDNS, Prometheus formatında metrik sunmak için yerleşik bir plugin’e sahip. Bu plugin prometheus adını taşıyor ve Corefile’a tek satır ekleyerek aktive ediliyor. Ama işin sadeliğine aldanmayın; bu metrikleri doğru okumak ve anlamlandırmak başlı başına bir iş.
CoreDNS’in sunduğu metrikler birkaç ana kategoriye ayrılıyor:
- coredns_dns_requests_total: Toplam DNS istek sayısı, protocol/family/server/zone/type etiketleriyle
- coredns_dns_responses_total: Dönülen yanıtlar ve rcode’lar
- coredns_dns_request_duration_seconds: İstek işleme süresi histogramı
- coredns_dns_request_size_bytes: İstek boyutları
- coredns_dns_response_size_bytes: Yanıt boyutları
- coredns_cache_hits_total: Cache isabeti sayısı
- coredns_cache_misses_total: Cache ıskalama sayısı
- coredns_forward_requests_total: Upstream’e yönlendirilen istekler
- coredns_forward_healthcheck_failures_total: Upstream sağlık kontrol başarısızlıkları
Bu metrikleri okumak için önce CoreDNS’i düzgün yapılandırmak gerekiyor.
CoreDNS Prometheus Plugin Yapılandırması
Temel yapılandırma oldukça basit. Kubernetes’te CoreDNS genellikle kube-system namespace’inde bir ConfigMap ile yönetiliyor.
kubectl get configmap coredns -n kube-system -o yaml
Tipik bir Corefile şöyle görünür:
cat <<EOF > corefile-with-metrics.conf
.:53 {
errors
health {
lameduck 5s
}
ready
prometheus :9153
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
forward . /etc/resolv.conf {
max_concurrent 1000
}
cache 30
loop
reload
loadbalance
}
EOF
Buradaki prometheus :9153 satırı, CoreDNS’in 9153 portunda metrik sunmasını sağlıyor. Eğer bu satır yoksa hiçbir metrik göremezsiniz, bu arada. Kubernetes ortamında ConfigMap’i güncellemek için:
kubectl edit configmap coredns -n kube-system
Değişikliği yaptıktan sonra CoreDNS pod’larının reload plugin’i sayesinde otomatik yeniden yükleme yapması gerekiyor. Bunu doğrulamak için pod loglarına bakabilirsiniz:
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=20
Prometheus ServiceMonitor Kurulumu
Kubernetes üzerinde Prometheus Operator kullanıyorsanız (ve kullanıyor olmalısınız, elle scrape config yazmak artık 2015’te kaldı), ServiceMonitor kaynağı oluşturmanız gerekiyor.
Önce CoreDNS için bir Service tanımı var mı kontrol edin:
kubectl get svc -n kube-system | grep dns
Genellikle kube-dns adında bir servis zaten bulunuyor ama bu servis sadece 53 portunu expose ediyor. Metrikler için 9153 portunu da eklemek ya da ayrı bir servis oluşturmak gerekiyor.
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
name: coredns-metrics
namespace: kube-system
labels:
app: coredns
k8s-app: kube-dns
spec:
selector:
k8s-app: kube-dns
ports:
- name: metrics
port: 9153
targetPort: 9153
protocol: TCP
clusterIP: None
EOF
Şimdi ServiceMonitor:
cat <<EOF | kubectl apply -f -
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: coredns
namespace: monitoring
labels:
release: prometheus
spec:
namespaceSelector:
matchNames:
- kube-system
selector:
matchLabels:
k8s-app: kube-dns
endpoints:
- port: metrics
interval: 15s
path: /metrics
bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
tlsConfig:
insecureSkipVerify: true
EOF
Burada dikkat edilmesi gereken bir nokta: release: prometheus label’ı, Prometheus Operator’ın hangi ServiceMonitor’ları scrape edeceğini belirlemek için kullandığı selector ile eşleşmeli. Kendi kurulumunuzda bu label farklı olabilir, şöyle kontrol edin:
kubectl get prometheus -n monitoring -o jsonpath='{.items[0].spec.serviceMonitorSelector}'
Prometheus Olmayan Ortamlar için Statik Scrape Yapılandırması
Kubernetes dışında, örneğin bare metal veya VM üzerinde CoreDNS çalıştırıyorsanız, Prometheus’un prometheus.yml dosyasına statik hedef eklemek daha pratik:
cat <<EOF >> /etc/prometheus/prometheus.yml
scrape_configs:
- job_name: 'coredns'
static_configs:
- targets: ['coredns-server-1:9153', 'coredns-server-2:9153']
relabel_configs:
- source_labels: [__address__]
target_label: instance
- target_label: job
replacement: coredns
scrape_interval: 15s
scrape_timeout: 10s
EOF
Prometheus’u yeniden yüklemeden önce yapılandırmayı doğrulayın:
promtool check config /etc/prometheus/prometheus.yml
Ardından reload sinyali gönderin:
curl -X POST http://localhost:9090/-/reload
Grafana Dashboard Kurulumu
Grafana’da CoreDNS için hazır bir dashboard var, ID’si 5926. Bunu import etmek için Grafana UI’dan “Import” seçeneğini kullanabilirsiniz. Ama ben genellikle bu hazır dashboard’ları temel alıp kendi ortamıma göre özelleştiriyorum, çünkü hazırların bir kısmı eski metrik isimleriyle yazılmış oluyor.
Grafana API üzerinden dashboard import etmek için:
curl -s -X POST
-H "Content-Type: application/json"
-H "Authorization: Bearer YOUR_API_KEY"
http://grafana:3000/api/dashboards/import
-d '{
"dashboard": {"id": null},
"overwrite": true,
"inputs": [{"name": "DS_PROMETHEUS", "type": "datasource", "pluginId": "prometheus", "value": "Prometheus"}],
"folderId": 0,
"path": "https://grafana.com/api/dashboards/5926/revisions/latest/download"
}'
Kritik Alertler ve PromQL Sorguları
İşte gerçekten değerli kısım burası. Metrik toplamak güzel, ama ne zaman alarm üreteceğinizi bilmek daha önemli.
Günlük operasyonda kullandığım temel PromQL sorgularından bazıları:
DNS hata oranı:
# SERVFAIL oranı yüksek mi?
sum(rate(coredns_dns_responses_total{rcode="SERVFAIL"}[5m]))
/
sum(rate(coredns_dns_responses_total[5m])) * 100
Cache hit oranı:
sum(rate(coredns_cache_hits_total[5m]))
/
(sum(rate(coredns_cache_hits_total[5m])) + sum(rate(coredns_cache_misses_total[5m]))) * 100
95. persentil yanıt süresi:
histogram_quantile(0.95,
sum(rate(coredns_dns_request_duration_seconds_bucket[5m])) by (le, server)
)
Upstream forward hataları:
rate(coredns_forward_healthcheck_failures_total[5m]) > 0
Bu sorguları Prometheus alert rule’larına dönüştürmek için:
cat <<EOF > /etc/prometheus/rules/coredns.yml
groups:
- name: coredns
interval: 30s
rules:
- alert: CoreDNSHighErrorRate
expr: |
sum(rate(coredns_dns_responses_total{rcode=~"SERVFAIL|REFUSED"}[5m]))
/ sum(rate(coredns_dns_responses_total[5m])) * 100 > 5
for: 5m
labels:
severity: warning
annotations:
summary: "CoreDNS hata oranı yüksek"
description: "Son 5 dakikada DNS hata oranı {{ $value | printf "%.2f" }}% olarak ölçüldü."
- alert: CoreDNSLatencyHigh
expr: |
histogram_quantile(0.99,
sum(rate(coredns_dns_request_duration_seconds_bucket[5m])) by (le)
) > 0.5
for: 10m
labels:
severity: warning
annotations:
summary: "CoreDNS yanıt süresi yüksek"
description: "P99 yanıt süresi {{ $value | printf "%.3f" }} saniyenin üzerinde."
- alert: CoreDNSUpstreamFailure
expr: |
increase(coredns_forward_healthcheck_failures_total[5m]) > 3
for: 2m
labels:
severity: critical
annotations:
summary: "CoreDNS upstream DNS erişilemiyor"
description: "{{ $labels.to }} upstream'ine sağlık kontrolleri başarısız oluyor."
- alert: CoreDNSCacheHitRateLow
expr: |
sum(rate(coredns_cache_hits_total[10m]))
/ (sum(rate(coredns_cache_hits_total[10m])) + sum(rate(coredns_cache_misses_total[10m]))) * 100 < 60
for: 15m
labels:
severity: info
annotations:
summary: "CoreDNS cache hit oranı düşük"
description: "Cache hit oranı %{{ $value | printf "%.1f" }} seviyesinde, cache boyutunu artırmayı değerlendirin."
EOF
Gerçek Dünya Senaryosu: Gece Yarısı DNS Krizi
Geçen yıl yaşanan bir olayı anlatayım. Bir Kubernetes cluster’ında servisler arasında intermittent bağlantı kopmaları yaşanmaya başladı. Uygulama ekibi “bazen çalışıyor bazen çalışmıyor” diyordu, ki bu her sysadmin’in korkulu rüyasıdır.
Grafana’yı açtığımda coredns_forward_healthcheck_failures_total metriğinin gece 02:00-04:00 arasında spike yaptığını gördüm. Aynı saatlerde coredns_dns_request_duration_seconds P99 değeri 500ms’nin üzerine çıkıyordu.
Prometheus’ta daha derine indim:
# Hangi zone'lara yapılan istekler yavaş?
histogram_quantile(0.95,
sum(rate(coredns_dns_request_duration_seconds_bucket[5m])) by (le, zone)
)
Sonuç çok netti: Cluster dışı DNS sorguları yavaşlıyordu, internal sorgular değil. CoreDNS’in forward ettiği upstream DNS sunucusu (şirket içi bir DNS resolver) gece yarısı bakım penceresi nedeniyle yavaşlıyormuş. Hiç kimse bunu CoreDNS ekibine söylememiş tabii.
Çözüm: Corefile’a ikincil bir upstream ekledik ve health_check interval’ını düşürdük:
forward . 10.0.0.53 8.8.8.8 {
max_concurrent 1000
health_check 5s
policy sequential
}
Metriklerin olmadığı dönemde bu sorunu bulmak günler sürerdi. Metriklerle birlikte 20 dakikada çözdük.
CoreDNS Metrik Derinlikleri: Labels ile Analiz
CoreDNS metrikleri üzerindeki label’ları iyi anlamak, granüler analiz yapabilmenin anahtarı. Özellikle büyük cluster’larda hangi namespace’in ne kadar DNS sorgusu ürettiğini görmek isteyebilirsiniz.
Kubernetes’te CoreDNS’e gelen sorgularda kubernetes plugin’i zone bilgisini ekliyor. Bunu kullanarak:
# Zone bazında istek dağılımı
sum by (zone) (rate(coredns_dns_requests_total[5m]))
# Protokol bazında (UDP vs TCP)
sum by (proto) (rate(coredns_dns_requests_total[5m]))
# Sorgu tipi bazında (A, AAAA, SRV, PTR...)
sum by (type) (rate(coredns_dns_requests_total[5m]))
type bazında analiz yaparken PTR sorgularının beklenmedik biçimde yüksek olduğunu görmek çok yaygın bir bulgu. Bu genellikle uygulamaların IP adreslerini sürekli reverse lookup yaptığı anlamına geliyor ve çoğunlukla gereksiz bir yük. Bunu tespit edip uygulama ekiplerine bildirmek CoreDNS yükünü ciddi oranda düşürebiliyor.
Performans Baselining
Bir ortama yeni geldiğinizde veya büyük değişiklikler öncesinde baseline almak kritik. Şu recording rule’ları kullanıyorum:
cat <<EOF >> /etc/prometheus/rules/coredns-recording.yml
groups:
- name: coredns-recording
interval: 1m
rules:
- record: job:coredns_dns_requests:rate5m
expr: sum(rate(coredns_dns_requests_total[5m])) by (server, zone)
- record: job:coredns_error_rate:ratio5m
expr: |
sum(rate(coredns_dns_responses_total{rcode!="NOERROR"}[5m])) by (server)
/
sum(rate(coredns_dns_responses_total[5m])) by (server)
- record: job:coredns_cache_hit_ratio:rate5m
expr: |
sum(rate(coredns_cache_hits_total[5m]))
/
(sum(rate(coredns_cache_hits_total[5m])) + sum(rate(coredns_cache_misses_total[5m])))
EOF
Recording rule’lar karmaşık sorguları önceden hesaplayıp saklamak için kullanılır. Özellikle Grafana dashboard’larınızda sık sorgulanan metrikler için performans açısından çok fark yaratıyor, büyük Prometheus deployment’larında bunu mutlaka yapın.
Metrik Erişimini Doğrulama
Her şeyi kurduğunuzda gerçekten çalışıp çalışmadığını test etmek için:
# CoreDNS metrik endpoint'ine doğrudan erişim
kubectl exec -it -n kube-system $(kubectl get pods -n kube-system -l k8s-app=kube-dns -o name | head -1) -- wget -qO- http://localhost:9153/metrics | grep coredns_dns_requests_total | head -5
# Prometheus'un hedefi scrape edip etmediğini kontrol etme
curl -s http://prometheus:9090/api/v1/targets | python3 -m json.tool | grep -A 5 coredns
# Kısa süreli yük testi ile metriklerin değişip değişmediğini görmek
for i in $(seq 1 100); do
kubectl exec -it -n default test-pod -- nslookup kubernetes.default.svc.cluster.local > /dev/null 2>&1
done
Metriklerin gerçekten güncellendiğini Prometheus query browser’dan da doğrulayabilirsiniz. coredns_dns_requests_total için increase fonksiyonu kullanarak son birkaç dakikadaki artışı görebilirsiniz.
Sonuç
CoreDNS metrik izlemesi, Kubernetes ortamlarında genellikle ihmal edilen ama kritik bir alan. DNS sorunları çoğunlukla “aralıklı bağlantı hatası” ya da “servis bazen erişilemiyor” gibi belirsiz şikayetlerle yüzeye çıkar ve metriklerin olmadığı ortamlarda saatlerce debug sürecine dönüşür.
Öncelik sıralaması yapmam gerekirse: önce prometheus plugin’ini aktive edin, sonra SERVFAIL oranı ve upstream sağlık alertlerini kurun. Dashboard güzel ama alertler hayat kurtarır. Cache hit oranı da sürekli gözlemlenmesi gereken bir metrik; düşük cache hit oranı genellikle yanlış yapılandırılmış TTL değerlerinin ya da aşırı dinamik DNS sorgularının işareti.
Recording rule’ları eklemek, uzun vadeli trend analizi için gerekli. Özellikle cluster büyüdükçe DNS yükünün nasıl arttığını görmek, kapasite planlaması için değerli bir girdi sağlıyor.
Son olarak şunu söyleyeyim: bu metrikleri kurmak bir saatinizi alır. Ama ilk DNS krizinde sizi saatlik debug maratonundan kurtardığında, o bir saatin ne kadar iyi yatırım olduğunu anlayacaksınız.
