Creating a NAV Server Availability Set using the Azure Load Balancer

This post describes the steps needed to setup NAV Virtual Machines in an Availability Set behind an Azure Load Balancer. This provides high availability for an NAV Server and simple load distribution. Before reading you should already be familiar with the NAV Azure Image, the NAV Demo Environment and the Azure Resource Manager. You can read more about the Load Balancer here: Azure Load Balancer Overview

The following Azure PowerShell script creates an Azure Resource Group with two NAV Virtual Machines in an Availability Set and a Load Balancer with rules configured for the NAV demo environment on the Dynamics NAV 2016 gallery image.

Before running the script you need to be connected to your Azure Subscription using the Login-AzureRmAccount cmdlet and you need to update the $testName variable to something unique and meaningful. The script will prompt for the admin credentials for the virtual machines to be created.

When the script completes and the Virtual Machines are created, you can then connect to the virtual machines using via RDP using the Azure Portal and run the “Initialize Virtual Machine” script to create the demo environment. When prompted for the cloud service name you should provide the FQDN for the Load Balancer PublicIP, the FQDN is displayed at the end of running the script. If you are using self-signed certificates you can use the certificate generated for the first virtual machine, when running the script on the second virtual machine.

The Load Balancer has rules that enable requests to the default site on Port 80, the NAV Web Client on port 443 (HTTPS) and the NAV Client Service on port 7046. These ports works with the NAV demo environment on the Dynamics NAV 2016 gallery image.

The Azure Load Balancer distributes requests between the two virtual machines. The Load Balancer rules for port 443 and port 7046 are configured with session persisitence so that once a client creates a session with on of the virtual machines the load balancer continues to direct requests from the client to that virtual machine where the NAV client session has been created.

 

Here is the script which is hosted in a Gist:

 


$testName = "unique-resource-name"
$resourceGroupName = $testName
$location = "northeurope"
$domainName = $testName
$subnetName = "Subnet-1"
$publisher = "MicrosoftDynamicsNAV"
$offer = "DynamicsNAV"
$sku = "2016"
$version = "latest"
$cred = Get-Credential
New-AzureRmResourceGroup -Name $resourceGroupName -Location $location
$vip = New-AzureRmPublicIpAddress -ResourceGroupName $resourceGroupName -Name "PublicIP1" `
-Location $location -AllocationMethod Dynamic -DomainNameLabel $domainName
$subnet = New-AzureRmVirtualNetworkSubnetConfig -Name $subnetName `
-AddressPrefix "10.0.64.0/24"
$vnet = New-AzureRmVirtualNetwork -Name "VNET" `
-ResourceGroupName $resourceGroupName `
-Location $location -AddressPrefix "10.0.0.0/16" -Subnet $subnet
$subnet = Get-AzureRmVirtualNetworkSubnetConfig -Name $subnetName -VirtualNetwork $vnet
$feIpConfig = New-AzureRmLoadBalancerFrontendIpConfig -Name $testName -PublicIpAddress $vip
$inboundNatRule1 = New-AzureRmLoadBalancerInboundNatRuleConfig -Name "RDP1" `
-FrontendIpConfiguration $feIpConfig `
-Protocol TCP -FrontendPort 3441 -BackendPort 3389
$inboundNatRule2 = New-AzureRmLoadBalancerInboundNatRuleConfig -Name "RDP2" `
-FrontendIpConfiguration $feIpConfig `
-Protocol TCP -FrontendPort 3442 -BackendPort 3389
$beAddressPool = New-AzureRmLoadBalancerBackendAddressPoolConfig -Name "LBBE"
$healthProbe = New-AzureRmLoadBalancerProbeConfig -Name "HealthProbe" `
-RequestPath "Default.aspx" -Protocol http -Port 80 `
-IntervalInSeconds 15 -ProbeCount 2
$lbrule1 = New-AzureRmLoadBalancerRuleConfig -Name "HTTP" `
-FrontendIpConfiguration $feIpConfig -BackendAddressPool $beAddressPool `
-Probe $healthProbe -Protocol Tcp -FrontendPort 80 -BackendPort 80
$lbrule2 = New-AzureRmLoadBalancerRuleConfig -Name "HTTPS" `
-FrontendIpConfiguration $feIpConfig -BackendAddressPool $beAddressPool `
-Probe $healthProbe -Protocol Tcp -FrontendPort 443 -BackendPort 443 -LoadDistribution SourceIPProtocol
$lbrule3 = New-AzureRmLoadBalancerRuleConfig -Name "NAV" `
-FrontendIpConfiguration $feIpConfig -BackendAddressPool $beAddressPool `
-Probe $healthProbe -Protocol Tcp -FrontendPort 7046 -BackendPort 7046 -LoadDistribution SourceIPProtocol
$lbrule4 = New-AzureRmLoadBalancerRuleConfig -Name "NAVHELP" `
-FrontendIpConfiguration $feIpConfig -BackendAddressPool $beAddressPool `
-Probe $healthProbe -Protocol Tcp -FrontendPort 49000 -BackendPort 49000
$alb = New-AzureRmLoadBalancer -ResourceGroupName $resourceGroupName `
-Name "ALB" -Location $location -FrontendIpConfiguration $feIpConfig `
-InboundNatRule $inboundNatRule1,$inboundNatRule2 `
-LoadBalancingRule ($lbrule1,$lbrule2,$lbrule3,$lbrule4) -BackendAddressPool $beAddressPool `
-Probe $healthProbe
$nic1 = New-AzureRmNetworkInterface -ResourceGroupName $resourceGroupName `
-Name "nic1" -Subnet $subnet -Location $location `
-LoadBalancerInboundNatRule $alb.InboundNatRules[0] `
-LoadBalancerBackendAddressPool $alb.BackendAddressPools[0]
$nic2 = New-AzureRmNetworkInterface -ResourceGroupName $resourceGroupName `
-Name "nic2" -Subnet $subnet -Location $location `
-LoadBalancerInboundNatRule $alb.InboundNatRules[1] `
-LoadBalancerBackendAddressPool $alb.BackendAddressPools[0]
New-AzureRmAvailabilitySet -ResourceGroupName $resourceGroupName `
-Name "AVSet" -Location $location
$avset = Get-AzureRmAvailabilitySet -ResourceGroupName $resourceGroupName -Name "AVSet"
New-AzureRmStorageAccount -ResourceGroupName $resourceGroupName `
-Name $testName -Location $location -Type Standard_LRS
Get-AzureRmStorageAccount -ResourceGroupName $resourceGroupName
[array]$nics = @($nic1,$nic2)
For ($i=0; $i -le 1; $i++) {
$vmName = "$testName-w$i"
$vmConfig = New-AzureRmVMConfig -VMName $vmName -VMSize "Standard_DS1" `
-AvailabilitySetId $avSet.Id |
Set-AzureRmVMOperatingSystem -Windows -ComputerName $vmName `
-Credential $cred -ProvisionVMAgent -EnableAutoUpdate |
Set-AzureRmVMSourceImage -PublisherName $publisher -Offer $offer -Skus $sku `
-Version $version |
Set-AzureRmVMOSDisk -Name $vmName -VhdUri "https://$testName.blob.core.windows.net/vhds/$vmName-os.vhd" `
-Caching ReadWrite -CreateOption fromImage |
Add-AzureRmVMNetworkInterface -Id $nics[$i].Id
New-AzureRmVM -ResourceGroupName $resourceGroupName -Location $location `
-VM $vmConfig
}
$ipAddr = Get-AzureRmPublicIpAddress -ResourceGroupName $resourceGroupName
$ipAddr.IpAddress
$ipAddr.DnsSettings.Fqdn
Find-AzureRmResource -ResourceGroupNameContains $resourceGroupName | Select Name, ResourceType
<#
Remove-AzureRmResourceGroup -Name $resourceGroupName
#>

8 thoughts on “Creating a NAV Server Availability Set using the Azure Load Balancer

  1. This is a really useful blog post but I have one question. For most customers their employees are on their on premise network. Azure Load Balancer ultimately then sees all users connecting as coming from the ONE client IP address, likely the one bound on the corporate networks router. Therefore when you set this up you will only ever get traffic routed through one vm as it thinks it is all the same client connecting to the load balancer for the session persistence… Therefore you actually end up with no load balancing actually happening as it has no sight of the internal IP address on the users machine. How do you get around that?

    Like

    1. Hi Adrian,
      Thanks for you comments. There is no easy answer to your question. The Azure Load Balancer is designed to load balance clients distributed across multiple IP addresses and ports. As you probably know, each NAV client maintains a session on the a specific NAV server. To make this work with the Azure Load Balancer, we use Source IP Affinity to map traffic to the available servers. By using Source IP affinity, all connections initiated from the same IP address go to the same server. I explain a bit more about this in the How Do I: Setup a Microsoft Dynamics NAV Server with an Azure Load Balancer video.
      There is another white paper on Partner Source: Large scale hosting on Windows Azure that presents some other options for load balancing NAV Web Clients.

      Best Regards,

      David

      Like

      1. Hello David
        This is extremely good post, and the reason I got here is that we have similar situation as Ade does. However, your reply to his post did not really answer the question, neither did the video (which was, btw really enlightening).
        Do you, or anyone, have a solution for load balanced and NATted connections? If yes, I’d be more than happy to hear it.

        Like

      2. Hi Urpo,

        As in the previous reply I can only refer to the white paper for alternative load balancing options. AFAIK Azure Load Balancer does not support load balancing multiple connections from behind the same NAT (with the same IP).

        Regards,

        David

        Like

  2. Hello David,

    Great video, really helpful. I’m just having trouble initializing the first VM when its connected to the Load balancer, is there something I am doing wrong?

    Like

      1. Hi David,

        I had to build the setup through Azure manually for Dynamics NAV 2017 because I could not get the script to work that you provided.

        I’ve built 2 VMs in an availability set and created a load balancer and all other required elements as stated in your Video. When it comes to initializing the First VM, it asked for the DNS that is connected to the Load balancer, as it is subsequently also the DNS name of the VM, it runs the scripts fine, it finds the DNS, it creates a Certificate but when it gets to “Connect to NAV with admin user to create User Personalization Record” it gives the error “Unable to connect to the remote server (at , C:\DEMO\Initialize\install.ps1: line 422)”

        I know this error is to do with the correct ports being closed but I have opened all the ports on the Network Security Group but still no success.

        This is where my problem lies, I am unable to successfully initialize the machine and therefore have been stuck at this point.

        Please any help you may give me would be greatly appreciated.

        Kind regards,

        Alex

        Like

      2. Hi Alex,

        Thanks. I guess something has changed in the scripts since I created the demo with NAV 2016. I haven’t tried it yet with NAV 2017.
        Unfortunately, I don’t really have time to go through the setup again at the moment but I guess it is something to do with changes to the Install script. Have you tried modifying that to remove the “Create User Personalization Record” step?

        Regards,

        David

        Like

Comments are closed.