CoreDNS ile Kubernetes Service Discovery Nasıl Yapılır?
Kubernetes cluster’ında bir pod başka bir servise ulaşmaya çalıştığında arka planda neler döndüğünü hiç merak ettiniz mi? “Sadece servis adını yazıyorum, çalışıyor” diyip geçiyoruz çoğu zaman. Ama bu büyünün arkasında CoreDNS var ve prodüksiyon ortamında bir şeyler ters gittiğinde “sadece çalışıyor” demek yetmiyor. Bu yazıda CoreDNS’i gerçekten anlamak, doğru yapılandırmak ve sorunları çözmek üzerine konuşacağız.
CoreDNS Nedir ve Neden Önemlidir
Kubernetes 1.13’ten itibaren CoreDNS, kube-dns’in yerini alarak cluster içi DNS çözümlemenin standart bileşeni haline geldi. Go ile yazılmış, plugin tabanlı bir DNS sunucusu. Ama asıl önemli olan şu: Kubernetes’teki her servis keşfi, her pod-to-pod iletişimi, her dış kaynak erişimi bu bileşenden geçiyor. CoreDNS çöktüğünde veya yanlış yapılandırıldığında tüm cluster iletişimi durma noktasına geliyor.
CoreDNS’in plugin mimarisi sayesinde davranışını son derece esnek biçimde şekillendirebiliyorsunuz. Corefile adı verilen yapılandırma dosyasıyla hem hangi plugin’lerin çalışacağını hem de her birinin nasıl davranacağını kontrol ediyorsunuz.
Kubernetes’te CoreDNS’in Çalışma Mekanizması
Bir pod içinde /etc/resolv.conf dosyasına baktığınızda şöyle bir şey görürsünüz:
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
Bu nameserver adresi CoreDNS servisinin ClusterIP’sidir. search satırları ise kısa adlarla (örneğin sadece my-service) tam nitelikli domainlere (FQDN) ulaşmanızı sağlayan arama alanlarıdır.
ndots:5 ayarı çok kritik bir detay. Bir hostname içinde 5’ten az nokta varsa, DNS istemcisi önce arama listesindeki domainleri deniyor, başarısız olursa mutlak domain olarak sorguluyor. Bu ayar yanlış anlaşıldığında gereksiz DNS sorgularına ve latency artışlarına yol açıyor. Bunu ilerleyen bölümlerde daha ayrıntılı ele alacağız.
Servis keşfi için DNS kayıt formatları şu şekilde işliyor:
- Normal servisler:
..svc.cluster.local - Headless servisler:
...svc.cluster.local - Pod’lar (doğrudan):
..pod.cluster.local
CoreDNS Kurulumu ve Mevcut Durumu Kontrol Etmek
Eğer kubeadm ile cluster kurduysanız CoreDNS büyük ihtimalle zaten çalışıyordur. Durumu kontrol edelim:
kubectl get pods -n kube-system -l k8s-app=kube-dns
kubectl get deployment coredns -n kube-system
kubectl get configmap coredns -n kube-system -o yaml
CoreDNS’in hangi versiyonunu çalıştırdığınızı ve mevcut Corefile yapılandırmanızı görmek için:
kubectl describe configmap coredns -n kube-system
Eğer CoreDNS yoksa veya sıfırdan kurmak istiyorsanız, kubectl ile manifest uygulayabilirsiniz. Ancak gerçek hayatta çoğunlukla mevcut yapılandırmayı düzenlemek veya sorun gidermek söz konusu oluyor.
Corefile Yapılandırması: Gerçekten Anlamak
CoreDNS’in kalbi Corefile’dır. Varsayılan Corefile şuna benzer:
.: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
}
Her plugin ne yapıyor, tek tek bakalım:
- errors: Hataları stdout’a loglar
- health:
/healthendpoint’i açar, liveness probe için kullanılır - ready:
/readyendpoint’i açar, readiness probe için kullanılır - kubernetes: Kubernetes servis ve pod kayıtlarını çözümler
- prometheus: Metrikleri
:9153portunda açar - forward: Cluster dışı sorgular için upstream DNS’e yönlendirir
- cache: DNS yanıtlarını önbelleğe alır (TTL saniye cinsinden)
- loop: DNS döngülerini tespit eder
- reload: Corefile değişikliklerini otomatik algılar
- loadbalance: Birden fazla A kaydı varsa round-robin uygular
Kubernetes Plugin’ini Derinlemesine İncelemek
pods insecure ayarı pod IP’lerini doğrulama yapmadan DNS’e kaydeder. pods verified daha güvenli ama daha yavaş. Prodüksiyonda güvenlik politikalarınıza göre bu ayarı değerlendirmenizi öneririm.
fallthrough direktifi çok önemli: Kubernetes plugin’i bir kaydı bulamazsa sorguyu bir sonraki plugin’e iletir. in-addr.arpa ve ip6.arpa için bu gerekli çünkü reverse DNS sorguları bazen cluster dışına çıkması gerekiyor.
Özel DNS Yapılandırma Senaryoları
Şirket İçi Domain’leri CoreDNS’e Eklemek
Sahadan bir örnek: Şirketinizin iç DNS sunucusunda internal.company.com domain’i var ve cluster içindeki pod’ların bu adreslere ulaşması gerekiyor. Bunun için stub zone yapılandırması kullanıyorsunuz:
kubectl edit configmap coredns -n kube-system
Corefile’a şu bloğu ekleyebilirsiniz:
internal.company.com:53 {
errors
cache 30
forward . 192.168.1.53 192.168.1.54
}
Bu yapılandırmayla internal.company.com altındaki tüm sorgular şirket DNS sunucularınıza iletilir. ConfigMap’i düzenledikten sonra reload plugin’i değişikliği otomatik algılar, CoreDNS’i restart etmenize gerek kalmaz. Ama emin olmak için pod’ları gözlemleyin:
kubectl logs -f -l k8s-app=kube-dns -n kube-system
Split-Horizon DNS Yapılandırması
Bazı şirketlerin hem iç hem dış DNS’te aynı domain adları var ama farklı IP’lere işaret ediyor. Bu durumda şöyle bir Corefile yapısı kuruyorsunuz:
example.com:53 {
errors
cache 30
forward . 10.0.0.53 {
prefer_udp
}
}
.:53 {
errors
health
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . 8.8.8.8 8.8.4.4
cache 30
loop
reload
loadbalance
}
DNS Performans Sorunlarını Çözmek
ndots Sorunu ve Çözümü
Bahsettiğim ndots:5 ayarı prodüksiyonda ciddi latency artışına yol açabilir. Diyelim ki pod’unuz api.external.com‘a istek atıyor. DNS istemcisi sırayla şunları deniyor:
api.external.com.default.svc.cluster.localapi.external.com.svc.cluster.localapi.external.com.cluster.localapi.external.com.(mutlak)
İlk üç sorgu başarısız olacak ve 3 gereksiz DNS roundtrip yapacaksınız. Bunu çözmek için pod spec’inizde DNS yapılandırmasını override edebilirsiniz:
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
dnsConfig:
options:
- name: ndots
value: "2"
containers:
- name: my-app
image: my-app:latest
ndots:2 ile dış domain’lere yapılan sorgular çok daha hızlı çözülecek. Ama dikkat: Eğer uygulamanız cluster içi servisleri kısa adıyla çağırıyorsa (örneğin sadece my-service), bu ayarla sorun yaşayabilirsiniz. Cluster içi çağrılar için her zaman tam FQDN kullanmak en sağlıklı yaklaşım.
CoreDNS Cache Ayarlarını Optimize Etmek
Yoğun DNS trafiği olan ortamlarda cache süresini artırmak sorgu sayısını drastik biçimde azaltır:
.:53 {
errors
health
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
cache {
success 9984 300
denial 9984 5
prefetch 10
}
forward . /etc/resolv.conf
loop
reload
loadbalance
}
- success 9984 300: Başarılı yanıtları 300 saniye önbelleğe al, maksimum 9984 kayıt
- denial 9984 5: NXDOMAIN yanıtlarını 5 saniye önbelleğe al
- prefetch 10: 10 kez sorgulanmış kayıtları TTL dolmadan önce yenile
denial cache’i düşük tutmak önemli. Bir servis henüz hazır değilken gelen NXDOMAIN yanıtı uzun süre cache’de kalırsa, servis hazır olduğunda bile pod’lar onu bulamaz.
CoreDNS’i Scale Etmek
Büyük cluster’larda tek CoreDNS deployment’ı yeterli gelmiyor. Önce mevcut replica sayısını kontrol edelim:
kubectl get deployment coredns -n kube-system
Replica sayısını artırmak için:
kubectl scale deployment coredns --replicas=4 -n kube-system
Ama bunu otomatik hale getirmek daha iyi. HorizontalPodAutoscaler kullanabilirsiniz, ama DNS gibi kritik bir bileşen için cluster-proportional-autoscaler daha yaygın tercih:
apiVersion: apps/v1
kind: Deployment
metadata:
name: coredns-autoscaler
namespace: kube-system
spec:
replicas: 1
selector:
matchLabels:
k8s-app: coredns-autoscaler
template:
metadata:
labels:
k8s-app: coredns-autoscaler
spec:
containers:
- name: autoscaler
image: registry.k8s.io/cpa/cluster-proportional-autoscaler:1.8.4
command:
- /cluster-proportional-autoscaler
- --namespace=kube-system
- --configmap=coredns-autoscaler
- --target=deployment/coredns
- --default-params={"linear":{"coresPerReplica":256,"nodesPerReplica":16,"min":2}}
- --logtostderr=true
Bu yapılandırmayla CoreDNS replika sayısı node ve CPU çekirdeği sayısına göre otomatik ayarlanır.
DNS Sorun Giderme: Sahadan Notlar
Prodüksiyonda sık karşılaştığım senaryolar ve çözümleri:
Pod DNS’i Çözemiyor
İlk kontrol: Pod içinden DNS çözümlemesini test et.
kubectl run dns-test --image=busybox:1.28 --rm -it --restart=Never -- nslookup kubernetes.default
Eğer bu çalışmıyorsa CoreDNS pod’larının durumuna bakın:
kubectl get pods -n kube-system -l k8s-app=kube-dns -o wide
kubectl logs <coredns-pod-name> -n kube-system
Upstream DNS Sorunlarını Debug Etmek
CoreDNS’in upstream DNS sunucularına ulaşıp ulaşamadığını test etmek için:
kubectl run dns-debug --image=infoblox/dnstools --rm -it --restart=Never -- /bin/bash
Pod içinde:
dig @10.96.0.10 google.com
dig @10.96.0.10 kubernetes.default.svc.cluster.local
Cluster DNS’i çalışıyor ama dış adresler çözümlenemiyorsa sorun forward plugin’inde veya node’ların upstream DNS’e erişiminde.
CoreDNS Log Seviyesini Artırmak
Geçici debug için log plugin’ini Corefile’a ekleyebilirsiniz. Ama dikkat: Prodüksiyonda bu ciddi log hacmi üretiyor ve performansı etkiliyor. Kısa süreli tutun:
kubectl edit configmap coredns -n kube-system
errors satırının altına log ekleyin:
.:53 {
errors
log
health
...
}
Sonra CoreDNS log’larını izleyin:
kubectl logs -f -l k8s-app=kube-dns -n kube-system --max-log-requests 10
Sorunu tespit ettikten sonra log direktifini kaldırmayı unutmayın.
Metrics ile CoreDNS’i İzlemek
Prometheus entegrasyonu varsa CoreDNS metrikleri :9153/metrics endpoint’inden geliyor. Kritik metrikler:
- coredns_dns_requests_total: Toplam istek sayısı
- coredns_dns_responses_total: Yanıt kodlarına göre toplam yanıt
- coredns_forward_requests_total: Upstream’e iletilen istekler
- coredns_cache_hits_total / coredns_cache_misses_total: Cache performansı
Grafana’da izlemek için ServiceMonitor ekleyebilirsiniz:
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: coredns
namespace: kube-system
labels:
app: coredns
spec:
selector:
matchLabels:
k8s-app: kube-dns
namespaceSelector:
matchNames:
- kube-system
endpoints:
- port: metrics
interval: 15s
path: /metrics
Cache hit oranı %80’in altına düşüyorsa cache boyutunu veya TTL süresini artırmayı düşünün. coredns_dns_responses_total metriğinde SERVFAIL artışı varsa upstream DNS sorununu araştırın.
NodeLocal DNSCache: Bir Sonraki Seviye
Büyük ve yoğun cluster’lar için NodeLocal DNSCache çok etkili bir çözüm. Her node üzerinde bir DNS cache daemon çalıştırarak pod’ların CoreDNS pod’larına değil, kendi node’larındaki local cache’e gitmesini sağlıyor. Bu hem latency’yi düşürüyor hem de CoreDNS üzerindeki yükü azaltıyor.
NodeLocal DNSCache’i etkinleştirmek için DaemonSet deploy etmeniz gerekiyor. Cluster’ınızın kubeadm ile kurulduğunu varsayarak:
wget https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dns/nodelocaldns/nodelocaldns.yaml
Dosyada __PILLAR__DNS__SERVER__, __PILLAR__LOCAL__DNS__ ve __PILLAR__DNS__DOMAIN__ değerlerini cluster’ınıza göre değiştirin. CoreDNS ClusterIP’yi almak için:
kubectl get service kube-dns -n kube-system -o jsonpath='{.spec.clusterIP}'
Bu değerleri YAML dosyasında güncelledikten sonra:
kubectl apply -f nodelocaldns.yaml
NodeLocal DNSCache aktif olduğunda pod’ların resolv.conf‘undaki nameserver 169.254.20.10 (link-local adres) olacak şekilde güncellenir.
Güvenlik Açısından CoreDNS
DNS, güvenlik açısından sıklıkla göz ardı edilen bir bileşen. Birkaç kritik nokta:
Pod’ların CoreDNS’e erişimini NetworkPolicy ile kontrol edebilirsiniz. Aşağıdaki policy yalnızca belirli namespace’lerin DNS sorgularına izin verir:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns-access
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
Ayrıca CoreDNS’in kendisini güncel tutmak kritik. DNS amplification saldırıları ve cache poisoning saldırılarına karşı güncel versiyon kullanın. loop plugin’i DNS döngülerini tespit ederek CoreDNS’in kendi kendine sorgu gönderip askıda kalmasını önlüyor, varsayılan Corefile’da bu plugin mutlaka olsun.
Sonuç
CoreDNS, Kubernetes’in sessiz kahramanlarından biri. Düzgün çalıştığında kimse fark etmiyor, bozulduğunda ise tüm cluster ayağa kalkıyor. Bu yazıda ele aldığımız konuları özetlemek gerekirse: Corefile yapılandırmasını gerçekten anlamak, stub zone ve split-horizon senaryolarını bilmek, ndots sorununu çözmek, cache’i doğru optimize etmek ve metriklerle izlemek prodüksiyonda karşınıza çıkacak sorunların büyük çoğunluğunu bertaraf ediyor.
NodeLocal DNSCache’i henüz kullanmıyorsanız ve yoğun DNS trafiğiniz varsa, bunu denemek için iyi bir dönem. CoreDNS metriklerini Prometheus ve Grafana’ya bağlamak da kör noktaları ortadan kaldırıyor, sorunları reaktif değil proaktif yakalayabiliyorsunuz.
Son bir not: Corefile değişikliklerini her zaman önce staging ortamında test edin. reload plugin’i harika ama yanlış bir yapılandırma tüm DNS çözümlemesini durdurabilir. Özellikle stub zone eklerken veya forward direktifini değiştirirken dikkatli olun.
