coredns
Installation
SKILL.md
Identity
- Binary:
/usr/local/bin/coredns(standalone),/usr/bin/coredns(package install) - Unit:
coredns.service(when run as a systemd service) - Corefile:
/etc/coredns/Corefile(standalone), ConfigMapcorednsin namespacekube-system(Kubernetes) - Logs:
journalctl -u coredns(systemd),kubectl logs -n kube-system -l k8s-app=kube-dns(k8s) - Kubernetes deployment:
kubectl -n kube-system get deployment coredns - Distro install:
apt install coredns/dnf install coredns/ binary from https://github.com/coredns/coredns/releases - Docker:
docker run coredns/coredns -conf /Corefile
Key Operations
| Operation | Command |
|---|---|
| Check service status | systemctl status coredns |
| Reload config (no restart) | kill -SIGUSR1 $(pidof coredns) or systemctl reload coredns |
| Validate Corefile syntax | coredns -conf /etc/coredns/Corefile -validate |
| Query health endpoint | curl -s http://localhost:8080/health |
| Query readiness endpoint | curl -s http://localhost:8181/ready |
| View Prometheus metrics | curl -s http://localhost:9153/metrics |
| Check specific metric | curl -s http://localhost:9153/metrics | grep coredns_dns_requests_total |
| Check logs (systemd) | journalctl -u coredns -f |
| Test DNS query (UDP) | dig @127.0.0.1 example.com A |
| Test DNS query (TCP) | dig +tcp @127.0.0.1 example.com A |
| Override Kubernetes DNS | Edit ConfigMap: kubectl -n kube-system edit configmap coredns |
| Reload k8s CoreDNS | kubectl -n kube-system rollout restart deployment/coredns |
| Check plugin build list | coredns -plugins |
| Trace a query | Add log plugin to zone block; watch journalctl -u coredns -f |
Expected Ports
- 53/UDP — DNS queries (primary)
- 53/TCP — DNS queries (fallback for large responses, zone transfers)
- 9153/TCP — Prometheus metrics (requires
prometheusplugin in Corefile) - 8080/TCP — Health check endpoint (requires
healthplugin) - 8181/TCP — Readiness endpoint (requires
readyplugin) - Verify listening:
ss -ulnp | grep coredns(UDP) andss -tlnp | grep coredns(TCP)
Health Checks
systemctl is-active coredns→activecurl -sf http://localhost:8080/health→ response bodyOKcurl -sf http://localhost:8181/ready→ response bodyOK(all plugins initialized)dig @127.0.0.1 . SOA +noall +comments→ statusNOERRORconfirms DNS is answering
Common Failures
| Symptom | Likely cause | Check/Fix |
|---|---|---|
plugin/forward: no nameservers found |
forward block has no upstream or upstream unreachable |
Verify upstream IPs: dig @8.8.8.8 google.com; check firewall allows outbound 53 |
| Loop detected, CoreDNS restarting | loop plugin detected forwarding back to itself |
Check /etc/resolv.conf — if it points to 127.0.0.1 and CoreDNS forwards there, a loop forms; use a real upstream |
| Kubernetes service DNS not resolving | kubernetes plugin not loaded, or wrong cluster domain |
Confirm kubernetes cluster.local in-addr.arpa ip6.arpa line exists in Corefile and CoreDNS pod is running |
| Metrics endpoint returns 404 or connection refused | prometheus plugin not in Corefile, or wrong port |
Add prometheus :9153 to the server block; confirm port in ss output |
| Config reload drops in-flight queries | SIGUSR1 reload is not instantaneous; brief query loss possible under high load | For zero-drop reloads in k8s, use a rolling restart with PodDisruptionBudget |
| Plugin not available at runtime | Plugin not compiled into the binary | Run coredns -plugins to list compiled plugins; custom plugins require building with xcorefile |
SERVFAIL on all queries |
Corefile syntax error or upstream unreachable | Run coredns -conf /etc/coredns/Corefile -validate; check upstream reachability |
Pain Points
- Plugin chain execution order is critical: plugins in a zone block execute top-to-bottom.
cachemust come beforeforward;rewritemust come beforeforward. Wrong order silently changes behavior. forwardreplacesproxy(v1.5+): theproxyplugin was removed in CoreDNS 1.5. All configs usingproxymust be migrated toforward. The syntax is similar but not identical —health_checkbecomeshealth_check <interval>inforward.healthvsreadyvsprometheusendpoints are separate:health(:8080) answers once the server is up.ready(:8181) waits until all plugins signal readiness (e.g., Kubernetes plugin has synced). Kubernetes liveness useshealth; readiness usesready. Mixing them causes premature or delayed traffic routing.- Kubernetes
ClusterDNSmust point to CoreDNS service IP: kubelet's--cluster-dnsflag (orclusterDNSin kubelet config) must match thekube-dnsService ClusterIP. Mismatch silently leaves pods using the node's resolver instead of CoreDNS. - Compiling custom plugins requires
xcorefile: CoreDNS uses aplugin.cfgfile and amakebuild to include plugins. Thexcorefiletool automates this. Standard binaries and distro packages do not include third-party plugins. loopplugin is safety-critical in Kubernetes: without it, a misconfigured upstream pointing back at CoreDNS creates an infinite loop that exhausts resources. Theloopplugin detects this and kills the server — alarming but correct behavior.- Zone block scoping: a query matches the most-specific zone.
.(dot) is the catch-all. If you defineexample.comand., queries forexample.comhit the first block only. Plugins in.do not run forexample.comqueries unless explicitly repeated.
References
See references/ for:
Corefile.annotated— complete Corefile with every plugin and directive explaineddocs.md— official documentation and community links
Related skills