CoreDNS Nedir: Cloud Native DNS Sunucusuna Giriş
Kubernetes cluster’ı ilk kurduğumda DNS olayını tam anlayamamıştım. kube-dns çalışıyor, pod’lar birbirini buluyor, herşey güzel. Ama bir gün production’da DNS sorguları aniden yavaşlamaya başladı, bazı sorgular zaman aşımına uğruyordu. O günden sonra CoreDNS’i ciddiye almaya başladım ve altında ne döndüğünü gerçekten anlamak istedim. Bu yazıda size CoreDNS’in ne olduğunu, neden bu kadar önem kazandığını ve nasıl çalıştığını anlatacağım.
CoreDNS Nedir ve Nereden Geldi
CoreDNS, Go diliyle yazılmış, plugin tabanlı bir DNS sunucusudur. 2016 yılında Miek Gieben tarafından başlatılan proje, 2017’de Cloud Native Computing Foundation (CNCF) bünyesine girdi ve 2019’da “graduated” statüsüne yükseldi. Bu statü, projenin production-ready olduğunun resmi onayı sayılır.
Kubernetes 1.11 sürümüyle birlikte CoreDNS, kube-dns’in yerini alarak varsayılan DNS çözümleyici haline geldi. Ama CoreDNS sadece Kubernetes için değil, bağımsız bir DNS sunucusu olarak da kullanılabilen genel amaçlı bir çözüm.
Peki neden yeni bir DNS sunucusuna ihtiyaç duyuldu? BIND yıllardır var, dnsmasq var, Unbound var. Bunlar yetmiyor muydu?
Sorun şu ki geleneksel DNS sunucuları monolitik yapıda. Bir özelliği değiştirmek istediğinizde kaynak koduna giriyorsunuz, derliyorsunuz, test ediyorsunuz. Cloud native dünyasının dinamik yapısına bu yaklaşım tam olarak uymuyordu. CoreDNS’in getirdiği temel yenilik şu: her şey bir plugin.
Plugin Mimarisi: CoreDNS’i Farklı Kılan Şey
CoreDNS’in kalbi Caddy web sunucusundan alınan plugin zincirine dayanıyor. Bir DNS sorgusu geldiğinde, bu sorgu sırayla tanımlanmış plugin’lerden geçiyor. Her plugin sorguya bir şey yapabilir, yapamayabilir ya da bir sonraki plugin’e bırakabilir.
Bir sorgunun yolculuğunu şöyle düşünebilirsiniz:
DNS Sorgusu -> cache plugin -> forward plugin -> upstream DNS
|
Cache'de varsa
direkt cevapla
Bu yaklaşım inanılmaz bir esneklik sağlıyor. Örneğin şu anda Kubernetes’te CoreDNS’in tipik bir Corefile’ı şöyle görünür:
.:53 {
errors
health {
lameduck 5s
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . /etc/resolv.conf {
max_concurrent 1000
}
cache 30
loop
reload
loadbalance
}
Bu dosyayı ilk gördüğünüzde kafa karıştırıcı görünebilir ama aslında çok okunabilir bir yapı. errors, health, ready, kubernetes, prometheus… her biri bir plugin ve her biri belirli bir işlevi yerine getiriyor.
Corefile Sözdizimi
CoreDNS’in konfigürasyon dosyası Corefile adını alır. Temel sözdizimi şöyle:
ZONE:PORT {
plugin1 [options]
plugin2 [options]
...
}
Zone tanımı hangi DNS sorgularının bu blok tarafından ele alınacağını belirliyor. Birden fazla zone tanımlayabilirsiniz:
example.com:53 {
file /etc/coredns/zones/example.com.db
log
errors
}
.:53 {
forward . 8.8.8.8 8.8.4.4
cache 300
log
errors
}
Burada example.com için yerel zone dosyası kullanılıyor, diğer tüm sorgular ise Google’ın DNS sunucularına iletiliyor. . notasyonu “her şey” anlamına geliyor.
Temel Plugin’lere Yakından Bakış
errors ve log Plugin’leri
.:53 {
errors
log
forward . 1.1.1.1
}
errors plugin’i hata mesajlarını standart çıktıya yazar. log ise her DNS sorgusunu loglar. Production ortamında log plugin’ini dikkatli kullanın, yüksek trafikteki ortamlarda ciddi disk I/O oluşturabilir.
cache Plugin’i
Cache, CoreDNS’in en değerli özelliklerinden biri. TTL değerlerine göre yanıtları bellekte tutuyor:
.:53 {
cache {
success 9984 3600
denial 9984 300
prefetch 10 1m 10%
}
forward . 1.1.1.1
}
- success 9984 3600: Başarılı yanıtlar için 9984 kayıt kapasitesi, maksimum 3600 saniye TTL
- denial 9984 300: NXDOMAIN gibi olumsuz yanıtlar için 9984 kayıt, 300 saniye TTL
- prefetch 10 1m 10%: Son 1 dakikada 10’dan fazla sorgulanmış kayıtları TTL dolmadan yenile
Production’da bu yazının başında anlattığım sorunu, cache konfigürasyonunu optimize ederek çözmüştük.
forward Plugin’i
Upstream DNS sunucularına yönlendirme için kullanılır:
.:53 {
forward . 1.1.1.1 1.0.0.1 8.8.8.8 {
max_concurrent 1000
health_check 5s
policy random
}
}
- max_concurrent 1000: Aynı anda maksimum 1000 eş zamanlı sorgu
- health_check 5s: Upstream sunucuların sağlığını 5 saniyede bir kontrol et
- policy random: Upstream sunucular arasında rastgele seçim yap (round_robin ve sequential alternatifleri de var)
kubernetes Plugin’i
Kubernetes ortamlarında servis keşfi için:
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods verified
upstream
fallthrough in-addr.arpa ip6.arpa
ttl 30
noendpoints
}
- pods verified: Pod IP’lerini doğrulayarak çöz
- fallthrough: Bu zone’da bulunamazsa bir sonraki plugin’e geç
- ttl 30: Kubernetes kayıtları için 30 saniye TTL
- noendpoints: Endpoint kayıtlarını yayımlama
CoreDNS Kurulumu
Bağımsız Kurulum (Binary)
# GitHub releases'tan en son versiyonu indir
wget https://github.com/coredns/coredns/releases/download/v1.11.1/coredns_1.11.1_linux_amd64.tgz
# Arşivi aç
tar -xzf coredns_1.11.1_linux_amd64.tgz
# Binary'yi uygun yere taşı
sudo mv coredns /usr/local/bin/
# Çalıştırma izni ver
sudo chmod +x /usr/local/bin/coredns
# Versiyon kontrolü
coredns --version
Systemd Servis Dosyası
sudo tee /etc/systemd/system/coredns.service > /dev/null <<EOF
[Unit]
Description=CoreDNS DNS server
Documentation=https://coredns.io
After=network.target
[Service]
PermissionsStartOnly=true
LimitNOFILE=1048576
LimitNPROC=512
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
NoNewPrivileges=true
User=coredns
WorkingDirectory=/etc/coredns
ExecStart=/usr/local/bin/coredns -conf /etc/coredns/Corefile
ExecReload=/bin/kill -SIGUSR1 $MAINPID
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
EOF
# Kullanıcı oluştur
sudo useradd -r -s /sbin/nologin coredns
# Konfigürasyon dizinini oluştur
sudo mkdir -p /etc/coredns
# Servisi aktif et
sudo systemctl daemon-reload
sudo systemctl enable coredns
sudo systemctl start coredns
Docker ile Hızlı Test
# Basit bir Corefile oluştur
cat > /tmp/Corefile << 'EOF'
.:53 {
forward . 1.1.1.1 8.8.8.8
cache 300
log
errors
health :8080
}
EOF
# Docker container başlat
docker run -d
--name coredns-test
-p 53:53/udp
-p 53:53/tcp
-p 8080:8080
-v /tmp/Corefile:/Corefile
coredns/coredns:1.11.1
-conf /Corefile
# Test sorgusu
dig @localhost google.com
# Health check
curl http://localhost:8080/health
Gerçek Dünya Senaryosu: Split-Horizon DNS
Split-horizon DNS, aynı domain adını iç ve dış ağlarda farklı IP’lerle çözümleme ihtiyacında kullanılır. Şirkette sıkça karşılaşılan bir senaryo:
# /etc/coredns/Corefile
# İç ağ için company.local zone'u
company.local:53 {
file /etc/coredns/zones/company.local.db
log
errors
}
# Dış DNS'e ihtiyaç duyan internal domainler için
aws.internal:53 {
forward . 169.254.169.253
cache 60
}
# Genel internet trafiği
.:53 {
forward . 1.1.1.1 1.0.0.1 {
policy round_robin
health_check 10s
}
cache {
success 10000 3600
denial 1000 300
}
errors
log . {
class error
}
}
Zone dosyası da şöyle olabilir:
# /etc/coredns/zones/company.local.db
$ORIGIN company.local.
$TTL 300
@ IN SOA ns1.company.local. admin.company.local. (
2024010101 ; serial
3600 ; refresh
900 ; retry
604800 ; expire
300 ) ; minimum TTL
IN NS ns1.company.local.
ns1 IN A 192.168.1.10
gitlab IN A 192.168.1.50
nexus IN A 192.168.1.51
jenkins IN A 192.168.1.52
*.apps IN A 192.168.1.100
Kubernetes’te CoreDNS Troubleshooting
Kubernetes’te DNS sorunları yaşıyorsanız, ilk bakmanız gereken yer CoreDNS logları:
# CoreDNS pod'larını bul
kubectl get pods -n kube-system -l k8s-app=kube-dns
# Log'lara bak
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=100
# CoreDNS ConfigMap'ini incele
kubectl get configmap coredns -n kube-system -o yaml
# DNS test pod'u başlat
kubectl run dns-test --image=busybox:1.35 --rm -it --restart=Never -- nslookup kubernetes.default
# CoreDNS metriklerini kontrol et
kubectl port-forward -n kube-system svc/kube-dns 9153:9153
curl http://localhost:9153/metrics | grep coredns_dns_requests_total
Sık karşılaşılan bir sorun: pod’lar dış adresleri çözemiyorsa ama cluster içi servisler çalışıyorsa, genellikle forward plugin’i veya node’daki /etc/resolv.conf konfigürasyonuyla ilgili bir problem vardır.
Prometheus ile Monitoring
CoreDNS, prometheus plugin’i sayesinde zengin metrikler sunuyor:
.:53 {
prometheus :9153
# diğer plugin'ler...
}
Dikkat etmeniz gereken önemli metrikler:
- coredns_dns_requests_total: Toplam sorgu sayısı (type ve rcode’a göre ayrılmış)
- coredns_dns_responses_total: Toplam yanıt sayısı
- coredns_cache_hits_total: Cache isabet sayısı
- coredns_cache_misses_total: Cache ıskalamalar
- coredns_forward_requests_total: Upstream’e iletilen sorgular
- coredns_forward_request_duration_seconds: Upstream yanıt süreleri
- coredns_panics_total: Bu metriğin sıfır olmasını istiyorsunuz, sıfırdan büyükse ciddi bir sorun var
Cache hit ratio şu şekilde hesaplanabilir: cache_hits / (cache_hits + cache_misses). Genel kural olarak bu oranın yüzde 80’in üzerinde olması istenir, altındaysa ya TTL değerlerinizi artırmanız ya da cache boyutunu büyütmenüz gerekiyor.
Performans Tuning
Yüksek yüklü ortamlarda CoreDNS’i optimize etmek için:
.:53 {
cache {
success 65536 3600
denial 8192 300
prefetch 10 60s 10%
}
forward . 1.1.1.1 1.0.0.1 {
max_concurrent 2000
health_check 5s
expire 10s
}
# UDP buffer boyutunu artır
bufsize 4096
errors
}
Ayrıca sistem tarafında da birkaç ayar yapmanızı öneririm:
# UDP buffer boyutlarını artır
sysctl -w net.core.rmem_max=134217728
sysctl -w net.core.wmem_max=134217728
# Kalıcı hale getir
cat >> /etc/sysctl.conf << EOF
net.core.rmem_max=134217728
net.core.wmem_max=134217728
EOF
CoreDNS vs BIND vs Unbound: Hangisini Seçmeli
Bu karşılaştırmayı tablo yerine somut durumlarla anlatmak daha doğru olur.
BIND seçin eğer:
- Çok karmaşık zone yönetimine ihtiyacınız varsa
- DNSSEC’i derinlemesine kullanmanız gerekiyorsa
- Ekibinizde BIND’a hakim kişiler varsa ve mevcut altyapınız BIND üzerine kurulu ise
Unbound seçin eğer:
- Sadece recursive resolver ihtiyacınız varsa
- Yüksek performanslı caching önceliğinizse
- Minimal footprint istiyorsanız
CoreDNS seçin eğer:
- Kubernetes veya container ortamında çalışıyorsanız, burada tercih değil zorunluluk
- Özel plugin geliştirme ihtiyacınız varsa
- Dynamic konfigürasyon değişikliklerine ihtiyaç duyuyorsanız
- Modern cloud native stack kuruyorsanız
Kendi tecrübelerimden söylüyorum: on-premise ortamlarda hala BIND kullanıyorum, ama Kubernetes cluster’larım için CoreDNS’ten başka bir seçenek düşünmüyorum bile.
Sonuç
CoreDNS, “DNS sunucusu” kavramını yeniden tanımlayan bir proje. Plugin mimarisi sayesinde ihtiyacınıza göre şekillendirilebiliyor, Kubernetes ile entegrasyonu birinci sınıf, monitoring desteği eksiksiz.
Ama şunu da söylemek gerekir: CoreDNS her ortam için doğru seçim değil. Karmaşık zone yönetimi gerektiren enterprise ortamlarda BIND hala daha yetenekli. CoreDNS’in gücü cloud native ekosistemde, dynamic service discovery’de ve Go dilinin getirdiği performans ile düşük bellek tüketiminde gizli.
Eğer Kubernetes kullanıyorsanız, CoreDNS zaten sisteminizde çalışıyor. Onu anlamak ve doğru konfigüre etmek, cluster’ınızın güvenilirliği için kritik. Cache ayarlarını optimize edin, Prometheus ile izleyin, sorun çıkmadan önce logları takip edin. DNS sorunları çoğunlukla başka bir şeyin belirtisi gibi görünür ama kaynağa inince DNS konfigürasyon hataları çıkar.
Bir sonraki yazıda CoreDNS plugin geliştirmeye bakacağız; kendi custom plugin’inizi Go ile nasıl yazarsınız, onu ele alacağız.
