Wat CoreDNS doet in een Kubernetes-cluster
CoreDNS verving kube-dns als standaard cluster-DNS-server vanaf Kubernetes 1.11. Het draait als Deployment in kube-system, meestal met 2 replica's op afzonderlijke nodes voor beschikbaarheid. Een Service met de naam kube-dns (bewaard voor backward compatibility) stelt CoreDNS beschikbaar achter een stabiel ClusterIP, doorgaans 10.96.0.10 afhankelijk van je service-CIDR.
De kubelet vult bij het starten van elke pod de /etc/resolv.conf:
nameserver 10.96.0.10
search <namespace>.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
Alle DNS-queries vanuit pods lopen via CoreDNS. De verantwoordelijkheden: Kubernetes-servicenamen resolven naar cluster-IP's, reverse-DNS serveren voor clusterresources, en niet-clusterqueries forwarden naar upstream-resolvers.
CoreDNS blijft gesynchroniseerd met het cluster door de API-server te watchen op Service-, EndpointSlice-, Namespace- en (optioneel) Pod-objecten. Wanneer een nieuwe Service wordt aangemaakt, ziet CoreDNS die binnen enkele seconden via deze watches en begint meteen DNS-records te serveren, zonder herstart.
Hoe een DNS-query verloopt
Pod (/etc/resolv.conf → nameserver 10.96.0.10)
└─ iptables DNAT (kube-proxy)
└─ CoreDNS-pod
├── cluster.local? → kubernetes-plugin (API-watchcache)
└── extern? → forward-plugin → upstream-resolver
Het ClusterIP van de kube-dns Service wordt door kube-proxy-regels geDNATed naar een van de CoreDNS-pod-IP's. CoreDNS checkt de query tegen zijn zoneconfiguratie. Cluster-interne namen worden beantwoord vanuit de in-memory cache die de kubernetes-plugin opbouwt. Al het andere gaat door naar de forward-plugin.
Opbouw van de Corefile
De Corefile is het configuratiebestand van CoreDNS. In Kubernetes leeft het in de coredns ConfigMap in kube-system:
kubectl get configmap coredns -n kube-system -o yaml
Server blocks en zones
De Corefile werkt met server blocks. Elk blok declareert een of meer DNS-zones, een optionele poort, en plugin-directives tussen accolades:
[SCHEME://]ZONE [:PORT] {
PLUGIN [ARGUMENTEN]
}
De standaard Kubernetes Corefile:
.: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
cache 30
loop
reload
loadbalance
}
Het .:53-blok behandelt alle zones (. is de DNS-root) op poort 53. Meerdere server blocks zijn toegestaan; bij een binnenkomende query wint het blok met de langst matchende zone.
Twee dingen om te weten: de reload-plugin pollt de SHA512-checksum van de ConfigMap elke ~30 seconden en herlaadt bij wijzigingen (geen pod-herstart nodig, maar propagatie kan tot 2 minuten duren). En {$ENV_VAR}-syntax maakt environment-variable-substitutie mogelijk bij het parsen.
Plugin-keten: uitvoeringsvolgorde
Dit is het belangrijkste concept van de Corefile. De volgorde van pluginnamen in de Corefile bepaalt niet de uitvoeringsvolgorde. CoreDNS heeft een compile-time plugin.cfg die een vaste verwerkingsvolgorde definieert. Je kunt cache voor forward zetten of erna; de uitvoeringsvolgorde is identiek.
Voor de standaard Kubernetes-build is de relevante volgorde:
errors(vangt foutresponses op)log(querylogging, als ingeschakeld)rewrite(transformeert queries)hosts(statische hosttabel-lookups)kubernetes(autoritatief voor clusterzones)autopath(zoekpadoptimalisatie, als ingeschakeld)forward(upstream-proxy)cache(response-caching)loop(forwardingloopdetectie)loadbalance(round-robin van A/AAAA-records)
Elke plugin serveert ofwel een response (en stopt de keten) of roept de volgende plugin aan via fallthrough. Als niets de query serveert, retourneert CoreDNS SERVFAIL.
Belangrijke plugins
| Plugin | Wat het doet |
|---|---|
kubernetes |
Autoritatief voor cluster.local, in-addr.arpa, ip6.arpa. Watcht de API-server op Services, EndpointSlices, Pods. |
forward |
Proxyt niet-clusterqueries naar upstream-resolvers. Ondersteunt UDP, TCP en DNS-over-TLS. Maximaal 15 upstreams. |
cache |
In-memory responsecache. Standaardcapaciteit: 9984 entries. Aparte TTL's voor succesvolle en NXDOMAIN-responses. |
errors |
Logt foutresponses naar stdout. |
health |
HTTP /health op poort 8080. De lameduck 5s-directive vertraagt shutdown zodat lopende queries kunnen finishen. |
ready |
HTTP /ready op poort 8181. Retourneert 200 alleen als alle plugins ready melden. Gebruikt door de readiness-probe. |
prometheus |
Stelt Prometheus-metrics beschikbaar op poort 9153 (/metrics). Standaard ingeschakeld. |
loop |
Detecteert DNS-forwardingloops (bijv. CoreDNS → systemd-resolved → terug naar CoreDNS) en stopt het proces. |
reload |
Herlaadt de Corefile als de ConfigMap wijzigt. |
loadbalance |
Randomiseert de recordvolgorde in A/AAAA/MX-responses voor round-robin-distributie. |
Service-DNS-records
CoreDNS genereert verschillende recordtypen afhankelijk van de Service-configuratie. De Kubernetes DNS-specificatie definieert deze patronen.
Normale services (ClusterIP)
Een query voor my-api.production.svc.cluster.local retourneert een enkel A-record dat naar het ClusterIP van de Service wijst. De client praat met het VIP; kube-proxy regelt de routing naar pods.
Headless services
Een headless Service (clusterIP: None) heeft geen VIP. Dezelfde DNS-naam retourneert meerdere A-records, een per Ready pod-IP. Clients ontvangen alle pod-IP's en moeten zelf selecteren.
Voor StatefulSets krijgt elke pod een individueel record:
postgres-0.postgres.db.svc.cluster.local → pod-0's IP
postgres-1.postgres.db.svc.cluster.local → pod-1's IP
postgres.db.svc.cluster.local → alle pod-IP's
Het patroon is <pod-naam>.<service-naam>.<namespace>.svc.<cluster-domain>. Deze per-pod-records bestaan alleen wanneer een headless Service matcht met de spec.subdomain van de pod.
SRV-records
Worden aangemaakt voor named ports op zowel normale als headless Services:
_http._tcp.my-api.production.svc.cluster.local → 8080 my-api.production.svc.cluster.local
ExternalName-services
Een Service met type: ExternalName levert een CNAME-record op:
legacy-db.production.svc.cluster.local CNAME rds.us-east-1.amazonaws.com
Geen VIP, geen kube-proxy-regels. De client resolvet het CNAME via normale DNS-recursie.
Aangepaste DNS-configuratie
Stub domains
Een stub domain routeert queries voor een specifiek DNS-suffix naar een toegewijde nameserver in plaats van de upstream. In CoreDNS is dit een extra server block in de Corefile. Bewerk de ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
data:
Corefile: |
.: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
}
consul.local:53 {
errors
cache 30
forward . 10.150.0.1
}
internal.corp:53 {
errors
cache 30
forward . 192.168.1.53
}
Een beperking: de forward-plugin vereist IP-adressen voor upstream-nameservers. FQDN's zoals ns.corp.example.com werken niet.
Eigen upstream-resolvers
Vervang de standaard forward . /etc/resolv.conf door expliciete IP's om CoreDNS los te koppelen van de node-level resolverconfiguratie:
forward . 8.8.8.8 8.8.4.4 {
max_fails 3
health_check 5s
policy random
}
Voor DNS-over-TLS-forwarding:
forward . tls://9.9.9.9 tls://149.112.112.112 {
tls_servername dns.quad9.net
health_check 5s
force_tcp
}
Statische hostoverrides
De hosts-plugin mapt vaste IP's naar hostnamen, handig voor on-premises databases of legacyservices zonder DNS-records:
hosts {
10.0.1.100 mydb.internal.example.com
192.168.5.5 legacy-api.corp.local
fallthrough
}
De fallthrough-directive stuurt niet-gematchte namen door naar de volgende plugin.
NodeLocal DNSCache
NodeLocal DNSCache is een Kubernetes-add-on (DaemonSet) die een CoreDNS-cache op elke node draait. GA sinds Kubernetes 1.18.
Het probleem dat het oplost
Zonder NodeLocal DNSCache reizen pod-DNS-queries via iptables-DNAT naar een CoreDNS-pod die op een andere node kan zitten. Bij hoge DNS-load veroorzaakt dit drie problemen:
- Conntrack-tabeldruk. UDP-entries hebben geen connection-close-events en moeten uitvallen na een timeout (standaard 30 seconden). Bij hoge queryratio's raakt de conntrack-tabel vol en worden pakketten gedropt.
- DNAT-races. Gelijktijdige DNS-queries met dezelfde connection-tuple racen in de conntrack-tabel, een bekend Linux-kernelprobleem dat intermitterende 5-seconden timeouts veroorzaakt.
- Cross-node latency. Elke cachemiss vereist een netwerk-roundtrip naar een CoreDNS-pod op een andere node.
Voor het diagnosticeren van conntrack-gerelateerde DNS-storingen, zie Kubernetes DNS-problemen oplossen.
Hoe het werkt
Zonder NodeLocal DNSCache:
Pod → iptables DNAT → kube-dns VIP → CoreDNS-pod (mogelijk andere node)
Met NodeLocal DNSCache:
Pod → 169.254.20.10 (link-local, node-lokaal) → node-local-dns DaemonSet-pod
├── cluster.local cachemiss → TCP → kube-dns VIP → CoreDNS
└── externe cachemiss → upstream-nameservers
De init-container van de DaemonSet voegt een link-local IP (169.254.20.10 standaard) toe aan het lo-interface van de node. Dit niet-routeerbare adres zorgt ervoor dat pods de lokale cache bereiken zonder het netwerk over te hoeven. Cachemisses voor cluster.local worden over TCP geforward (niet UDP), wat expliciete conntrack-close-events oplevert en de conntrack-racecondition volledig elimineert.
In IPVS kube-proxy-modus moet de kubelet worden geconfigureerd met --cluster-dns=169.254.20.10 zodat pods geboren worden met de lokale cache als nameserver. In iptables-modus (de standaard) zijn er geen kubelet-wijzigingen nodig; de DaemonSet onderschept verkeer bestemd voor het kube-dns-VIP op nodeniveau.
Geheugenoverwegingen
Als de node-local-dns pod OOMKilled wordt, blijven de aangepaste iptables-regels actief en worden queries gestuurd naar een nu afwezig proces. DNS faalt op die node totdat de DaemonSet-controller de pod herstart. Stel geheugenlimieten royaal in of gebruik VPA in recommender-modus. De standaardcache bevat ongeveer 10.000 entries (~30 MB).
Performancetuning
De ndots:5-overhead
Met ndots:5 genereert een pod die api.github.com opvraagt (2 dots) vier DNS-queries voordat hij resolvet:
api.github.com.app.svc.cluster.local(NXDOMAIN)api.github.com.svc.cluster.local(NXDOMAIN)api.github.com.cluster.local(NXDOMAIN)api.github.com(succes)
In high-QPS-omgevingen is 75% van de DNS-queries gegarandeerd falen. Drie mitigatie-opties:
Verlaag ndots per pod (het best voor workloads met veel externe calls):
spec:
dnsConfig:
options:
- name: ndots
value: "2"
Trailing dots in applicatieconfiguratie forceren absolute resolutie en slaan de search-domain-expansie helemaal over:
api_endpoint: "api.github.com."
De autopath-plugin (server-side mitigatie) onderschept de eerste search-expanded query, detecteert de namespace van de pod, en retourneert het absolute antwoord in een enkele roundtrip. Het vereist pods verified-modus in de kubernetes-plugin, wat het geheugenverbruik ongeveer 4x verhoogt per Pod/Service-object:
- Zonder autopath:
(Pods + Services) / 1000 + 54 MB - Met autopath:
(Pods + Services) / 250 + 56 MB
Cachetuning
De standaard cache 30 stelt een maximale TTL van 30 seconden in met 9984 entries. Voor meer controle:
cache {
success 9984 3600 5 # capaciteit, max TTL, min TTL
denial 9984 30 5 # NXDOMAIN-responses: kortere TTL
prefetch 10 1m 10% # populaire entries verversen voor expiry
serve_stale 1h immediate # verlopen entries serveren als upstream down is
}
De prefetch-directive vernieuwt proactief entries die minstens 10 keer zijn opgevraagd in een 1-minutenvenster en waarvan de TTL onder 10% is gezakt. serve_stale biedt veerkracht tijdens upstream-storingen door verlopen cache-entries te serveren gedurende maximaal de opgegeven duur.
Replica's schalen
CoreDNS is CPU-bound. Een CPU-gebaseerde HPA is de aanbevolen schaalaanpak:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: coredns
namespace: kube-system
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: coredns
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
Draai altijd minstens 2 replica's met pod anti-affinity om single-node-failures te overleven. De Cluster Proportional Autoscaler (schalen op node-/core-aantallen) is een alternatief, maar CPU-gebaseerde HPA past beter bij CoreDNS omdat de bottleneck CPU is, niet het aantal connecties.
Een waarschuwing over resourcelimieten: vaste CPU-limieten veroorzaken throttling die zich manifesteert als DNS-latencypieken. Sommige operators verwijderen CPU-limieten helemaal en vertrouwen op CPU-requests voor scheduling. Monitor container_cpu_throttled_seconds_total voor de CoreDNS-pods.
Belangrijke metrics om te monitoren
CoreDNS stelt Prometheus-metrics beschikbaar op poort 9153 via de prometheus-plugin.
| Wat je wilt zien | PromQL |
|---|---|
| Querysnelheid | rate(coredns_dns_requests_total[5m]) |
| NXDOMAIN-ratio (ndots-overheadsignaal) | rate(coredns_dns_responses_total{rcode="NXDOMAIN"}[5m]) |
| P99 latency | histogram_quantile(0.99, rate(coredns_dns_request_duration_seconds_bucket[5m])) |
| Cache-hitratio | sum(rate(coredns_cache_hits_total[5m])) / (sum(rate(coredns_cache_hits_total[5m])) + sum(rate(coredns_cache_misses_total[5m]))) |
| Upstream health-failures | rate(coredns_forward_healthcheck_failures_total[5m]) |
Een hoge NXDOMAIN-ratio ten opzichte van totale queries is een sterk signaal dat ndots:5-overhead je DNS-verkeer domineert. Zie Kubernetes DNS-problemen oplossen voor stapsgewijze diagnose wanneer deze metrics op een probleem wijzen.
Wat CoreDNS niet is
CoreDNS is geen general-purpose recursive resolver. Het voert standaard geen volledige DNSSEC-validatie uit (hoewel er een dnssec-plugin bestaat). Het fungeert niet als autoritatieve nameserver voor externe zones zonder extra configuratie. En het vervangt de DNS-infrastructuur van je organisatie niet; het zit ervoor als cluster-scoped caching forwarder voor alles buiten cluster.local.
CoreDNS is ook niet kube-dns, ondanks de kube-dns-Servicenaam. kube-dns was een architectuur van drie containers (dnsmasq + kubedns + sidecar) met configuratie verspreid over meerdere flags en ConfigMap-keys. CoreDNS is een enkele binary met een uniforme Corefile-configuratie. De Servicenaam is gewoon een backward-compatibility-artefact.
Verder lezen
- Kubernetes DNS-problemen oplossen behandelt stapsgewijs het diagnosticeren van DNS-fouten: CrashLoopBackOff, ndots-query-explosie, conntrack-races, dnsPolicy-misconfiguratie en upstream-resolverproblemen.
- Kubernetes Services uitgelegd behandelt Service-typen, kube-proxy-modi en hoe verkeer van een Service-VIP naar pod-endpoints stroomt.