TL;DR
Three real-life stories of DNS automation and CoreDNS hacks:
- Managing DNS zones via Git and CI/CD.
- Your own nip.io — a service that auto-resolves IPs directly from the name.
- How to write your own CoreDNS plugin and integrate with Kubernetes.
Story 1. Managing DNS Zones with Git
The Challenge
- Multiple teams, each needing DNS records for test/staging environments.
- Changes must be safe (no “oops, everything’s broken” scenarios).
- Administration should be simple, automated, and rollback-friendly.
The Solution
Using DNSControl
- A handy tool for describing DNS zones as code.
- Format is close to RFC 1035.
Sample configuration:
require("vars.js");
// Domains:
D('dso.domain.corp', REG_NONE, DnsProvider(BIND),
A('@', '10.1.2.3'),
A('ns1','10.1.2.4'),
A('ns2','10.1.2.5')
);
// subzones
require("./subzones/poc.js");
// reverse zone
require("./revzones/rev-10-2-2.js");
CI/CD pipeline for automation:
test_job:
stage: test
script:
- dnscontrol check
build_job:
stage: build
before_script:
- cp /etc/coredns/origins/* zones/
script:
- dnscontrol push
after_script:
- cp zones/*.zone /etc/coredns/origins/
- Validates config (
dnscontrol check
) before deployment. - Any change can be rolled back via Git.
- Only certain admins have access to DNS management.
Result
- Corporate users always have up-to-date DNS.
- Risks are minimized.
- Rollbacks are trivial.
- You can take the config and pipeline for your own use—see the author’s repo.
Story 2. Your Own nip.io: Auto-DNS for IP Addresses
The Problem
For pilot deployments, getting DNS records approved takes too long.
Need to resolve IPs from names (like nip.io), but:
- Must work in isolated environments (no outside access).
- Don’t want to depend on third-party services.
The Solution
Build your own nip.io
- Use CoreDNS with the template plugin to parse IPs from FQDN.
Example:
dig 2025.devopsconf.ip-20-25-4-7.shturval.link @8.8.8.8
;; ANSWER SECTION:
2025.devopsconf.ip-20-25-4-7.shturval.link. 3600 IN A 20.25.4.7
CoreDNS config:
shturval.link:53 {
ready
template IN A shturval.link {
match ^\S+[.]ip-(?P<a>[0-9]*)-(?P<b>[0-9]*)-(?P<c>[0-9]*)-(?P<d>[0-9]*)[.]shturval[.]link[.]$
answer "{{ .Name }} 3600 IN A {{ .Group.a }}.{{ .Group.b }}.{{ .Group.c }}.{{ .Group.d }}"
fallthrough
}
rewrite stop type AAAA A
rewrite stop type MX A
rewrite stop type HTTPS A
file /etc/coredns/shturval.link.zone
cache 3600
reload
prometheus localhost:9253
}
- Deploy locally—even in air-gapped environments.
- Simple template parsing of IPs from the domain name.
- Everything is powered by CoreDNS standard plugins.
Story 3. How to Write Your Own CoreDNS Plugin
The Backstory
- Platform upgrade caused node IPs to change.
- HAProxy was balancing traffic by static IPs → ingress stopped working.
- Needed autodiscovery without access to load balancer configs.
The Solution
- No need for Consul—Kubernetes + CoreDNS + etcd can do it!
- Write a CoreDNS plugin that watches pods and returns up-to-date IPs.
How it works:
- CoreDNS tracks pods with a specific annotation.
- On request—returns all relevant IPs.
- HAProxy (or any LB) queries CoreDNS via a resolver and always gets fresh IPs.
HAProxy config example:
resolvers shturval-sht-capov
nameserver ns1 api.shturval-sht-capov.domain.corp:1053
accepted_payload_size 8192
backend ingress-https-shturval-sht-capov
balance source
mode tcp
server-template ingress 3 default-nginx.ingress.shturval-sht-capov.coreha.shturval:30443 check resolvers shturval-sht-capov init-addr none
Plugin skeleton (Go):
func init() {
plugin.Register(pluginName, setup)
}
func setup(c *caddy.Controller) error {
k, err := parse(c)
if err != nil { /* ... */ }
k.setWatch(context.Background())
c.OnStartup(startWatch(k, dnsserver.GetConfig(c)))
c.OnShutdown(stopWatch(k))
dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
k.Next = next
return k
})
return nil
}
func (k *KubeHostport) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
// ... Build response, return current IPs ...
writeResponse(w, r, records, nil, nil, dns.RcodeSuccess)
return dns.RcodeSuccess, nil
}
- Code explanation:
- Register and initialize the plugin via CoreDNS API.
- Pod watcher—just like
kubectl get --watch
. - Caches the list of IPs; hits kube-API only on changes.
- You can literally write such a plugin in one evening—especially with LLM help 😄
Reflections & Takeaways
- CoreDNS is a powerful DevOps tool: flexible, extensible, minimal dependencies.
- 50+ in-tree plugins are officially supported.
- Making your own plugins and custom builds is truly simple.
- Code and examples are available in the author’s GitHub. Pull requests welcome!
Useful Links
- DNSControl
- CoreDNS Plugins
- Example of a self-hosted nip.io
- Repo with all examples from the article
- Хабр - Как я перестал страдать и полюбил CoreDNS: три истории
💡 Key Takeaways
- Treat your infrastructure as code (IaC)—even DNS!
- Don’t be afraid to write your own plugins and automate your routine.
- CoreDNS is a fantastic tool for tricky DNS challenges.
That’s all.