Bonnes pratiques¶
Haute disponibilité¶
Minimum 2 serveurs par zone¶
Un service DNS unique constitue un SPOF (Single Point of Failure). Toute panne DNS paralyse l'ensemble de l'infrastructure.
| Configuration | Disponibilité | Commentaire |
|---|---|---|
| 1 serveur | ~99.5% | Inacceptable pour un service critique |
| 2 serveurs (actif/actif) | ~99.95% | Minimum requis |
| 3 serveurs (multi-AZ) | ~99.99% | Recommande pour la production |
Architecture HA avec load balancer¶
graph TD
LB["Load Balancer<br/>(HAProxy / MetalLB)<br/>VIP: 10.30.2.1"] --> C1["coredns-1<br/>AZ-a<br/>10.30.2.10"]
LB --> C2["coredns-2<br/>AZ-b<br/>10.30.2.11"]
LB --> C3["coredns-3<br/>AZ-c<br/>10.30.2.12"] Health check pour le load balancer¶
# HAProxy configuration
frontend dns_frontend
bind *:53
mode tcp
default_backend dns_servers
backend dns_servers
mode tcp
balance roundrobin
option tcp-check
server coredns-1 10.30.2.10:53 check inter 5s fall 3 rise 2
server coredns-2 10.30.2.11:53 check inter 5s fall 3 rise 2
server coredns-3 10.30.2.12:53 check inter 5s fall 3 rise 2
Synchronisation des zones¶
Pour que tous les serveurs autoritatifs servent les mêmes enregistrements :
| Méthode | Avantage | Inconvénient |
|---|---|---|
| Backend partage (etcd) | Cohérence forte, temps reel | Necessite etcd en HA |
| Fichiers de zone + Git + CI/CD | Auditabilite, rollback | Latence de propagation |
| Transfert de zone (AXFR/IXFR) | Standard DNS, compatible BIND | Configuration supplémentaire |
Recommandation
Pour CoreDNS, le backend etcd offre la meilleure cohérence. Si etcd n'est pas disponible, gérer les fichiers de zone dans Git et les déployer via CI/CD sur tous les serveurs.
Caching¶
TTL adaptés par type de service¶
; Services stables (changent rarement)
$TTL 3600
ns1 IN A 10.30.2.10
ns2 IN A 10.30.2.11
; Services avec failover (changent lors des basculements)
$TTL 120
db-master IN A 10.30.2.50
db-replica IN A 10.30.2.51
; Services dynamiques (pods Kubernetes, auto-scaling)
$TTL 30
worker IN A 10.30.3.10
worker IN A 10.30.3.11
worker IN A 10.30.3.12
Configuration du cache CoreDNS¶
# Corefile — cache avec tuning
production.internal.company.io {
file /etc/coredns/zones/db.production.internal
cache {
success 9984 3600 # Cache positif : max 9984 entrees, 3600s max
denial 9984 300 # Cache negatif : max 9984 entrees, 300s max
prefetch 10 1h 20% # Prefetch si >10 requetes et TTL restant <20%
}
log
errors
}
Metriques de cache¶
| Metrique | Seuil sain | Action si anormal |
|---|---|---|
| Cache hit ratio | > 70% | Augmenter TTL ou taille du cache |
| Cache miss ratio | < 30% | Normal si beaucoup de noms uniques |
| Cache evictions | Stable | Augmenter la taille du cache |
| Prefetch count | > 0 | Confirme que le prefetch fonctionne |
Monitoring¶
Metriques Prometheus essentielles¶
CoreDNS expose nativement des metriques Prometheus sur le port 9153 :
| Metrique | Description | Alerte si |
|---|---|---|
coredns_dns_requests_total | Nombre total de requêtes | Chute brutale (panne client) |
coredns_dns_responses_total | Nombre total de réponses | Divergence avec les requêtes |
coredns_dns_request_duration_seconds | Latence de résolution | p99 > 100 ms |
coredns_dns_responses_total{rcode="SERVFAIL"} | Erreurs serveur | > 1% du trafic |
coredns_dns_responses_total{rcode="NXDOMAIN"} | Noms inexistants | Augmentation soudaine |
coredns_cache_hits_total | Hits de cache | Cache hit ratio < 50% |
coredns_cache_misses_total | Misses de cache | Augmentation soudaine |
coredns_forward_healthcheck_failures_total | Echecs de health check upstream | > 0 (upstream en panne) |
Dashboard Grafana¶
Les metriques cles a afficher :
graph TD
subgraph Dashboard["DNS Dashboard"]
subgraph Row1[" "]
Req["Requetes/s<br/>1,234"]
Lat50["Latence p50<br/>2.3 ms"]
CacheHit["Cache Hit Ratio<br/>82.4%"]
end
subgraph Row2[" "]
Fail["SERVFAIL/s<br/>0.1"]
Lat99["Latence p99<br/>12.1 ms"]
Health["Upstream Health<br/>3/3 healthy"]
end
Rcode["Requetes par rcode (time series)<br/>NOERROR | NXDOMAIN | SERVFAIL"]
Heatmap["Latence par zone (heatmap)<br/>production.internal 2.1ms<br/>enterprise.internal 1.8ms<br/>build.internal 1.5ms<br/>external (forward) 15.2ms"]
end Regles d'alerte¶
# Prometheus alerting rules
groups:
- name: coredns
rules:
- alert: CoreDNSDown
expr: up{job="coredns"} == 0
for: 1m
labels:
severity: critical
annotations:
summary: "CoreDNS {{ $labels.instance }} est down"
runbook: "https://wiki.internal/runbooks/dns-down"
- alert: CoreDNSHighLatency
expr: histogram_quantile(0.99, rate(coredns_dns_request_duration_seconds_bucket[5m])) > 0.1
for: 5m
labels:
severity: warning
annotations:
summary: "Latence DNS p99 > 100ms sur {{ $labels.instance }}"
- alert: CoreDNSHighSERVFAIL
expr: >
rate(coredns_dns_responses_total{rcode="SERVFAIL"}[5m])
/ rate(coredns_dns_responses_total[5m]) > 0.01
for: 5m
labels:
severity: warning
annotations:
summary: "Taux de SERVFAIL > 1% sur {{ $labels.instance }}"
- alert: CoreDNSForwardUnhealthy
expr: coredns_forward_healthcheck_failures_total > 0
for: 2m
labels:
severity: critical
annotations:
summary: "Upstream DNS en echec sur {{ $labels.instance }}"
Troubleshooting¶
Outils essentiels¶
dig — requête DNS détaillée¶
# Requete A simple
dig @10.30.2.10 app-api.production.internal.company.io A
# Requete avec details (flags, TTL, autorite)
dig @10.30.2.10 app-api.production.internal.company.io A +noall +answer +authority
# Requete SRV
dig @10.30.2.10 _ldaps._tcp.enterprise.internal.company.io SRV +short
# Tracer la resolution complete
dig @10.30.2.10 app-api.production.internal.company.io A +trace
# Requete en TCP (si UDP pose probleme)
dig @10.30.2.10 app-api.production.internal.company.io A +tcp
# Resolution inverse
dig @10.30.2.10 -x 10.30.1.10
nslookup — vérification rapide¶
# Resolution simple
nslookup app-api.production.internal.company.io 10.30.2.10
# Requete specifique (SRV)
nslookup -type=SRV _ldaps._tcp.enterprise.internal.company.io 10.30.2.10
tcpdump — capture du trafic DNS¶
# Capturer le trafic DNS sur l'interface reseau
tcpdump -i eth0 port 53 -nn -v
# Capturer et sauvegarder pour analyse dans Wireshark
tcpdump -i eth0 port 53 -w /tmp/dns-capture.pcap
# Filtrer par IP source
tcpdump -i eth0 port 53 and src host 10.30.1.42 -nn
CoreDNS debug logging¶
# Corefile — activer le debug logging
. {
debug # Active le debug sur toutes les zones
log . {
class all # Journaliser toutes les classes de requetes
}
errors
forward . 1.1.1.1
}
Problèmes courants¶
| Symptome | Cause probable | Diagnostic | Solution |
|---|---|---|---|
SERVFAIL | Zone mal configuree ou upstream injoignable | dig +trace, logs CoreDNS | Vérifier le fichier de zone, tester l'upstream |
NXDOMAIN inattendu | Enregistrement manquant ou search domain incorrect | dig FQDN. (avec point final) | Ajouter l'enregistrement ou corriger le search domain |
| Latence elevee | Cache froid ou upstream lent | Metriques Prometheus, dig +stats | Vérifier le cache hit ratio, tester l'upstream |
| Résolution intermittente | Un des serveurs en panne | dig @serveur1, dig @serveur2 | Vérifier le health du serveur defaillant |
| Pods K8s ne résolvent pas | CoreDNS kube-system down | kubectl get pods -n kube-system | Redemarrer les pods CoreDNS |
Migration de BIND vers CoreDNS¶
Stratégie progressive¶
La migration s'effectue zone par zone, sans interruption de service :
graph TD
subgraph P1["Phase 1 — Coexistence"]
C1["Clients"] --> CD1["CoreDNS"] -->|forward| BIND1["BIND (autoritatif)"]
end
subgraph P2["Phase 2 — Migration progressive"]
C2["Clients"] --> CD2["CoreDNS"]
CD2 -->|file| Zone["zone production (local)"]
CD2 -->|forward| BIND2["BIND (zones restantes)"]
end
subgraph P3["Phase 3 — CoreDNS seul"]
C3["Clients"] --> CD3["CoreDNS"] -->|file| All["toutes les zones"]
end
P1 --> P2 --> P3 Étapes détaillées¶
Phase 1 : Déployer CoreDNS en forward
# Corefile initial — tout forwarder vers BIND
. {
forward . 10.30.2.50 10.30.2.51 {
# BIND existant
health_check 10s
}
cache 300
prometheus :9153
log
errors
}
Phase 2 : Migrer une zone
# Exporter la zone depuis BIND
dig @10.30.2.50 production.internal.company.io AXFR > db.production.internal
# Convertir au format CoreDNS file (identique au format BIND)
# Le fichier de zone BIND est directement utilisable par CoreDNS
cp db.production.internal /opt/coredns/zones/
# Corefile — zone production en local, reste en forward
production.internal.company.io {
file /etc/coredns/zones/db.production.internal
cache 300
log
errors
}
. {
forward . 10.30.2.50 10.30.2.51
cache 300
log
errors
}
Phase 3 : Decommissionner BIND
Une fois toutes les zones migrees et validees (minimum 2 semaines de fonctionnement stable) :
- Retirer le forward vers BIND dans le Corefile
- Garder BIND en lecture seule pendant 1 semaine (sécurité)
- Eteindre BIND
- Supprimer les références a BIND dans l'infrastructure
Points d'attention pour la migration
- Tester chaque zone migree avec
digdepuis plusieurs clients - Comparer les réponses CoreDNS vs BIND pour chaque enregistrement
- Surveiller les metriques SERVFAIL et NXDOMAIN apres chaque migration
- Prevoir un rollback rapide (re-activer le forward vers BIND)
- Prevenir les équipes de la migration et du calendrier
Script de validation post-migration¶
#!/bin/bash
# validate-dns-migration.sh
# Compare les reponses entre l'ancien BIND et le nouveau CoreDNS
BIND_SERVER="10.30.2.50"
COREDNS_SERVER="10.30.2.10"
ZONE="production.internal.company.io"
RECORDS=(
"app-api"
"db-master"
"db-replica"
"cache-redis"
"mq-rabbit"
)
echo "=== Validation migration DNS : $ZONE ==="
ERRORS=0
for record in "${RECORDS[@]}"; do
FQDN="${record}.${ZONE}"
BIND_RESULT=$(dig @${BIND_SERVER} ${FQDN} A +short | sort)
COREDNS_RESULT=$(dig @${COREDNS_SERVER} ${FQDN} A +short | sort)
if [ "$BIND_RESULT" = "$COREDNS_RESULT" ]; then
echo "[OK] ${FQDN} : ${COREDNS_RESULT}"
else
echo "[ERREUR] ${FQDN}"
echo " BIND : ${BIND_RESULT}"
echo " CoreDNS : ${COREDNS_RESULT}"
ERRORS=$((ERRORS + 1))
fi
done
echo ""
if [ $ERRORS -eq 0 ]; then
echo "Validation reussie : ${#RECORDS[@]} enregistrements OK"
else
echo "ECHEC : ${ERRORS} divergences detectees"
exit 1
fi