Unbound DNS Sunucusunda Monitoring ve Alerting: Prometheus ve Grafana ile İzleme
DNS altyapınızın ne durumda olduğunu bilmeden sistemi yönetmek, arabasının gösterge panelini bantla kapatıp sürmek gibidir. Unbound DNS sunucunuz çalışıyor olabilir, ama kaç sorgu işliyor, cache hit oranı ne, yanıt süreleri normal mi? Bu sorulara cevap veremiyorsanız, bu yazı tam size göre.
Bu rehberde Unbound DNS sunucusunu Prometheus ile nasıl izleyeceğinizi, Grafana’da anlamlı dashboard’lar nasıl oluşturacağınızı ve kritik eşiklere ulaşıldığında nasıl alert alacağınızı adım adım anlatacağım. Küçük bir şirket altyapısından kurumsal ortama kadar uygulanabilir, gerçek dünya odaklı bir rehber olacak.
Neden Unbound Monitoring Gerekli?
Unbound, varsayılan olarak oldukça sessiz çalışır. Bir şeyler ters gidene kadar fark etmezsiniz, ta ki kullanıcılar “internet çalışmıyor” diye gelene kadar. Oysa DNS sorunları çoğunlukla ani değil, yavaş yavaş ortaya çıkar:
- Cache hit oranı düşmeye başlar, sorgular yavaşlar
- Upstream resolver’lara bağlantı sorunları olur, timeout’lar artar
- Sorgu sayısı anormal yükselir, DDoS veya misconfiguration işareti olabilir
- Memory kullanımı giderek artar, restart gerekmeden yakalanması gerekir
Monitoring olmadan bunların hiçbirini önceden yakalayamazsınız. Prometheus + Grafana kombinasyonu, Unbound için mükemmel bir izleme çözümü sunar.
Ortam ve Ön Gereksinimler
Bu rehberde şu ortamı varsayıyorum:
- OS: Ubuntu 22.04 LTS (Debian tabanlı her sistemde benzer şekilde çalışır)
- Unbound: 1.17+
- Prometheus: 2.45+
- Grafana: 10.x
- Unbound ve Prometheus/Grafana aynı sunucuda veya aynı ağda
Unbound kurulu ve çalışıyor olduğunu varsayıyorum. Eğer kurmadıysanız önce temel kurulumu tamamlayın.
Unbound’da İstatistik Toplama Aktif Etme
Her şeyden önce Unbound’un istatistik üretmesini sağlamamız gerekiyor. Unbound, unbound-control stats komutuyla çok detaylı metrik verir, ama bunun için remote-control modülünün aktif olması şart.
/etc/unbound/unbound.conf.d/stats.conf dosyası oluşturun:
sudo nano /etc/unbound/unbound.conf.d/stats.conf
İçine şunları yazın:
server:
# İstatistik toplama aktif
statistics-interval: 0
statistics-cumulative: yes
extended-statistics: yes
remote-control:
control-enable: yes
control-interface: 127.0.0.1
control-port: 8953
control-use-cert: yes
server-key-file: "/etc/unbound/unbound_server.key"
server-cert-file: "/etc/unbound/unbound_server.pem"
control-key-file: "/etc/unbound/unbound_control.key"
control-cert-file: "/etc/unbound/unbound_control.pem"
statistics-cumulative: yes ayarı önemli. Bu sayede metrikler sıfırlanmadan birikimli olarak tutulur, Prometheus’un zaten delta hesapladığını düşünürsek bu daha sağlıklı sonuç verir.
Şimdi TLS sertifikalarını oluşturalım:
sudo unbound-control-setup
Bu komut otomatik olarak gerekli key ve sertifikaları /etc/unbound/ altına oluşturur. Ardından Unbound’u yeniden başlatın:
sudo systemctl restart unbound
sudo unbound-control stats_noreset | head -20
Çıktıda thread0.num.queries, total.num.cachehits gibi satırlar görüyorsanız istatistikler çalışıyor demektir.
Prometheus Exporter Kurulumu
Unbound için en olgun exporter unbound_exporter‘dır. GitHub’da letsencrypt/unbound_exporter projesi aktif olarak geliştirilmektedir.
Exporter’ı Binary Olarak Kurmak
# Son sürümü indir
wget https://github.com/letsencrypt/unbound_exporter/releases/download/v0.4.6/unbound_exporter-0.4.6.linux-amd64.tar.gz
# Çıkart ve yerleştir
tar xzf unbound_exporter-0.4.6.linux-amd64.tar.gz
sudo mv unbound_exporter-0.4.6.linux-amd64/unbound_exporter /usr/local/bin/
sudo chmod +x /usr/local/bin/unbound_exporter
# Dedicated kullanıcı oluştur
sudo useradd -rs /bin/false unbound_exporter
Systemd Service Dosyası
sudo nano /etc/systemd/system/unbound_exporter.service
[Unit]
Description=Unbound Prometheus Exporter
After=network.target unbound.service
Wants=unbound.service
[Service]
User=unbound_exporter
Group=unbound_exporter
Type=simple
ExecStart=/usr/local/bin/unbound_exporter
--unbound.host=tcp://127.0.0.1:8953
--unbound.ca=/etc/unbound/unbound_server.pem
--unbound.cert=/etc/unbound/unbound_control.pem
--unbound.key=/etc/unbound/unbound_control.key
--web.listen-address=:9167
--web.telemetry-path=/metrics
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
Exporter’ın Unbound sertifikalarını okuyabilmesi için izin vermemiz gerekiyor:
sudo usermod -aG unbound unbound_exporter
sudo chmod 640 /etc/unbound/unbound_control.key
sudo chgrp unbound /etc/unbound/unbound_control.key
sudo systemctl daemon-reload
sudo systemctl enable --now unbound_exporter
sudo systemctl status unbound_exporter
Metriklerin geldiğini doğrulayın:
curl -s http://localhost:9167/metrics | grep unbound_
unbound_query_total, unbound_cache_hits_total, unbound_answer_rcode_total gibi metrikler görüyorsanız exporter düzgün çalışıyor.
Prometheus Yapılandırması
Prometheus’un zaten kurulu olduğunu varsayıyorum. Eğer yoksa apt install prometheus ile kurabilirsiniz veya binary kurulumu tercih edebilirsiniz.
/etc/prometheus/prometheus.yml dosyasına unbound job’ını ekleyin:
scrape_configs:
# Mevcut job'larınız...
- job_name: 'unbound'
static_configs:
- targets: ['localhost:9167']
labels:
instance: 'dns-01'
environment: 'production'
scrape_interval: 15s
scrape_timeout: 10s
metrics_path: /metrics
Birden fazla DNS sunucunuz varsa targets’ı genişletebilirsiniz:
- job_name: 'unbound'
static_configs:
- targets:
- 'dns-01.internal:9167'
- 'dns-02.internal:9167'
labels:
environment: 'production'
relabel_configs:
- source_labels: [__address__]
target_label: instance
regex: '([^:]+)(?::d+)?'
replacement: '${1}'
Prometheus’u yeniden yükleyin:
sudo systemctl reload prometheus
Prometheus UI’da (genellikle port 9090) Status > Targets bölümünde unbound target’ının UP durumda olduğunu görmelisiniz.
Grafana Dashboard Oluşturma
Grafana’da anlamlı bir Unbound dashboard’u oluşturmak için hangi metriklerin önemli olduğunu bilmek gerekiyor.
Önemli Unbound Metrikleri
- unbound_query_total: Toplam sorgu sayısı (rate ile kullanın)
- unbound_cache_hits_total: Cache’den karşılanan sorgular
- unbound_cache_misses_total: Cache’de bulunamayan sorgular
- unbound_answer_rcode_total: NOERROR, NXDOMAIN, SERVFAIL gibi yanıt kodları
- unbound_memory_cache_bytes: Cache bellek kullanımı
- unbound_memory_mod_bytes: Modül bellek kullanımı
- unbound_time_up_seconds_total: Sunucu uptime
- unbound_query_duration_seconds: Sorgu yanıt süresi histogram’ı
- unbound_prefetch_count_total: Prefetch yapılan kayıt sayısı
Temel Panel Sorguları
Grafana’da yeni bir dashboard oluşturun ve şu panelleri ekleyin.
Panel 1: Sorgu Hızı (QPS)
rate(unbound_query_total{job="unbound"}[5m])
Bu panel saniyedeki sorgu sayısını gösterir. Ani artışlar dikkat gerektiren durumlardır.
Panel 2: Cache Hit Oranı
rate(unbound_cache_hits_total{job="unbound"}[5m])
/
(rate(unbound_cache_hits_total{job="unbound"}[5m]) + rate(unbound_cache_misses_total{job="unbound"}[5m]))
* 100
Bu değerin %70’in altına düşmesi sorun işaretidir. Sağlıklı bir DNS sunucusunda cache hit oranı %80-90 civarında olmalıdır.
Panel 3: SERVFAIL Oranı
rate(unbound_answer_rcode_total{job="unbound", rcode="SERVFAIL"}[5m])
/
rate(unbound_query_total{job="unbound"}[5m])
* 100
Panel 4: Bellek Kullanımı
unbound_memory_cache_bytes{job="unbound"} + unbound_memory_mod_bytes{job="unbound"}
Grafana Dashboard JSON Import
Grafana topluluk dashboard’ları için grafana.com/dashboards adresinde Unbound için hazır dashboard’lar bulabilirsiniz. Dashboard ID 11705 iyi bir başlangıç noktasıdır, ancak kendi ortamınıza göre özelleştirmenizi öneririm.
Alerting Kuralları
İzlemenin en kritik parçası alerting. Prometheus’ta alert rule’ları tanımlar, Alertmanager ile bildirimleri yönetirsiniz.
/etc/prometheus/rules/unbound.yml dosyası oluşturun:
groups:
- name: unbound_alerts
interval: 30s
rules:
# DNS sunucusu erişilemiyor
- alert: UnboundDown
expr: up{job="unbound"} == 0
for: 1m
labels:
severity: critical
team: infrastructure
annotations:
summary: "Unbound DNS sunucusu erişilemiyor"
description: "{{ $labels.instance }} - Unbound exporter'a 1 dakikadır ulaşılamıyor. DNS servisi çalışmıyor olabilir."
runbook: "https://wiki.internal/runbooks/unbound-down"
# Yüksek SERVFAIL oranı
- alert: UnboundHighServfailRate
expr: |
(
rate(unbound_answer_rcode_total{rcode="SERVFAIL"}[5m])
/
rate(unbound_query_total[5m])
) * 100 > 5
for: 5m
labels:
severity: warning
annotations:
summary: "Yüksek SERVFAIL oranı tespit edildi"
description: "{{ $labels.instance }} sunucusunda SERVFAIL oranı {{ $value | printf "%.2f" }}% seviyesinde. Upstream resolver'larda sorun olabilir."
# Düşük cache hit oranı
- alert: UnboundLowCacheHitRate
expr: |
(
rate(unbound_cache_hits_total[10m])
/
(rate(unbound_cache_hits_total[10m]) + rate(unbound_cache_misses_total[10m]))
) * 100 < 60
for: 15m
labels:
severity: warning
annotations:
summary: "Cache hit oranı kritik seviyenin altında"
description: "{{ $labels.instance }} - Cache hit oranı {{ $value | printf "%.1f" }}%. Normal değer >70% olmalıdır. Cache boyutunu artırmayı değerlendirin."
# Anormal yüksek sorgu sayısı
- alert: UnboundHighQueryRate
expr: rate(unbound_query_total[5m]) > 10000
for: 5m
labels:
severity: warning
annotations:
summary: "Anormal yüksek DNS sorgu oranı"
description: "{{ $labels.instance }} - Saniyede {{ $value | printf "%.0f" }} sorgu işleniyor. Olası DNS amplification saldırısı veya misconfigured client."
# Yüksek bellek kullanımı
- alert: UnboundHighMemoryUsage
expr: |
(unbound_memory_cache_bytes + unbound_memory_mod_bytes) / 1024 / 1024 > 512
for: 10m
labels:
severity: warning
annotations:
summary: "Unbound bellek kullanımı yüksek"
description: "{{ $labels.instance }} - Unbound {{ $value | printf "%.0f" }} MB bellek kullanıyor."
Prometheus’a bu dosyayı tanıtın:
# prometheus.yml içine ekleyin
rule_files:
- "rules/unbound.yml"
- "rules/*.yml"
Kural syntax’ını kontrol edin:
promtool check rules /etc/prometheus/rules/unbound.yml
sudo systemctl reload prometheus
Alertmanager Yapılandırması
Alert’lerin Slack ve email ile gelmesi için Alertmanager konfigürasyonu:
global:
smtp_smarthost: 'smtp.company.com:587'
smtp_from: '[email protected]'
smtp_auth_username: '[email protected]'
smtp_auth_password: 'sifre'
route:
group_by: ['alertname', 'instance']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receiver: 'default'
routes:
- match:
severity: critical
receiver: 'critical-alerts'
repeat_interval: 1h
- match:
severity: warning
receiver: 'warning-alerts'
receivers:
- name: 'default'
email_configs:
- to: '[email protected]'
- name: 'critical-alerts'
email_configs:
- to: '[email protected], [email protected]'
subject: '[CRITICAL] {{ .GroupLabels.alertname }}'
slack_configs:
- api_url: 'https://hooks.slack.com/services/XXXXX'
channel: '#alerts-critical'
title: 'CRITICAL: {{ .GroupLabels.alertname }}'
text: '{{ range .Alerts }}{{ .Annotations.description }}{{ end }}'
- name: 'warning-alerts'
slack_configs:
- api_url: 'https://hooks.slack.com/services/XXXXX'
channel: '#alerts-warning'
Gerçek Dünya Senaryosu: Upstream Sorununu Erken Yakalamak
Bir gün ofis saatleri başlamadan sabah 07:30’da UnboundHighServfailRate alertı geldi. SERVFAIL oranı %12’ye çıkmıştı. Grafana’ya bakıldığında görüldü ki cache miss oranı da aynı anda artmış, yani önbelleğe alınmış kayıtlar süresi dolmaya başlamış, upstream’e giden sorgular hata dönüyordu.
Unbound log’larına bakınca upstream olarak kullanılan ISP’nin recursive resolver’larında sorun olduğu anlaşıldı. Monitoring olmasaydı, kullanıcılar geldiğinde “sabahtan beri internet çalışmıyor” diye şikayet edecekti. Alert sayesinde kullanıcılar gelmeden önce upstream resolver’lar değiştirildi ve sorun kapatıldı.
Bunu mümkün kılan şey şu Grafana paneliydi: SERVFAIL rate ile cache miss rate’i aynı grafikte görmek, korelasyonu anında ortaya koyuyordu.
Log Tabanlı Monitoring ile Tamamlamak
Prometheus metrikleri sayısal olayları izler, ama bazen log’lara da bakmanız gerekir. Loki + Promtail kombinasyonu ile Unbound log’larını da Grafana’ya çekebilirsiniz.
Unbound’da query logging aktif etmek için:
server:
verbosity: 1
log-queries: yes
log-replies: yes
log-tag-queryreply: yes
Dikkat: Production ortamında log-queries çok yüksek disk yazma üretebilir. Yüksek trafikli sunucularda bu ayarı sadece debug gerektiğinde açın veya rate limiting uygulayın.
Dashboard İçin İpuçları
Grafana dashboard’ınızı daha kullanışlı hale getirmek için birkaç öneri:
- Time range: Default olarak son 1 saati gösterin, haftalık trend için “last 7 days” preset ekleyin
- Annotation’lar: Unbound restart zamanlarını annotation olarak ekleyin, metrik değişikliklerini restart’larla ilişkilendirmek kolaylaşır
- Variable’lar: Birden fazla DNS sunucunuz varsa instance için Grafana variable tanımlayın, tek dashboard’dan tüm sunucuları izleyin
- Alert panel’leri: Dashboard’un üstüne alert durumlarını gösteren stat panel’ler ekleyin, tek bakışta durum anlaşılsın
Sonuç
Unbound’u kurmak bir saatlik iş, ama monitoring olmadan onu gözü kapalı yönetiyorsunuz demektir. Prometheus exporter kurulumu, birkaç alert kuralı ve bir Grafana dashboard ile DNS altyapınız şeffaf hale gelir. Sabah iş başlarken dashboard’a bir bakış, gün boyunca kafanızın rahat olmasını sağlar.
Bu yazıda anlattığım yapı temel bir başlangıç noktası. Zamanla kendi ortamınızın normal değerlerini öğreneceksiniz, alert eşiklerini buna göre fine-tune edeceksiniz. Özellikle cache hit oranı için kendi ortamınızdaki baseline’ı bulun, %60 çok düşük olan bir ortamda %75 de kabul edilebilir olmayabilir.
DNS izleme sistemini kurduktan sonra bir sonraki adım olarak Unbound’un DNSSEC doğrulama hatalarını da takip etmeyi, RPZ (Response Policy Zone) istatistiklerini eklemeyi düşünebilirsiniz. DNS altyapısı ne kadar görünür olursa, sorunları o kadar erken ve az stresle çözebilirsiniz.
