CoreDNS und Kubernetes: Ein Überblick

14 Juli, 2025

Daniel Bodky
Daniel Bodky
Senior Platform Advocate

Daniel kam nach Abschluss seines Studiums im Oktober 2021 zu NETWAYS und beriet zwei Jahre lang Kunden zu den Themen Icinga2 und Kubernetes, bevor es ihn weiter zu Managed Services zog. Seitdem redet und schreibt er viel über cloud-native Technologien und ihre spannenden Anwendungsfälle und gibt sein Bestes, um Neues und Interessantes rund um Kubernetes zu vermitteln. Nebenher schreibt er in seiner Freizeit kleinere Tools für verschiedenste Einsatzgebiete, nimmt öfters mal ein Buch in die Hand oder widmet sich seinem viel zu großen Berg Lego. In der wärmeren Jahreszeit findet man ihn außerdem oft auf dem Fahrrad oder beim Wandern.

von | Juli 14, 2025

CoreDNS ist einer der unbesungenen Helden in Kubernetes. Es ist in fast jedem Kubernetes Setup zu finden und verrichtet seine Aufgaben unbemerkt und zuverlässig. Auch in NETWAYS Managed Kubernetes® ist es zu finden.
Daher war ich vor kurzem im Rahmen der Certified Kubernetes Administrator Prüfung überrascht, plötzlich selbst mit CoreDNS interagieren zu müssen. Grund genug, dessen Rolle in Kubernetes einmal etwas genauer unter die Lupe zu nehmen!

Was ist CoreDNS?

CoreDNS beschreibt sich auf seiner Website als DNS Server, geschrieben in Go. Seine Flexibilität erlaubt den Einsatz in verschiedensten Umgebungen, unter Anderem in Kubernetes. Es bietet Service Discovery basierend auf etcd, Kubernetes und den DNS-Lösungen der großen Cloudprovider, und ist durch sein Pluginsystem schnell und flexibel.

Serverblocks

Die grundlegende Einteilung in verschiedene Routingblöcke bilden in CoreDNS sogenannte Server Blocks. Diese sehen wie folgt aus:

coredns.io:5300 {
    file db.coredns.io
}

example.io:53 {
    log
    errors
    file db.example.io
}

example.net:53 {
    file db.example.net
}

.:53 {
    kubernetes
    forward . 8.8.8.8
    log
    errors
    cache
}
HCL

Für jeden in einem Server Block definierten Port erstellt CoreDNS einen Server, der die eingehenden DNS-Abfragen der Konfiguration entsprechend an den passenden Server Block weiterreicht. Das folgende Schaubild visualisiert die Server Blocks aus dem Beispiel aus CoreDNS‘ Sicht.

CoreDNS im Überblick
Die Server Blocks aus dem Beispiel werden von CoreDNS in verschiedene Routing-Flows übersetzt.

Hat CoreDNS die eingehende DNS-Abfrage einem Server Block zugeordnet, übernehmen die im jeweiligen Serverblock definierten Plugins die weitere Verarbeitung der Abfragen.

Plugins in CoreDNS

Die Vielzahl an Plugins bildet die Basis des DNS-Servers: Sie werden zur Buildtime in das ausführbare Programm eingebaut und stellen jegliche Funktionalität bereit. In Version 1.12.2 besteht die Binary für macOS beispielsweise aus 55 Plugins:

$ coredns -version
    CoreDNS-1.12.2
    darwin/arm64, go1.24.4,
  
$ coredns -plugins | wc -l
    55
Bash

Diese Plugins werden gechained, also quasi in Reihe geschaltet. Die Reihenfolge wird hierbei zur Buildtime durch eine Datei namens plugin.cfg vorgegeben. Die Version für die offiziell veröffentlichten Binaries findet sich auf GitHub.
Daraus ergibt sich, dass bei Hinzunahme weiterer Plugins ein Neubau des Programms inklusive eventuell notwendiger Anpassungen in plugin.cfg nötig wird.

Verhalten von Plugins in CoreDNS

Die verschiedenen Plugins erfüllen unterschiedliche Rollen und verhalten sich je nach Situation unterschiedlich. Für jede von CoreDNS empfangene DNS-Abfrage kann ein Plugin eine dieser vier Reaktionen zeigen:

  • Verarbeitung der Abfrage: Das Plugin verarbeitet die Abfrage, generiert die Antwort entsprechend der Funktion des Plugins, und sendet sie zurück an den Client.
  • Ignorieren der Abfrage: Stellt ein Plugin fest, dass es nicht für eine Abfrage zuständig ist, kann es diese auch ignorieren. In diesem Fall geht die Abfrage an das nächste Plugin der Pluginchain. Ist die Abfrage am Ende der Pluginchain angekommen und wird weiterhin ignoriert, antwortet CoreDNS dem Client mit SERVFAIL.
  • Verarbeitung der Abfrage mit Fallthrough: Grundsätzlich verhält sich das Plugin hier wie bei einer normalen Verarbeitung der Abfrage. Ist die durch das Plugin generierte Antwort allerdings nicht zufriedenstellend (z.B. NXDOMAIN), kann die Abfrage auch hier an das nächste Plugin der Pluginchain weitergegeben werden.
  • Verarbeitung der Abfrage mit Hinweis: Nicht jedes Plugin ist dafür zuständig, eine Antwort auf eine Abfrage zu generieren. Ein Beispiel hierfür ist das prometheus Plugin, das Metriken für Prometheus generiert. Es inspiziert die eingehende Abfrage, gibt diese aber immer an das nächste Plugin der Pluginchain weiter.

Zusätzlich gibt es sogenannte Unregistered Plugins, die sich nicht mit DNS-Abfragen befassen, sondern das Verhalten von CoreDNS selbst beeinflussen: bind, root, health und ready.

Nach dieser Einführung in die Funktionsweise von CoreDNS ist es nun an der Zeit, sich CoreDNS im Kubernetes-Kontext einmal genauer anzuschauen.

CoreDNS in Kubernetes

Für die folgenden Betrachtungen und Experimente nutze ich KinD, eine standardisierte Möglichkeit, ein Kubernetes Cluster lokal auf Docker aufzusetzen. Wenn du den Beispielen folgen möchtest, musst du diese Tools also auch auf deiner lokalen Maschine installieren.

Cluster Setup

Zuerst muss natürlich ein Cluster aufgesetzt werden. Das geschieht durch einen einzelnen KinD-Befehl, gefolgt von 1-3 Minuten Wartezeit:

kind create cluster --name coredns-lab
Bash

Ist das Cluster eingerichtet, kann man auch schon CoreDNS entdecken:

kubectl get pods -n kube-system

NAME                                                READY   STATUS    RESTARTS   AGE
coredns-674b8bbfcf-rdq5v                            1/1     Running   0          102s
coredns-674b8bbfcf-rr22p                            1/1     Running   0          102s
etcd-coredns-lab-control-plane                      1/1     Running   0          109s
kindnet-k9cb4                                       1/1     Running   0          102s
kube-apiserver-coredns-lab-control-plane            1/1     Running   0          109s
kube-controller-manager-coredns-lab-control-plane   1/1     Running   0          109s
kube-proxy-r6q84                                    1/1     Running   0          102s
kube-scheduler-coredns-lab-control-plane            1/1     Running   0          110s
Bash

Gut versteckt im kube-system Namespace verrichtet es neben anderen fundamentalen Workloads wie etcd, API-Server und Scheduler seinen Dienst. Doch welchen genau?

Um diese Frage zu beantworten, können wir uns die CoreDNS Konfiguration einmal genauer anschauen. In Kubernetes ist diese normalerweise als ConfigMap mit dem Namen coredns ebenfalls im Namespace kube-system hinterlegt.

Der CoreDNS Corefile in Kubernetes

kubectl get configmap -n kube-system coredns -o yaml

apiVersion: v1
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 {
           disable success cluster.local
           disable denial cluster.local
        }
        loop
        reload
        loadbalance
    }
kind: ConfigMap
metadata:
  creationTimestamp: "2025-07-09T14:38:11Z"
  name: coredns
  namespace: kube-system
  resourceVersion: "226"
  uid: b59a1656-04df-40bd-ae3c-b765dd184ba0
Bash

Unter data in der Ausgabe finden wir einen einzigen Eintrag mit dem Namen Corefile, der die CoreDNS Konfiguration beinhaltet. Im Corefile sehen wir die Definition eines einzigen Serverblocks (.:53), der sämtlche Anfragen auf dem Standardport annimmt. Die definierten Plugins mit entsprechenden Aufgaben sind für die Verarbeitung der eingehenden DNS-Abfragen zuständig.

Die Plugins errors, health, ready, prometheus, cache, loop, reload und loadbalance sind hierbei hauptsächlich für die Konfiguration von CoreDNS selbst verantwortlich. Sie stellen zum Beispiel Health- und Readiness-Endpoints für die Abfrage durch Kubernetes bereit, erlauben das Loggen von Fehlermeldungen, oder ermöglichen das Neuladen von Konfiguration ohne Neustart von CoreDNS.

Der tatsächlich für DNS-Abfragen relevante Teil der CoreDNS-Konfiguration in Kubernetes ist – wer hätte es gedacht – das kubernetes Plugin.

Das kubernetes Plugin

Die Konfiguration des kubernetes Plugins innerhalb des catch-all Server Blocks ermöglicht die Auflösung von Service- und Podadressen in Kubernetes. Schauen wir uns diesen Teil des Corefiles also noch einmal genauer an.

kubernetes cluster.local in-addr.arpa ip6.arpa {
    pods insecure
    fallthrough in-addr.arpa ip6.arpa
    ttl 30
}
Bash

Das Plugin ist so konfiguriert, dass es für DNS-Abfragen für die Domain cluster.local (das Standard-DNS-Suffix für Kubernetes Cluster) zuständig ist. Darüber hinaus versucht es, Reverse DNS-Abfragen für IPv4 (in-addr.arpa) und IPv6 (ip6.arpa) aufzulösen.
Im eigentlichen Konfigurationsblock des kubernetes Plugins sehen wir dann drei weitere Einstellungen:

  • pods insecure: Erlaubt Reverse DNS-Abfragen für sämtliche Pods, ohne Verifizierung, ob der gewünschte Pod tatsächlich existiert oder die IP anderweitig vergeben ist. Dieses Feature ist hauptsächlich als Rückwärtskompatibilität zu kube-dns gedacht. In der Praxis antwortet CoreDNS hierbei immer mit der in der Abfrage enthaltenen IP-Adresse:
    10.244.0.3.kube-system.pod.cluster.local IN A 10.244.0.3
  • fallthrough in-addr.arpa ip6.arpa: Für den Fall, dass ein Pod eine Reverse DNS-Abfrage für Dienste außerhalb des Clusters vornehmen möchte, ist ein Fallthrough definiert. Die DNS-Abfrage geht in diesem Fall an das nächste Plugin der Plugin-Chain. Andernfalls würde das kubernetes Plugin mit NXDOMAIN antworten.
    Im Fall unseres Corefiles wäre das nächste Plugin forward, das einen Lookup anhand der resolv.conf versuchen würde.
  • ttl 30: Für erfolgte Abfragen wird die Time to Live auf 30 Sekunden gesetzt. Das ist ein guter Kompromiss aus sinnvollem Caching und kurzen Reaktionszeiten, sollten sich Services oder Pods ändern.

Darüber hinaus gibt es weitere Konfigurationsmöglichkeiten – beispielsweise könnte CoreDNS auch außerhalb eines Clusters laufen und sich via API-Endpoint für Namensauflösungen mit diesem verbinden. Auch die Eingrenzung der DNS-Auflösungen auf einzelne Objekte oder Namespaces ist möglich. Eine vollständige Liste der Konfigurationsmöglichkeiten findet sich in der Dokumentation des kubernetes Plugins.

Beispiel 1: Hinzufügen einer weiteren Cluster-Domain

Wie im letzten Absatz bereits erwähnt, ist das Standard-DNS-Suffix für Kubernetes Cluster cluster.local. Dieses lässt sich bei Clusterinstallation für viele Kubernetes Distributionen anpassen. Hat man das vergessen oder möchte aus anderen Gründen ein weiteres gültiges Suffix einführen, geht das ganz einfach durch Anpassung des Corefiles im Cluster.

Zuerst öffnen wir die ConfigMap mit dem Corefile im Editierungsmodus:

kubectl edit configmap -n kube-system coredns
Bash

Im Anschluss fügen wir ein neues Suffix my.cluster zum kubernetes Block hinzu:

kubernetes my.cluster cluster.local in-addr.arpa ip6.arpa {
    pods insecure
    fallthrough in-addr.arpa ip6.arpa
    ttl 30
}
Bash

Da das reload Plugin ebenfalls konfiguriert ist, sollte CoreDNS die Konfiguration automatisch neu laden. Der Reload wird geloggt, wir können also zuschauen, wann die neue Konfiguration greift:

kubectl logs -n kube-system deploy/coredns -f

Found 2 pods, using pod/coredns-674b8bbfcf-rdq5v
maxprocs: Leaving GOMAXPROCS=8: CPU quota undefined
.:53
[INFO] plugin/reload: Running configuration SHA512 = 1b226df79860026c6a52e67daa10d7f0d57ec5b023288ec00c5e05f93523c894564e15b91770d3a07ae1cfbe861d15b37d4a0027e69c546ab112970993a3b03b
CoreDNS-1.12.0
linux/arm64, go1.23.3, 51e11f1
[INFO] Reloading
[INFO] plugin/reload: Running configuration SHA512 = cba5a092f893ab79c6f781e049eefe86ec640a8826a0df31b100ec96f4e446c6be8b2c8c7f6aea6ddebb4228cd022a7aacbc93ef7a0d38082dca4bb9d308c6fe
[INFO] Reloading complete
Bash

Ist der Reload erfolgt, sollten wir in der Lage sein, bspw. die Kubernetes API jetzt auch unter kubernetes.default.svc.my.cluster auflösen zu können:

kubectl run test-pod --image nginx
kubectl exec -it test-pod -- curl -v https://kubernetes.default.svc.my.cluster
*   Trying 10.96.0.1:443...
* Connected to kubernetes.default.svc.my.cluster (10.96.0.1) port 443 (#0)
* ALPN: offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Request CERT (13):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (OUT), TLS alert, unknown CA (560):
* SSL certificate problem: unable to get local issuer certificate
* Closing connection 0
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
command terminated with exit code 60
Bash

Die DNS-Abfrage funktioniert. Die IP des Kubernetes Services wird korrekt aufgelöst.

Beispiel 2: Beschränkung des DNS-Services auf einzelne Namespaces

Für das zweite Beispiel wollen wir die Auflösung von DNS-Abfragen im Cluster auf den Namespace default beschränken. Auf diese Weise kann bspw. der Service der Kubernetes API weiterhin aufgelöst werden, während Abfragen für Dienste in anderen Namespaces fehlschlagen.

Hierzu editieren wir erneut den Corefile von CoreDNS und fügen der Konfiguration des kubernetes Plugins einen namespaces Eintrag hinzu.

kubectl edit configmap -n kube-system coredns
Bash
kubernetes my.cluster cluster.local in-addr.arpa ip6.arpa {
    pods insecure
    fallthrough in-addr.arpa ip6.arpa
    ttl 30
    namespaces default
}
Bash

Wir können erneut zuschauen, wie die Konfiguration von CoreDNS neu geladen wird:

kubectl logs -n kube-system deploy/coredns -f
Bash

Im Anschluss können wir erneut mit unserem test-pod die Wirksamkeit der Konfiguration testen:

kubectl exec -it test-pod -- curl -v https://kubernetes.default.svc.my.cluster
*   Trying 10.96.0.1:443...
* Connected to kubernetes.default.svc.my.cluster (10.96.0.1) port 443 (#0)
...

kubectl exec -it test-pod -- curl -v https://kube-dns.kube-system.svc.my.cluster
* Could not resolve host: kube-dns.kube-system.svc.my.cluster
* Closing connection 0
curl: (6) Could not resolve host: kube-dns.kube-system.svc.my.cluster
command terminated with exit code 6
Bash

Wie erwartet kann der kubernetes Service weiterhin aufgelöst werden, da er sich im Namespace default befindet. Der Service kube-dns im Namespace kube-system hingegen kann nun nicht mehr aufgelöst werden.

Fazit

CoreDNS verrichtet in nahezu jedem Kubernetes-Cluster seine Arbeit leise und zuverlässig. So zuverlässig, dass man es im Alltag oft kaum wahrnimmt. Doch gerade in dieser Unauffälligkeit liegt seine Stärke: Es bildet das Rückgrat für DNS-Auflösungen im Cluster und ermöglicht damit essenzielle Funktionen wie Service Discovery und Kommunikation zwischen Pods und Services.

Dieser Blogpost zeigt, dass sich ein genauer Blick auf CoreDNS lohnen kann. Nicht nur zur Vorbereitung auf Zertifizierungen wie den CKA, sondern vor allem, um das Verhalten des eigenen Clusters besser zu verstehen und gezielt zu optimieren. Egal ob zusätzliche Cluster-Domains, Einschränkungen auf bestimmte Namespaces oder das Tuning des DNS-Caches: CoreDNS bietet dank seines modularen Aufbaus und der Plugin-basierten Architektur eine beeindruckende Flexibilität.

Wenn du noch mehr rund um CoreDNS ausprobieren oder nachlesen möchtest, ist hier noch einmal der Link zur CoreDNS Dokumentation. Und wenn diese Ressourcen nicht ausreichen oder noch Fragen offen sind, stehen unsere MyEngineers® dir jederzeit mit Rat und Tat zur Seite.

Unser Portfolio

0 Kommentare

Einen Kommentar abschicken

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Wie hat Dir unser Artikel gefallen?