CoreDNS ile DNS Tabanlı Yük Dengeleme ve Round-Robin Yapılandırması
DNS yük dengeleme deyince aklınıza ilk ne geliyor? Büyük ihtimalle HAProxy, Nginx ya da bulut sağlayıcıların load balancer servisleri geliyor. Ama işin ilginç yanı, DNS katmanında da son derece etkili bir yük dengeleme yapabilirsiniz ve bu iş için CoreDNS mükemmel bir araç. Üstelik Kubernetes ortamlarında zaten CoreDNS kullanıyorsanız, aynı aracı bare-metal veya VM tabanlı altyapınız için de değerlendirebilirsiniz. Bu yazıda CoreDNS ile DNS tabanlı round-robin yük dengeleme kurulumunu, gerçek dünya senaryolarıyla birlikte ele alacağız.
DNS Tabanlı Yük Dengeleme Nedir ve Ne Zaman Kullanılır?
Klasik yük dengeleme yaklaşımlarında bir ara katman (load balancer) vardır: istemci isteği buraya gelir, LB arkadaki sunuculardan birine yönlendirir. DNS tabanlı yük dengelemede ise bu iş DNS seviyesinde çözülür. Bir alan adına birden fazla A kaydı atarsınız, DNS sunucusu da her sorguya farklı bir IP döndürür.
Bu yaklaşımın avantajları var, dezavantajları da. Önce nerede işe yaradığına bakalım:
- Basit stateless servisler için idealdir. Web sunucuları, API endpoint’leri, CDN origin’leri gibi her node’un aynı yanıtı verebileceği durumlarda çok temiz çalışır.
- Ek bir infra bileşeni gerektirmez. HAProxy veya Nginx LB için ayrı bir VM ayağa kaldırmanıza gerek yok.
- Coğrafi dağıtım senaryolarında kullanışlıdır. Farklı bölgelerdeki sunuculara aynı hostname üzerinden ulaşmak istiyorsanız DNS’i kullanmak mantıklı.
- Kubernetes dışı ortamlarda hızlı bir çözüm sunar.
Dezavantajları ise şunlar:
- TTL sorunları: İstemciler DNS yanıtlarını cache’ler. Bir sunucu çöktüğünde istemciler TTL süresi boyunca o IP’ye gitmeye devam edebilir.
- Sağlık kontrolü yoktur (en azından temel konfigürasyonla). CoreDNS’in health plugin’i ile bunu kısmen çözebilirsiniz ama Layer 7 sağlık kontrolü yapmazsınız.
- Session persistence (sticky session) yoktur. Durum tutması gereken uygulamalarda sorun çıkarır.
Kısacası, bu yaklaşım “iyi yeterli” bir çözüm arıyorsanız ve hızlıca devreye almak istiyorsanız harika. Production’da kritik durum tutan servisler için tek başına yetmez.
CoreDNS Kurulumu
Önce CoreDNS’i sisteminize kuralım. Ubuntu/Debian ve RHEL/CentOS için ayrı adımlar var.
Ubuntu/Debian üzerinde kurulum:
# En güncel release'i çekelim
COREDNS_VERSION=$(curl -s https://api.github.com/repos/coredns/coredns/releases/latest | grep tag_name | cut -d '"' -f 4 | tr -d 'v')
wget https://github.com/coredns/coredns/releases/download/v${COREDNS_VERSION}/coredns_${COREDNS_VERSION}_linux_amd64.tgz
tar -xzf coredns_${COREDNS_VERSION}_linux_amd64.tgz
sudo mv coredns /usr/local/bin/
sudo chmod +x /usr/local/bin/coredns
# Versiyon kontrolü
coredns --version
Systemd servis dosyası oluşturalım:
sudo useradd -r -s /sbin/nologin coredns
sudo mkdir -p /etc/coredns
sudo tee /etc/systemd/system/coredns.service > /dev/null <<EOF
[Unit]
Description=CoreDNS DNS Server
Documentation=https://coredns.io
After=network.target
[Service]
User=coredns
ExecStart=/usr/local/bin/coredns -conf /etc/coredns/Corefile
Restart=on-failure
RestartSec=5s
LimitNOFILE=1048576
LimitNPROC=512
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable coredns
RHEL/CentOS tabanlı sistemlerde kurulum aynı şekilde işler, sadece paket yöneticisi farkı vardır. Binary indirme yöntemi her dağıtımda çalışır.
Temel Corefile Yapısı
CoreDNS’in kalbi Corefile adlı konfigürasyon dosyasıdır. Syntax’ı biraz kendine özgüdür ama anlaşılır. Önce basit bir örnek görelim:
sudo tee /etc/coredns/Corefile > /dev/null <<EOF
# Genel DNS zone tanımı
. {
# Upstream DNS sunucuları (Google ve Cloudflare)
forward . 8.8.8.8 1.1.1.1
# Cache ayarları (saniye cinsinden)
cache 30
# Log ayarları
log
# Hata yönetimi
errors
}
EOF
Bu temel konfigürasyon CoreDNS’i bir forwarding resolver olarak çalıştırır. Şimdi asıl konumuza geçelim.
Round-Robin Yük Dengeleme Konfigürasyonu
CoreDNS’in loadbalance plugin’i DNS yanıtlarındaki A, AAAA ve MX kayıtlarını shuffle eder. Yani her sorguya dönen IP sıralaması değişir. İşte bu basit mekanizma round-robin yük dengeleme sağlar.
Önce zone dosyamızı hazırlayalım. Diyelim ki internal.company.com adında bir internal domain’iniz var ve app.internal.company.com adresini 3 uygulama sunucusuna dağıtmak istiyorsunuz.
Zone dosyası oluşturma:
sudo tee /etc/coredns/zones/internal.company.com.db > /dev/null <<EOF
$ORIGIN internal.company.com.
$TTL 10
@ IN SOA ns1.internal.company.com. admin.company.com. (
2024010101 ; Serial
3600 ; Refresh
900 ; Retry
604800 ; Expire
60 ; Minimum TTL
)
; Name servers
@ IN NS ns1.internal.company.com.
; NS kaydı için A kaydı
ns1 IN A 192.168.1.10
; Uygulama sunucuları - aynı hostname'e birden fazla A kaydı
app IN A 192.168.1.101
app IN A 192.168.1.102
app IN A 192.168.1.103
; Veritabanı round-robin (okuma replika'ları için)
db-read IN A 192.168.1.201
db-read IN A 192.168.1.202
; API servisleri
api IN A 192.168.1.111
api IN A 192.168.1.112
api IN A 192.168.1.113
api IN A 192.168.1.114
EOF
sudo mkdir -p /etc/coredns/zones
Corefile’ı round-robin için güncelleyelim:
sudo tee /etc/coredns/Corefile > /dev/null <<EOF
# Internal zone - round-robin aktif
internal.company.com {
file /etc/coredns/zones/internal.company.com.db
# Kritik plugin: DNS yanıtlarını shuffle eder
loadbalance round_robin
# Düşük TTL - sunucu çöktüğünde hızlı geçiş için
# (cache ile çelişmesin diye dikkatli ayarlayın)
cache 10
log
errors
}
# Diğer tüm sorgular için upstream
. {
forward . 8.8.8.8 1.1.1.1 {
max_concurrent 1000
}
cache 300
log
errors
}
EOF
sudo systemctl start coredns
sudo systemctl status coredns
Konfigürasyonu Test Etme
Kurulumu tamamladıktan sonra gerçekten round-robin çalışıp çalışmadığını doğrulamanız gerekir. dig komutu burada en iyi arkadaşınız.
# Birkaç kez çalıştırıp yanıtların değişip değişmediğini izleyin
for i in {1..6}; do
echo "Sorgu $i:"
dig @192.168.1.10 app.internal.company.com A +short
echo "---"
done
# Daha detaylı çıktı için
dig @192.168.1.10 app.internal.company.com A +noall +answer
# TTL değerini kontrol edin
dig @192.168.1.10 app.internal.company.com A +ttlid
Başarılı bir çıktıda her sorguda IP’lerin sıralandığını göreceksiniz:
Sorgu 1: 192.168.1.101, 192.168.1.102, 192.168.1.103
Sorgu 2: 192.168.1.102, 192.168.1.103, 192.168.1.101
Sorgu 3: 192.168.1.103, 192.168.1.101, 192.168.1.102
İstemciler genellikle listenin ilk IP’sine bağlandığı için bu shuffle mekanizması yük dağılımını sağlar.
Gerçek Dünya Senaryosu: Mikroservis Altyapısı
Şimdi daha gerçekçi bir senaryo kuralım. Bir e-ticaret platformu yönetiyorsunuz. Aşağıdaki servisler var:
- 4 adet frontend web sunucusu
- 3 adet API gateway
- 2 adet image processing servisi
- 3 adet arama servisi (Elasticsearch)
sudo tee /etc/coredns/zones/prod.ecommerce.local.db > /dev/null <<EOF
$ORIGIN prod.ecommerce.local.
$TTL 15
@ IN SOA dns1.prod.ecommerce.local. ops.ecommerce.com. (
2024020101
3600
900
604800
30
)
@ IN NS dns1.prod.ecommerce.local.
dns1 IN A 10.0.0.5
; Frontend web sunucuları
frontend IN A 10.0.10.11
frontend IN A 10.0.10.12
frontend IN A 10.0.10.13
frontend IN A 10.0.10.14
; API Gateway'ler
api-gw IN A 10.0.20.11
api-gw IN A 10.0.20.12
api-gw IN A 10.0.20.13
; Image processing
img-proc IN A 10.0.30.11
img-proc IN A 10.0.30.12
; Elasticsearch cluster (sadece query node'ları)
search IN A 10.0.40.11
search IN A 10.0.40.12
search IN A 10.0.40.13
; CNAME örnekleri - alias oluşturma
www IN CNAME frontend
api IN CNAME api-gw
EOF
Gelişmiş Corefile konfigürasyonu:
sudo tee /etc/coredns/Corefile > /dev/null <<EOF
# Production e-commerce zone
prod.ecommerce.local {
file /etc/coredns/zones/prod.ecommerce.local.db
loadbalance round_robin
# Health check için prometheus metrikleri
prometheus :9153
# Sorgu log'u - production'da dikkatli kullanın, disk I/O yükler
log . {combined}
errors
# Cache: TTL'den fazla olmamalı
cache 10 {
success 512
denial 256
}
}
# Staging ortamı ayrı zone
staging.ecommerce.local {
file /etc/coredns/zones/staging.ecommerce.local.db
loadbalance round_robin
cache 5
log
errors
}
# Diğer iç domain'ler
ecommerce.local {
forward . 10.0.0.1
cache 60
errors
}
# External sorgular
. {
forward . 8.8.8.8 1.1.1.1 {
max_concurrent 1000
expire 10s
health_check 5s
}
cache 300
errors
}
EOF
Prometheus ile Monitoring Entegrasyonu
CoreDNS Prometheus metriklerini doğal olarak destekler. Bu metrikleri toplayarak yük dağılımını izleyebilirsiniz.
# Prometheus plugin için Corefile güncellemesi (zaten yukarıda ekledik)
# Metrikleri test edelim
curl -s http://localhost:9153/metrics | grep coredns_dns_requests_total
# Grafana dashboard için örnek PromQL sorguları
# Toplam sorgu sayısı
# rate(coredns_dns_requests_total[5m])
# Zone başına sorgu oranı
# rate(coredns_dns_requests_total{zone="prod.ecommerce.local."}[5m])
# Hata oranı
# rate(coredns_dns_responses_total{rcode="SERVFAIL"}[5m])
Basit bir sağlık kontrolü scripti yazalım. CoreDNS’in health plugin’i HTTP üzerinden /health endpoint’i sunar:
#!/bin/bash
# /usr/local/bin/coredns-healthcheck.sh
# Hem CoreDNS sağlığını hem de backend'lerin erişilebilirliğini kontrol eder
COREDNS_HOST="192.168.1.10"
DOMAIN="app.internal.company.com"
ALERT_EMAIL="[email protected]"
LOG_FILE="/var/log/coredns-health.log"
check_coredns_health() {
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/health)
if [ "$HTTP_STATUS" != "200" ]; then
echo "$(date): CoreDNS health check FAILED - HTTP $HTTP_STATUS" >> $LOG_FILE
echo "CoreDNS health check failed on $(hostname)" | mail -s "ALERT: CoreDNS Down" $ALERT_EMAIL
return 1
fi
return 0
}
check_dns_resolution() {
RESOLVED_IPS=$(dig @$COREDNS_HOST $DOMAIN A +short)
IP_COUNT=$(echo "$RESOLVED_IPS" | grep -c '^')
if [ "$IP_COUNT" -lt 1 ]; then
echo "$(date): DNS resolution FAILED for $DOMAIN" >> $LOG_FILE
return 1
fi
echo "$(date): DNS OK - $DOMAIN resolves to $IP_COUNT IPs: $RESOLVED_IPS" >> $LOG_FILE
return 0
}
check_backend_connectivity() {
RESOLVED_IPS=$(dig @$COREDNS_HOST $DOMAIN A +short)
for IP in $RESOLVED_IPS; do
if ! nc -z -w3 $IP 80 2>/dev/null; then
echo "$(date): Backend $IP:80 is NOT reachable!" >> $LOG_FILE
echo "Backend $IP unreachable for $DOMAIN" | mail -s "ALERT: Backend Down" $ALERT_EMAIL
fi
done
}
check_coredns_health
check_dns_resolution
check_backend_connectivity
Bu scripti crontab’a ekleyin:
chmod +x /usr/local/bin/coredns-healthcheck.sh
# Crontab'a ekle
(crontab -l 2>/dev/null; echo "*/2 * * * * /usr/local/bin/coredns-healthcheck.sh") | crontab -
TTL Optimizasyonu: Kritik Bir Konu
Round-robin yük dengelemede TTL ayarı çok önemlidir. Çok yüksek TTL, sunucu çöktüğünde istemcilerin o IP’ye gitmeye devam etmesine neden olur. Çok düşük TTL ise DNS sunucusuna aşırı yük bindirir.
Pratik öneriler:
- Kritik production servisleri: 10-30 saniye TTL. Cache süresi de aynı ya da daha kısa olmalı.
- Genel API endpoint’leri: 30-60 saniye TTL.
- Statik veya nadiren değişen servisler: 300 saniye (5 dakika) TTL yeterli.
- Acil failover senaryoları: 5 saniye bile kullanılabilir, ama DNS sunucunuz buna dayanıklı olmalı.
Zone dosyasında TTL’yi global ve kayıt bazında ayrı ayrı ayarlayabilirsiniz:
# Global TTL düşük ayarlanmış, kritik kayıtlar için
$TTL 15
; Bu kayıt global TTL'i kullanır (15s)
app IN A 192.168.1.101
app IN A 192.168.1.102
; Bu kayıt kendi TTL'ini belirler (300s) - statik servis
; mail 300 IN A 192.168.1.50
; Acil failover için çok düşük TTL
; emergency 5 IN A 192.168.1.200
CoreDNS Cluster Kurulumu: Yüksek Erişilebilirlik
Tek bir CoreDNS instance’ı SPOF (Single Point of Failure) oluşturur. Production için en az iki CoreDNS sunucusu çalıştırın. Aralarında Keepalived ile VIP (Virtual IP) kullanabilirsiniz.
# Keepalived kurulumu (her iki DNS sunucusunda)
sudo apt install keepalived -y
# Master DNS sunucusu (192.168.1.10) konfigürasyonu
sudo tee /etc/keepalived/keepalived.conf > /dev/null <<EOF
global_defs {
router_id DNS_MASTER
}
vrrp_script check_coredns {
script "curl -sf http://localhost:8080/health"
interval 3
weight -20
fall 3
rise 2
}
vrrp_instance VI_DNS {
state MASTER
interface eth0
virtual_router_id 51
priority 110
advert_int 1
authentication {
auth_type PASS
auth_pass dns_secret_2024
}
virtual_ipaddress {
192.168.1.9/24
}
track_script {
check_coredns
}
}
EOF
sudo systemctl enable keepalived
sudo systemctl start keepalived
Backup DNS sunucusunda state BACKUP ve priority 100 olarak ayarlayın.
Zone Reload ve Dinamik Güncelleme
Zone dosyasını değiştirdiğinizde CoreDNS’i yeniden başlatmak yerine sadece zone’u reload edebilirsiniz. auto plugin bunu otomatik yapar:
# Corefile'da auto plugin kullanımı
internal.company.com {
auto {
directory /etc/coredns/zones
reload 30s
}
loadbalance round_robin
cache 10
log
errors
}
Bu konfigürasyonla CoreDNS her 30 saniyede zone dosyasını kontrol eder ve değişiklik varsa servis kesintisi olmadan yükler. Yeni bir sunucu eklediğinizde sadece zone dosyasına A kaydı eklemek yeterli.
Manuel reload için ise:
# SIGUSR1 sinyali ile reload
sudo kill -SIGUSR1 $(pgrep coredns)
# Ya da systemctl ile
sudo systemctl reload coredns
# Zone değişikliğinden sonra serial numarasını güncellemeyi unutmayın
# SOA kaydındaki serial'ı artırın: 2024010101 -> 2024010102
Performans Tuning
CoreDNS’i production’da çalıştırırken bazı sistem ayarları yapmanız gerekir:
# /etc/sysctl.conf - network buffer'larını artır
sudo tee -a /etc/sysctl.conf > /dev/null <<EOF
# CoreDNS performans ayarları
net.core.rmem_max = 67108864
net.core.wmem_max = 67108864
net.core.netdev_max_backlog = 5000
net.ipv4.udp_mem = 65536 131072 262144
EOF
sudo sysctl -p
# CoreDNS için ulimit ayarları (systemd servis dosyasında zaten var)
# LimitNOFILE=1048576 - açık dosya limiti
# LimitNPROC=512 - process limiti
# Corefile'da concurrent limit ayarı
# forward . 8.8.8.8 {
# max_concurrent 1000
# }
Sonuç
CoreDNS ile DNS tabanlı round-robin yük dengeleme, özellikle şu durumlarda gerçekten değerli bir araç haline geliyor: Kubernetes olmayan ortamlarda hızlı bir yük dağıtımı mekanizmasına ihtiyaç duyduğunuzda, ekstra load balancer VM’i ayağa kaldırmak istemediğinizde ya da Kubernetes’in yanında hybrid bir altyapı yönetirken.
Hatırlatmak istediğim kritik noktalar şunlar: TTL değerinizi iş gereksinimlerinize göre ayarlayın ve cache sürenizi bununla uyumlu tutun. Backend sağlık kontrolünü CoreDNS tek başına yapmaz, bunu harici bir script ya da monitoring sistemiyle destekleyin. Production için mutlaka en az iki CoreDNS instance’ı çalıştırın ve aralarına Keepalived gibi bir VIP mekanizması koyun. Son olarak, Prometheus metriklerini Grafana’ya bağlayın, DNS katmanında ne olduğunu görmeden kör uçamazsınız.
DNS tabanlı yük dengeleme, “silver bullet” değil. Durum tutan uygulamalar, Layer 7 health check gereksinimleri veya sticky session ihtiyacı olan servisler için HAProxy ya da Nginx LB ile desteklemeniz gerekebilir. Ama doğru senaryoda, özellikle stateless mikroservisler için, CoreDNS ile elde edeceğiniz sadelik ve performans sizi gerçekten memnun edecek.
