Blog Post

Apps on Azure Blog
8 MIN READ

Exploring Traffic Manager Integration for External DNS

samcogan's avatar
samcogan
Icon for Microsoft rankMicrosoft
Jan 29, 2026

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:

  1. Watches Kubernetes Services for Traffic Manager annotations
  2. Automatically creates and manages Traffic Manager profiles and endpoints
  3. Syncs state between your Kubernetes clusters and Azure
  4. Enables annotation-driven configuration - no manual Traffic Manager management needed
  5. Handles duplication so that when your second cluster attempts to create a Traffic Manager record it adds an endpoint to the existing instance
  6. 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:

  1. Azure Load Balancer provisions and assigns public IPs to each Service
  2. 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
  3. External DNS (Webhook provider) creates a Traffic Manager profile named my-app-global
  4. 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)
  5. 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

Updated Jan 29, 2026
Version 1.0
No CommentsBe the first to comment