ExternalDNS: Sync Kubernetes with Cloudflare

Manually managing DNS records for every new service or application deployed on Kubernetes is a pain. It's slow, error-prone, and frankly, we have better things to do.
ExternalDNS solves this by sitting inside your cluster, watching your Kubernetes resources (like Services, Ingresses, and Gateways), and automatically creating or updating the corresponding DNS records in your provider (like Cloudflare, AWS Route53, or Google Cloud DNS).
When you delete a service, it cleans up the DNS record. It just works.
How it works
ExternalDNS operates as a pod within your cluster that securely talks to your DNS provider's API. Here is the flow:
graph LR
EDNS[ExternalDNS] -->|Watches| K8s[Kubernetes API Resources]
K8s -->|Updates| DNS[DNS Records]
DNS -.->|Resolved by| Users[User] Configuration
Let's look at a production-ready configuration for Cloudflare. This setup handles standard Services and the newer Gateway API.
Installation
We install ExternalDNS using its Helm chart. It's the standard way to deploy it.
We're now ready to deploy DNS :)
Manage records
Exposing a Service
To expose a standard Service, you just need to add the external-dns.alpha.kubernetes.io/hostname annotation. ExternalDNS sees this, will get the LoadBalancer IP from the Service and creates the A record.
Exposing a Gateway HTTPRoute
If you are using the Gateway API, ExternalDNS can watch your HTTPRoute resources. Unlike Services, you often define the hostname directly in the rule hostnames, and ExternalDNS picks it up automatically.
Useful annotations
There are many other useful annotations you can use to control how ExternalDNS behaves. Here are a few:
external-dns.alpha.kubernetes.io/target: The target IP address to create (comma separated for multiple targets).external-dns.alpha.kubernetes.io/ttl: The TTL of the record.
Other annotations are "Provider" specific like Cloudflare for their Proxied option. You can find the full list of annotations in the official documentation.
Manual records
ExternalDNS can also create records manually by using its CRDs! This is useful if you want to separate your DNS management from your Kubernetes resources. Here is a basic example for a A record:
Note
All the record types are not enabled by default, so the required record types must be enabled by using --managed-record-types=A in the extraArgs section of the external-dns chart: