Aller au contenu
Conteneurs & Orchestration medium

CoreDNS, DNS interne de Kubernetes

22 min de lecture

CoreDNS est le DNS par défaut de Kubernetes depuis la version 1.13. Il permet aux Pods de résoudre les noms de Services (my-service.my-namespace.svc.cluster.local) en adresses IP ClusterIP. Sans DNS fonctionnel, la communication inter-Pods par nom de Service ne fonctionne pas.

Ce guide couvre CoreDNS pour la certification CKA, où le dépannage DNS représente une compétence clé du domaine Troubleshooting (30%).

  • Comment fonctionne la résolution DNS dans Kubernetes
  • La syntaxe des noms de Services (service.namespace.svc.cluster.local)
  • Comment configurer CoreDNS via le Corefile
  • Les techniques de dépannage DNS pour la CKA
  • Les erreurs courantes et leurs solutions

Kubernetes attribue des adresses IP éphémères : un Pod recréé change d'IP, un Service en change à chaque suppression. Le DNS interne est la couche d'indirection qui rend cette instabilité invisible aux applications, en associant un nom stable à l'adresse du moment. CoreDNS est le composant qui produit et sert ces enregistrements, à partir des objets Service et Endpoints de l'API Kubernetes.

Trois éléments distincts interviennent, et les confondre complique le dépannage : le fichier /etc/resolv.conf injecté dans chaque Pod par le kubelet, le Service kube-dns qui porte une ClusterIP fixe, et les Pods CoreDNS qui répondent réellement aux requêtes. Le nom kube-dns du Service est un héritage historique : il pointe bien vers CoreDNS.

┌─────────────────────────────────────────────────────────────────┐
│ Cluster Kubernetes │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Pod A │ │ Pod B │ │ Pod C │ │
│ │ │ │ │ │ │ │
│ │ /etc/resolv │ │ /etc/resolv │ │ /etc/resolv │ │
│ │ nameserver │ │ nameserver │ │ nameserver │ │
│ │ <DNS_IP> │ │ <DNS_IP> │ │ <DNS_IP> │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
│ └────────────────────┼────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Service DNS │ │
│ │ kube-dns │ │
│ │ 10.96.0.10:53 │ │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ CoreDNS Pods │ │
│ │ (Deployment) │ │
│ └─────────────────┘ │
│ │
└───────────────────────────────────────────────────────────────────┘

Suivre une requête de bout en bout donne la carte des points de panne possibles : chacune des cinq étapes ci-dessous peut échouer indépendamment, et le dépannage consiste précisément à déterminer laquelle. Retenez que CoreDNS ne stocke rien : il lit l'état de l'API Kubernetes et le traduit en réponses DNS.

Quand un Pod veut contacter my-service.default.svc.cluster.local :

  1. Le Pod lit /etc/resolv.confnameserver <IP du Service kube-dns>
  2. La requête DNS part vers le Service kube-dns (souvent 10.96.0.10 sur kubeadm)
  3. CoreDNS reçoit la requête via le plugin kubernetes qui publie les enregistrements DNS à partir des objets Kubernetes (Services, Endpoints)
  4. CoreDNS renvoie l'adresse ClusterIP du Service
  5. Le Pod peut maintenant contacter le Service

Kubernetes suit une convention de nommage stricte, identique sur tous les clusters : connaître ce format permet de deviner l'adresse d'un Service sans consulter le cluster. Le domaine du cluster vaut cluster.local par défaut, mais il est configurable à l'installation. Trois catégories d'objets ont leurs propres règles : les Services classiques, les Pods et les Services headless.

Les formes courtes fonctionnent grâce à la ligne search du fichier /etc/resolv.conf du Pod, qui complète automatiquement les noms incomplets. Un nom court ne résout donc que depuis un Pod, jamais depuis un nœud ou une machine extérieure au cluster.

Type de nomFormatExemple
FQDN complet<service>.<namespace>.svc.<cluster-domain>nginx.default.svc.cluster.local
Dans le même namespace<service>nginx
Cross-namespace<service>.<namespace>nginx.production

Kubernetes peut publier des enregistrements DNS pour les Pods, mais la résolution exacte dépend du DNS du cluster et de sa configuration. Pour CoreDNS, ce comportement dépend du plugin kubernetes et de ses options (notamment pods insecure).

Format si activé :

<pod-ip-avec-tirets>.<namespace>.pod.cluster.local

Exemple : 10-244-0-5.default.pod.cluster.local

Un Service headless (clusterIP: None) ne reçoit aucune adresse virtuelle et n'équilibre pas la charge. CoreDNS renvoie alors directement les IPs des Pods, et attribue en plus un nom stable à chacun. C'est ce qui permet à un client de s'adresser à une instance précise, besoin typique des bases de données répliquées :

<pod-name>.<service>.<namespace>.svc.cluster.local

Utile pour les StatefulSets : mysql-0.mysql.default.svc.cluster.local

Avant de soupçonner une configuration, vérifiez que la chaîne existe : le Deployment, ses Pods et le Service qui les expose. Ces trois commandes prennent quelques secondes et éliminent d'emblée les causes les plus grossières, comme des Pods CoreDNS bloqués faute de CNI fonctionnel.

Le Deployment coredns déclare deux répliques par défaut sur un cluster kubeadm. La colonne AVAILABLE doit être égale à READY : un écart signale des Pods qui ne passent pas leur sonde de disponibilité.

Fenêtre de terminal
kubectl get deployment coredns -n kube-system
NAME READY UP-TO-DATE AVAILABLE AGE
coredns 2/2 2 2 10d

Le label de sélection reste k8s-app=kube-dns alors que les Pods s'appellent coredns : c'est ce label, et non le nom, qu'attendent les commandes de logs et de diagnostic. Un compteur RESTARTS qui grimpe trahit souvent une boucle de forwarding détectée par le plugin loop.

Fenêtre de terminal
kubectl get pods -n kube-system -l k8s-app=kube-dns
NAME READY STATUS RESTARTS AGE
coredns-5644d7b6d9-abcde 1/1 Running 0 10d
coredns-5644d7b6d9-fghij 1/1 Running 0 10d

C'est l'adresse de ce Service que le kubelet écrit dans chaque Pod : elle doit correspondre exactement au nameserver du fichier /etc/resolv.conf des Pods. Le port 9153 sert aux métriques Prometheus, les deux entrées sur le port 53 exposent le DNS en UDP et en TCP.

Fenêtre de terminal
kubectl get svc kube-dns -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 10d

CoreDNS est configuré via une ConfigMap nommée coredns dans kube-system. Elle contient un fichier unique, le Corefile, qui décrit une chaîne de plugins exécutés dans un ordre fixe, celui du code de CoreDNS et non celui du fichier. Modifier cette ConfigMap suffit à changer le comportement du DNS de tout le cluster, sans redéployer quoi que ce soit.

Commencez toujours par lire la configuration réelle plutôt que de supposer celle de votre distribution : k3s, RKE2 et les fournisseurs cloud livrent chacun des variantes.

Fenêtre de terminal
kubectl get configmap coredns -n kube-system -o yaml

Le Corefile varie selon la distribution, la version et les personnalisations. Voici un exemple typique sur un cluster kubeadm :

.: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
}

Deux plugins font l'essentiel du travail : kubernetes, qui répond pour les noms internes du cluster, et forward, qui transmet tout le reste aux résolveurs du nœud. Les autres apportent l'observabilité, le cache et la robustesse. Le plugin reload mérite une mention particulière : c'est lui qui fait qu'une modification du Corefile est prise en compte sans redémarrer les Pods.

PluginRôle
errorsLog les erreurs
healthExpose /health sur le port 8080
readyExpose /ready sur le port 8181
kubernetesRésout les noms du cluster Kubernetes
prometheusExpose les métriques sur le port 9153
forwardForwarde les requêtes externes vers les DNS upstream
cacheCache les réponses (TTL 30 secondes)
loopDétecte les boucles de forwarding
reloadRecharge la config quand la ConfigMap change
loadbalanceRépartit les réponses DNS (round-robin)

Deux besoins reviennent constamment en entreprise : joindre un domaine interne servi par un DNS maison, et résoudre un nom d'hôte qui n'existe dans aucun DNS. Le Corefile répond au premier avec un bloc de serveur dédié, au second avec le plugin hosts. Dans les deux cas, une erreur de syntaxe casse la résolution de tout le cluster : gardez une copie de la ConfigMap avant de la modifier.

Pour résoudre *.corp.example.com via un DNS interne d'entreprise :

Fenêtre de terminal
kubectl edit configmap coredns -n kube-system

Ajoutez un bloc avant le bloc principal :

corp.example.com:53 {
errors
cache 30
forward . 10.0.0.53
}
.:53 {
# ... config par défaut
}

Utilisez le plugin hosts pour des résolutions statiques :

.:53 {
errors
health
hosts {
192.168.1.100 legacy.internal
192.168.1.101 oldserver.internal
fallthrough
}
kubernetes cluster.local in-addr.arpa ip6.arpa {
# ...
}
# ...
}

Un problème DNS se manifeste rarement comme tel : l'application signale un hôte introuvable, une connexion qui expire ou une lenteur inexpliquée. La méthode consiste à tester la résolution depuis un Pod, à comparer avec le comportement attendu, puis à remonter la chaîne jusqu'à CoreDNS. Cette compétence est directement évaluée à l'examen CKA, dans le domaine Troubleshooting.

Le test doit partir d'un Pod, jamais d'un nœud : seul un Pod dispose du fichier /etc/resolv.conf pointant vers CoreDNS. Le nom kubernetes.default est la cible idéale, ce Service existe sur tous les clusters.

  1. Lancez un Pod de test

    Fenêtre de terminal
    kubectl run dnsutils --image=registry.k8s.io/e2e-test-images/agnhost:2.39 \
    --command -- sleep infinity
  2. Testez la résolution

    Fenêtre de terminal
    kubectl exec -it dnsutils -- nslookup kubernetes.default

    Résultat attendu :

    Server: 10.96.0.10
    Address: 10.96.0.10#53
    Name: kubernetes.default.svc.cluster.local
    Address: 10.96.0.1
  3. Testez un Service spécifique

    Fenêtre de terminal
    kubectl exec -it dnsutils -- nslookup my-service.my-namespace
  4. Nettoyez

    Fenêtre de terminal
    kubectl delete pod dnsutils

Ce fichier est écrit par le kubelet au démarrage du Pod et n'est plus modifié ensuite : un Pod démarré avant un changement de configuration DNS garde donc l'ancienne valeur jusqu'à sa recréation. Vérifiez surtout que le nameserver correspond bien à la ClusterIP du Service kube-dns.

Fenêtre de terminal
kubectl exec <pod-name> -- cat /etc/resolv.conf

Contenu attendu :

nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

Trois situations couvrent la grande majorité des incidents DNS, et elles se distinguent par une seule question : qu'est-ce qui résout et qu'est-ce qui échoue ? Plus rien du tout oriente vers CoreDNS ou le réseau, l'interne seul fonctionne pointe vers le forwarding, tout fonctionne mais lentement met en cause le paramètre ndots.

Aucune résolution, interne comme externe, signifie que le Pod n'atteint pas CoreDNS ou que CoreDNS ne répond pas. La cause est presque toujours en dessous du DNS : plugin réseau défaillant, ou politique réseau qui bloque le port 53.

Symptôme :

Fenêtre de terminal
kubectl exec mypod -- nslookup google.com
# timeout ou "server can't find"

Diagnostic :

Fenêtre de terminal
# 1. CoreDNS fonctionne ?
kubectl get pods -n kube-system -l k8s-app=kube-dns
# 2. Service kube-dns existe ?
kubectl get svc kube-dns -n kube-system
# 3. Logs CoreDNS
kubectl logs -n kube-system -l k8s-app=kube-dns

Solutions possibles :

  • Redémarrez CoreDNS : kubectl rollout restart deployment coredns -n kube-system
  • Vérifiez les NetworkPolicies bloquant le port 53
  • Vérifiez que le CNI est installé et fonctionnel

CoreDNS fonctionne, la panne est donc en aval : le plugin forward ne parvient pas à joindre les résolveurs qu'il utilise. Par défaut il reprend le fichier /etc/resolv.conf du nœud, ce qui déplace le diagnostic hors du cluster.

Symptôme :

Fenêtre de terminal
kubectl exec mypod -- nslookup kubernetes.default
# OK
kubectl exec mypod -- nslookup google.com
# timeout

Diagnostic :

Fenêtre de terminal
# Vérifiez le forward dans le Corefile
kubectl get configmap coredns -n kube-system -o yaml | grep forward

Solution : Vérifiez que /etc/resolv.conf du nœud contient des DNS valides, ou configurez un forward explicite :

forward . 8.8.8.8 8.8.4.4

Avec ndots:5, tout nom comportant moins de cinq points est d'abord essayé avec chacun des suffixes de la ligne search. Une requête vers un domaine public déclenche ainsi trois à quatre résolutions inutiles avant la bonne, chacune pouvant expirer.

Cause fréquente : Le paramètre ndots:5 fait essayer plusieurs suffixes avant la requête finale.

Solution : Pour une application qui fait beaucoup de requêtes externes, ajoutez un point final :

Fenêtre de terminal
# Lent (essaie google.com.default.svc.cluster.local, etc.)
nslookup google.com
# Rapide (requête directe)
nslookup google.com.

Ou configurez le Pod avec un dnsConfig personnalisé :

apiVersion: v1
kind: Pod
metadata:
name: fast-dns
spec:
dnsConfig:
options:
- name: ndots
value: "2"
containers:
- name: app
image: nginx

Tout ce qui précède concerne le serveur ; deux champs du manifeste de Pod agissent du côté client. dnsPolicy choisit quel résolveur le Pod interroge, dnsConfig permet d'ajuster ou de remplacer entièrement le contenu de son fichier /etc/resolv.conf. Ces réglages sont fixés à la création du Pod et exigent une recréation pour changer.

Le champ dnsPolicy contrôle la configuration DNS du Pod :

ValeurComportement
ClusterFirst (défaut)Utilise CoreDNS pour tout
DefaultUtilise le resolv.conf du nœud
ClusterFirstWithHostNetPour les Pods avec hostNetwork: true
NoneAucune config, à définir via dnsConfig

Avec dnsPolicy: "None", Kubernetes n'injecte plus aucune configuration : le bloc dnsConfig devient obligatoire et doit tout déclarer, résolveurs compris. Ce Pod perd donc l'accès aux noms de Services du cluster, sauf à ajouter la ClusterIP de kube-dns dans nameservers.

apiVersion: v1
kind: Pod
metadata:
name: custom-dns
spec:
dnsPolicy: "None"
dnsConfig:
nameservers:
- 8.8.8.8
- 8.8.4.4
searches:
- ns1.svc.cluster.local
- my.dns.search.suffix
options:
- name: ndots
value: "2"
- name: edns0
containers:
- name: app
image: nginx

CoreDNS expose des métriques Prometheus sur le port 9153. Les surveiller donne un signal d'alerte avant que les utilisateurs ne remontent quoi que ce soit : une hausse des réponses SERVFAIL ou un effondrement du taux de cache précèdent en général l'incident visible. Le port-forward ci-dessous permet de les consulter sans installer de collecteur.

Fenêtre de terminal
kubectl port-forward -n kube-system svc/kube-dns 9153:9153
curl http://localhost:9153/metrics

Quatre métriques suffisent à qualifier la santé du service : le volume de requêtes, la répartition des codes de réponse, la latence et l'efficacité du cache.

MétriqueDescription
coredns_dns_requests_totalNombre total de requêtes
coredns_dns_responses_totalRéponses par code (NOERROR, NXDOMAIN, SERVFAIL)
coredns_dns_request_duration_secondsLatence des requêtes
coredns_cache_hits_totalHits du cache

Deux répliques suffisent à un cluster de taille modeste, mais la charge DNS croît avec le nombre de Pods et la fréquence de leurs requêtes, pas avec le nombre de nœuds. Une latence qui monte alors que les Pods CoreDNS saturent leur CPU est le signal qu'il faut en ajouter. Descendre sous deux répliques est à proscrire : une seule instance rend le DNS du cluster indisponible à chaque redémarrage.

Pour les grands clusters, augmentez le nombre de replicas :

Fenêtre de terminal
kubectl scale deployment coredns -n kube-system --replicas=4

Ou utilisez l'Autoscaler DNS :

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

Le temps est la contrainte principale de l'examen : ces cinq commandes couvrent le parcours complet de diagnostic sans rien avoir à rédiger. La dernière, kubectl run --rm -it, crée un Pod de test et le supprime automatiquement à la sortie, ce qui évite de laisser des ressources derrière soi.

Fenêtre de terminal
# Vérifier l'état de CoreDNS
kubectl get deployment,pods,svc -n kube-system -l k8s-app=kube-dns
# Voir la configuration
kubectl get configmap coredns -n kube-system -o yaml
# Logs CoreDNS
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=50
# Test DNS rapide (image officielle de debug)
kubectl run test-dns --rm -it --restart=Never \
--image=registry.k8s.io/e2e-test-images/agnhost:2.39 \
-- /agnhost dns-lookup kubernetes.default
# Redémarrer CoreDNS
kubectl rollout restart deployment coredns -n kube-system

Pour les grands clusters ou les applications sensibles à la latence DNS, Kubernetes propose NodeLocal DNSCache. Il place un cache DNS sur chaque nœud via un DaemonSet, réduisant la charge sur CoreDNS et les temps de résolution.

Consultez la documentation NodeLocal DNSCache pour la mise en place.

Ce quiz reprend les questions CoreDNS du programme CKA, où le dépannage DNS relève du domaine Troubleshooting. Un score inférieur à 70 % indique les sections à reprendre avant de passer à la pratique.

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

10 questions
8 min.
70% requis

Informations

  • Le chronomètre démarre au clic sur Démarrer
  • Questions à choix multiples, vrai/faux et réponses courtes
  • Vous pouvez naviguer entre les questions
  • Les résultats détaillés sont affichés à la fin

Lance le quiz et démarre le chronomètre

  1. CoreDNS est le DNS par défaut de Kubernetes depuis la v1.13
  2. Service kube-dns expose CoreDNS (IP variable selon le Service CIDR, souvent 10.96.0.10 sur kubeadm)
  3. Format DNS : <service>.<namespace>.svc.cluster.local
  4. Corefile dans la ConfigMap coredns du namespace kube-system
  5. Plugin forward gère les requêtes DNS externes
  6. Test rapide avec l'image agnhost ou un Pod dnsutils
  7. ndots:5 peut ralentir les requêtes externes (ajouter un . final)
  8. hostNetwork nécessite ClusterFirstWithHostNet pour résoudre les Services

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn