If you have been following my series, (part1 & part2) on Traffic Manager profiles you should understand how to create a setup that can select between a number of App Service endpoints based on a Routing Method. You’ll also be able to create custom domains, so your customers don’t have to use
*.azurewebsites.net based addresses.
Up to now, all of these changes have been achieved manually through the Azure portal. Whilst this acceptable for proof of concepts and small scale deployments, doing everything by hand very quickly becomes error prone and time consuming. When I need to provision a number of environments with near identical setups I prefer to automate via Azure Resource Manager (ARM) templates.
I have written about ARM template previously so I am not going to cover old ground. Instead I will cover one of the problems I bumped up against when trying to automate the setup described in the diagram below.
Here I have three resource groups.
- One for the primary region that contains a web site and the API supporting it
- One for the secondary region which is a copy of the first, providing basic business continuity in the case of failure
- One containing traffic manager profiles for both the web site and the API.
Before I go on, there is one important thing to highlight about ARM templates. You cannot have one template that effects multiple resource groups. Therefore I had to have at least three template deployments to achieve this automation. Full disclosure: I actually achieved this with two templates. One that had two different parameters sets for the web/api sites in UK West and UK South and one for the traffic manger profiles, making three deployments.
Creating a template to deploy the web site and API turned out to be quite simple. I could use different parameter files against the same templates to give me two of the three resource groups I needed. This created the website, API and a custom domain for each.
The difficultly came when creating the traffic manager profiles. Whilst setting up the profile rules and the endpoints was easy enough there was no clear way to provide a custom domain so customers don’t need to use the
*.trafficmanager.net address. Why?…
The custom domain must be added to the app services, not the traffic manager profile or the endpoints. As these app services live in different resource groups I could not affect them from the traffic manager profile deployment.
So why not add this step to the template that provisions the App Services? I did try this but still hit problems. If I tried to provision the app service first this didn’t work because the CNAME for custom domain I was provisioning was configured at my DNS registrar to point at the traffic manager profile address and that didn’t exist yet. As part of provisioning the custom domain Azure couldn’t verify that it was valid.
Reversing the provisioning order did not help either. It is not possible to provision endpoints to a traffic manager profile if the app services they point at do not exist yet.
I am not the sort of person to give up easily so I wanted to see if there was an resource group topology that could be provisioned automatically. So this time I tried the configuration below.
The main change is that the traffic manager now exists in the same resource group as the app services it is managing, so this should just work…
Unfortunately this was not the case. This time something more subtle was causing problems.
Remember last time that I pointed out that when you create the traffic manager profile in the Azure Portal a
*.trafficmanager.net custom domain is added to each underlying app service. And in order to access the traffic managed site through a friendly domain name you also need to add a custom binding to each app service.
In my template, I was provisioning the traffic manager profile and it endpoints once the app services were created. Once the endpoints were available I’d then add the custom domain to each one. This final step failed because when provisioning the traffic manager profile endpoints, added the
*.trafficmanager.net domain to the app services is done asynchronously. Adding my custom domain whilst this was happening caused a conflict.
This stack overflow question covers a very similar issue. I tried the recommendation of using the
dependsOn element to change the order the resources were provisioned. The best I could achieve was a template that would fail on the first attempt but then work on subsequent runs. Not great, but least it failed reliably, and I could get a working environment eventually.
I have not been able to get any further than this. I can live with this for now but this is something I’ll keep an eye on and update this post if I find a resolution.