Migrating on-prem virtual machines to the cloud is a delicate dance and one that may take a few tries to get right. Application downtime while migrating up and failing back can be in short supply, so it's important to automate as many processes as possible to prevent mistakes and longer RTO.
Azure Traffic Manager uses DNS to direct client requests to the appropriate service endpoint based on a traffic-routing method. Because it uses DNS for multi-endpoint load balancing, we can use it during a cloud migration to point traffic at on-prem web servers until the migration is scheduled, then enable the Azure endpoints to immediately forward traffic to the new cloud server — without waiting for DNS TTL caching to expire on any hosts.
This sounds great, but how will it scale? If you're only moving a handful of servers, the transition is manageable. But with a large project using SRM, an entire data center might be migrated at once. This is where Bicep automation comes in.
The setup
The project I had required me to create approximately 50 Traffic Manager Profiles and be able to quickly fail back and forth between on-prem and cloud addresses. I accomplished this with a for loop that feeds a template resource with an array of variable objects.
First, define global parameters and the per-profile variable array:
// Global Variables
param globalVariables object = {
onpremTargetStatus: 'Enabled'
azureTargetStatus: 'Disabled'
trafficRoutingMethod: 'Priority'
environmentTag: 'UAT'
}
// Variable object list to create Traffic Manager Profiles
var profiles = [
{
profileName: 'website1-uat-domain-com'
dnsConfigRelativeName: 'website1-uat.domain.com'
onpremTargetIP: '1.1.1.1'
azureTargetIP: '2.2.2.2'
applicationTag: 'webApp1'
}
{
profileName: 'website2-uat-domain-com'
dnsConfigRelativeName: 'website2-uat.domain.com'
onpremTargetIP: '3.3.3.3'
azureTargetIP: '4.4.4.4'
applicationTag: 'webApp2'
}
{
profileName: 'website3-uat-domain-com'
dnsConfigRelativeName: 'website3-uat.domain.com'
onpremTargetIP: '5.5.5.5'
azureTargetIP: '6.6.6.6'
applicationTag: 'webApp3'
}
]
Then create all the Traffic Manager Profile resources in a single loop:
resource trafficManagerProfile 'Microsoft.Network/trafficManagerProfiles@2018-08-01' = [for profile in profiles: {
name: profile.profileName
location: 'global'
tags: {
App: profile.applicationTag
Env: globalVariables.environmentTag
}
properties: {
profileStatus: 'Enabled'
trafficRoutingMethod: globalVariables.trafficRoutingMethod
dnsConfig: {
relativeName: profile.dnsConfigRelativeName
ttl: 35
}
monitorConfig: {
protocol: 'HTTP'
port: 80
path: '/'
intervalInSeconds: 30
timeoutInSeconds: 5
toleratedNumberOfFailures: 3
}
endpoints: [
{
name: 'OnPrem-Endpoint'
type: 'Microsoft.Network/TrafficManagerProfiles/ExternalEndpoints'
properties: {
target: profile.onpremTargetIP
endpointStatus: globalVariables.onpremTargetStatus
endpointLocation: 'westus'
weight: 100
priority: 1
}
}
{
name: 'Azure-Endpoint'
type: 'Microsoft.Network/TrafficManagerProfiles/ExternalEndpoints'
properties: {
target: profile.azureTargetIP
endpointStatus: globalVariables.azureTargetStatus
endpointLocation: 'westus'
weight: 100
priority: 2
}
}
]
}
}]
Running the migration
On the first run, the script creates all Azure resources still pointing traffic at the on-prem public IPs. When it's time to kick off migration, run it a second time with the endpoints flipped:
param globalVariables object = {
onpremTargetStatus: 'Disabled'
azureTargetStatus: 'Enabled'
}
The complete version of this script is available on GitHub.