When you deploy externally accessible applications into Kubernetes, there is usually a requirement for creating some DNS records pointing to these applications, to allow your users to resolve them. Rather than manually creating these DNS records, there are tools that will do this work for you, one of which is External DNS.
External DNS can watch your Kubernetes resource configuration for specific annotations and then use these to create DNS records in your DNS zone. It has integrations with many DNS providers, including Azure DNS. This solution works well and is in use by many customers using AKS and Azure DNS. Where we hit a limitation with External DNS in Azure is in scenarios where we are need to distribute traffic across multiple clusters for load balancing and global distribution.
There are a few ways to achieve this global distribution in Azure, one way is to use Azure Traffic Manger. Unlike something like Azure Front Door, Azure Traffic Manager is a DNS based global load balancer. Traffic is directed to your different AKS clusters based on DNS resolution using Traffic Manager. When a user queries your Traffic Manager CNAME, they hit the Traffic Manager DNS servers, which then return a DNS record for a specific cluster based on your load balancing configuration. Traffic Manager can then introduce advanced load balancing scenarios such as:
- Geographic routing - direct users to the nearest endpoint based on their location
- Weighted distribution - split traffic percentages (e.g., 80% to one region, 20% to another)
- Priority-based failover - automatic disaster recovery with primary/backup regions
- Performance-based routing - direct users to the endpoint with lowest latency
So, given Azure Traffic Manager is a essentially a DNS service, it would be good if we could manage it using External DNS. We already use External DNS to create DNS records for each of our individual clusters, so why not use it to also create the Traffic Manager DNS configuration to load balance across them. This would also provides the added benefit of allowing us to change our load balancing strategy or configuration by making changes to our External DNS annotations.
Unfortunately, an External DNS integration for Traffic Manager doesn't currently exist. In this post, I'll walk through a proof-of-concept for a provider I built to explore whether this integration is viable, and share what I learned along the way.
External DNS Webhook Provider
External DNS has two types of integrations. The first, and most common for "official" providers are "In-tree" providers, which are the integrations that have been created by External DNS contributors and sit within the central External DNS repository. This includes the Azure DNS provider. The second type of provider is the WebHook provider, which allows for external contributors to easily create their own providers without the need to submit them to the core External DNS repo and go through that release process. We are going to use the WebHook provider
External DNS has begun the process of phasing out "In-tree" providers and replacing with WebHook ones. No new "In-tree" providers will be accepted.
By using the WebHook provider mechanism, I was able to create a proof of concept Azure Traffic Manager provider that does the following:
- Watches Kubernetes Services for Traffic Manager annotations
- Automatically creates and manages Traffic Manager profiles and endpoints
- Syncs state between your Kubernetes clusters and Azure
- Enables annotation-driven configuration - no manual Traffic Manager management needed
- Handles duplication so that when your second cluster attempts to create a Traffic Manager record it adds an endpoint to the existing instance
- Works alongside the standard External DNS Azure provider for complete DNS automation
Here's what the architecture looks like:
Example Configuration: Multi-Region Deployment
Let me walk you through a practical example using this provider to see how it works. We will deploy an application across two Azure regions with weighted traffic distribution and automatic failover. This example assumes you have built and deployed the PoC provider as discussed below.
Step 1: Deploy Your Application
You deploy your application to both East US and West US AKS clusters. Each deployment is a standard Kubernetes Service with LoadBalancer type. We then apply annotations that tell our External DNS provider how to create and configure the Traffic Manger resource. These annotations are defined as part of our plugin.
apiVersion: v1
kind: Service
metadata:
name: my-app-east
namespace: production
annotations:
# Standard External DNS annotation
external-dns.alpha.kubernetes.io/hostname: my-app-east.example.com
# Enable Traffic Manager integration
external-dns.alpha.kubernetes.io/webhook-traffic-manager-enabled: "true"
external-dns.alpha.kubernetes.io/webhook-traffic-manager-resource-group: "my-tm-rg"
external-dns.alpha.kubernetes.io/webhook-traffic-manager-profile-name: "my-app-global"
# Weighted routing configuration
external-dns.alpha.kubernetes.io/webhook-traffic-manager-weight: "70"
external-dns.alpha.kubernetes.io/webhook-traffic-manager-endpoint-name: "east-us"
external-dns.alpha.kubernetes.io/webhook-traffic-manager-endpoint-location: "eastus"
# Health check configuration
external-dns.alpha.kubernetes.io/webhook-traffic-manager-monitor-path: "/health"
external-dns.alpha.kubernetes.io/webhook-traffic-manager-monitor-protocol: "HTTPS"
spec:
type: LoadBalancer
ports:
- port: 443
targetPort: 8080
selector:
app: my-app
The West US deployment has identical annotations, except:
- Weight: "30" (sending 30% of traffic here initially)
- Endpoint name: "west-us"
- Location: "westus"
Step 2: Automatic Resource Creation
When you deploy these Services, here's what happens automatically:
- Azure Load Balancer provisions and assigns public IPs to each Service
- External DNS (Azure provider) creates A records:
- my-app-east.example.com ā East US LB IP
- my-app-west.example.com ā West US LB IP
- External DNS (Webhook provider) creates a Traffic Manager profile named my-app-global
- Webhook adds endpoints to the profile:
- East endpoint (weight: 70, target: my-app-east.example.com)
- West endpoint (weight: 30, target: my-app-west.example.com)
- External DNS (Azure provider) creates a CNAME:
- my-app.example.com ā Traffic Manager FQDN
Now when users access my-app.example.com, Traffic Manager routes 70% of traffic to East US and 30% to West US, with automatic health checking on both endpoints.
Step 3: Gradual Traffic Migration
Want to shift more traffic to West US? Just update the annotations:
kubectl annotate service my-app-east \
external-dns.alpha.kubernetes.io/webhook-traffic-manager-weight="50" \
--overwrite
kubectl annotate service my-app-west \
external-dns.alpha.kubernetes.io/webhook-traffic-manager-weight="50" \
--overwrite
Within minutes, traffic distribution automatically adjusts to 50/50. This enables:
- Blue-green deployments - test new versions with small traffic percentages
- Canary releases - gradually increase traffic to new deployments
- Geographic optimisation - adjust weights based on user distribution
Step 4: Automatic Failover
If the East US cluster becomes unhealthy, Traffic Manager's health checks detect this and automatically fail over 100% of traffic to West US, no manual intervention required.
How It Works
The webhook implements External DNS's webhook provider protocol:
1. Negotiate Capabilities
External DNS queries the webhook to determine supported features and versions.
2. Adjust Endpoints
External DNS sends all discovered endpoints to the webhook. The webhook:
- Filters for Services with Traffic Manager annotations
- Validates configuration
- Enriches endpoints with metadata
- Returns only Traffic Manager-enabled endpoints
3. Record State
External DNS queries the webhook for current Traffic Manager state. The webhook:
- Syncs profiles from Azure
- Converts to External DNS endpoint format
- Returns CNAME records pointing to Traffic Manager FQDNs
4. Apply Changes
External DNS sends CREATE/UPDATE/DELETE operations. The webhook:
- Creates Traffic Manager profiles as needed
- Adds/updates/removes endpoints
- Configures health monitoring
- Updates in-memory state cache
The webhook uses Azure SDK for Go to interact with the Traffic Manager API and maintains an in-memory cache of profile state to optimise performance and reduce API calls.
Proof of Concept
š Important: This is a Proof of Concept
This project is provided as example code to demonstrate the integration pattern between External DNS and Traffic Manager. It is not a supported product and comes with no SLAs, warranties, or commitments.
The code is published to help you understand how to build this type of integration. If you decide to implement something similar for your production environment, you should treat this as inspiration and build your own solution that you can properly test, secure, and maintain.
Think of this as a blueprint, not a finished product.
With that caveat out of the way, if you want to experiment with this approach, the PoC is available on GitHub: github.com/sam-cogan/external-dns-traffic-manager. The readme file containers detailed instructions on how to deploy the PoC into a single and multi-cluster environment, along with demo applications to try it out.
Use Cases
This integration unlocks several powerful scenarios:
- Multi-Region High Availability - Deploy your application across multiple Azure regions with automatic DNS-based load balancing and health-based failover. No additional load balancers or gateways required.
- Blue-Green Deployments - Deploy a new version alongside your current version, send 5% of traffic to test, gradually increase, and roll back instantly if issues arise by changing annotations.
- Geographic Distribution - Route European users to your Europe region and US users to your US region automatically using Traffic Manager's geographic routing with the same annotation-based approach.
- Disaster Recovery - Configure priority-based routing with your primary region at priority 1 and DR region at priority 2. Traffic automatically fails over when health checks fail.
- Cost Optimisation - Use weighted routing to balance traffic across regions based on capacity and costs. Send more traffic to regions where you have reserved capacity or lower egress costs.
Considerations and Future Work
This is a proof of concept and should be thoroughly tested before production use. Some areas for improvement:
Current Limitations
- In-memory state only - no persistent storage (restarts require resync)
- Basic error handling - needs more robust retry logic
- Limited observability - could use more metrics and events
- Manual CRD cleanup - DNSEndpoint CRDs need manual cleanup when switching providers
Potential Enhancements
- Support for more endpoint types - currently focuses on ExternalEndpoints
- Advanced health check configuration - custom intervals, timeouts, and thresholds
- Metric-based routing decisions - integrate with Azure Monitor for intelligent routing
- GitOps integration - Flux/ArgoCD examples and best practices
- Helm chart - simplified deployment
If you try this out or have ideas for improvements, please open an issue or PR on GitHub.
Wrapping Up
This proof of concept shows that External DNS and Traffic Manager can work together nicely. Since Traffic Manager is really just an advanced DNS service, bringing it into External DNS's annotation-driven workflow makes a lot of sense. You get the same declarative approach for both basic DNS records and sophisticated traffic routing.
While this isn't production-ready code (and you shouldn't use it as-is), it demonstrates a viable pattern. If you're dealing with multi-region Kubernetes deployments and need intelligent DNS-based routing, this might give you some ideas for building your own solution.
The code is out there for you to learn from, break, and hopefully improve upon. If you build something based on this or have feedback on the approach, I'd be interested to hear about it.
Resources
- GitHub Repository: github.com/sam-cogan/external-dns-traffic-manager
- External DNS Documentation: kubernetes-sigs.github.io/external-dns
- Azure Traffic Manager: learn.microsoft.com/azure/traffic-manager
- Webhook Provider Guide: External DNS Webhook Tutorial