Quickstart: Create a Load Balancer to load balance VMs by using an ARM template

Load balancing provides a higher level of availability and scale by spreading incoming requests across multiple virtual machines (VMs). This quickstart shows you how to deploy an Azure Resource Manager template (ARM template) that creates a Standard load balancer to load balance VMs. Using an ARM template takes fewer steps comparing to other deployment methods.

An ARM template is a JavaScript Object Notation (JSON) file that defines the infrastructure and configuration for your project. The template uses declarative syntax, which lets you state what you intend to deploy without having to write the sequence of programming commands to create it.

If your environment meets the prerequisites and you're familiar with using ARM templates, select the Deploy to Azure button. The template will open in the Azure portal.

Deploy to Azure

Prerequisites

If you don't have an Azure subscription, create a free account before you begin.

Review the template

The template used in this quickstart is from Azure Quickstart Templates.

Load Balancer and Public IP SKUs must match. When you create a Standard Load Balancer, you must also create a new Standard Public IP address that is configured as the frontend for the Standard load balancer. If you want to create a Basic Load Balancer, use this template. Microsoft recommends using Standard SKU for production workloads.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "projectName": {
      "type": "string",
      "metadata": {
        "description": "Specifies a project name that is used for generating resource names."
      }
    },
    "location": {
      "type": "string",
      "allowedValues": [
        "centralus",
        "eastus",
        "eastus2",
        "westus2",
        "francecentral",
        "northeurope",
        "uksouth",
        "westeurope",
        "japaneast",
        "southeastasia"
      ],
      "metadata": {
        "description": "Specifies the location for all of the resources created by this template. Availability zones are only supported in certain regions.  For the last supported zones, see https://docs.microsoft.com/en-us/azure/availability-zones/az-overview#services-support-by-region."
      }
    },
    "adminUsername": {
      "type": "string",
      "metadata": {
        "description": "Specifies the virtual machine administrator username."
      }
    },
    "adminPassword": {
      "type": "securestring",
      "metadata": {
        "description": "Specifies the virtual machine administrator password."
      }
    }
  },
  "variables": {
    "lbName": "[concat(parameters('projectName'),'-lb')]",
    "lbSkuName": "Standard",
    "lbPublicIpAddressName": "[concat(parameters('projectName'),'-lbPublicIP')]",
    "lbFrontEndName": "LoadBalancerFrontEnd",
    "lbBackendPoolName": "LoadBalancerBackEndPool",
    "lbProbeName": "loadBalancerHealthProbe",
    "nsgName": "[concat(parameters('projectName'),'-nsg')]",
    "vNetName": "[concat(parameters('projectName'),'-vnet')]",
    "vNetAddressPrefix": "10.0.1.0/24",
    "vNetSubnetName": "BackendSubnet",
    "vNetSubnetAddressPrefix": "10.0.1.0/24",
    "vmSize": "Standard_DS1_v2",
    "vmStorageAccountType": "Premium_LRS"
  },
  "resources": [
    {
      "type": "Microsoft.Network/loadBalancers",
      "apiVersion": "2018-12-01",
      "name": "[variables('lbName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "[variables('lbSkuName')]"
      },
      "dependsOn": [
        "[resourceId('Microsoft.Network/publicIPAddresses', variables('lbPublicIpAddressName'))]"
      ],
      "properties": {
        "frontendIPConfigurations": [
          {
            "name": "[variables('lbFrontEndName')]",
            "properties": {
              "publicIPAddress": {
                "id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('lbPublicIpAddressName'))]"
              }
            }
          }
        ],
        "backendAddressPools": [
          {
            "name": "[variables('lbBackendPoolName')]"
          }
        ],
        "loadBalancingRules": [
          {
            "name": "HTTPLBRule",
            "properties": {
              "frontendIPConfiguration": {
                "id": "[resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', variables('lbName'), variables('lbFrontEndName'))]"
              },
              "backendAddressPool": {
                "id": "[resourceId('Microsoft.Network/loadBalancers/backendAddressPools', variables('lbName'), variables('lbBackendPoolName'))]"
              },
              "frontendPort": 80,
              "backendPort": 80,
              "enableFloatingIP": false,
              "idleTimeoutInMinutes": 4,
              "protocol": "Tcp",
              "enableTcpReset": false,
              "loadDistribution": "Default",
              "disableOutboundSnat": false,
              "probe": {
                "id": "[resourceId('Microsoft.Network/loadBalancers/probes', variables('lbName'), variables('lbProbeName'))]"
              }
            }
          }
        ],
        "probes": [
          {
            "name": "[variables('lbProbeName')]",
            "properties": {
              "protocol": "Http",
              "port": 80,
              "requestPath": "/",
              "intervalInSeconds": 5,
              "numberOfProbes": 2
            }
          }
        ]
      }
    },
    {
      "type": "Microsoft.Network/publicIPAddresses",
      "apiVersion": "2018-12-01",
      "name": "[variables('lbPublicIPAddressName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "[variables('lbSkuName')]"
      },
      "properties": {
        "publicIPAddressVersion": "IPv4",
        "publicIPAllocationMethod": "Static"
      }
    },
    {
      "type": "Microsoft.Network/networkSecurityGroups",
      "apiVersion": "2018-12-01",
      "name": "[variables('nsgName')]",
      "location": "[parameters('location')]",
      "properties": {
        "securityRules": [
          {
            "name": "AllowHTTPInbound",
            "properties": {
              "protocol": "*",
              "sourcePortRange": "*",
              "destinationPortRange": "80",
              "sourceAddressPrefix": "Internet",
              "destinationAddressPrefix": "*",
              "access": "Allow",
              "priority": 100,
              "direction": "Inbound"
            }
          },
          {
            "name": "default-allow-rdp",
            "properties": {
              "priority": 1000,
              "protocol": "TCP",
              "access": "Allow",
              "direction": "Inbound",
              "sourceAddressPrefix": "*",
              "sourcePortRange": "*",
              "destinationAddressPrefix": "*",
              "destinationPortRange": "3389"
            }
          }
        ]
      }
    },
    {
      "type": "Microsoft.Network/virtualNetworks",
      "apiVersion": "2018-12-01",
      "name": "[variables('vNetName')]",
      "location": "[parameters('location')]",
      "properties": {
        "addressSpace": {
          "addressPrefixes": [
            "[variables('vNetAddressPrefix')]"
          ]
        },
        "subnets": [
          {
            "name": "[variables('vNetSubnetName')]",
            "properties": {
              "addressPrefix": "[variables('vNetSubnetAddressPrefix')]"
            }
          }
        ]
      }
    },
    {
      "type": "Microsoft.Compute/virtualMachines",
      "apiVersion": "2018-10-01",
      "name": "[concat(parameters('projectName'),'-vm', copyIndex(1))]",
      "location": "[parameters('location')]",
      "zones": [
        "[copyIndex(1)]"
      ],
      "copy": {
        "name": "vmCopy",
        "count": 3
      },
      "dependsOn": [
        "networkInterfaceCopy"
      ],
      "properties": {
        "hardwareProfile": {
          "vmSize": "[variables('vmSize')]"
        },
        "storageProfile": {
          "imageReference": {
            "publisher": "MicrosoftWindowsServer",
            "offer": "WindowsServer",
            "sku": "2019-Datacenter",
            "version": "latest"
          },
          "osDisk": {
            "createOption": "fromImage",
            "managedDisk": {
              "storageAccountType": "[variables('vmStorageAccountType')]"
            }
          }
        },
        "networkProfile": {
          "networkInterfaces": [
            {
              "id": "[resourceId('Microsoft.Network/networkInterfaces', concat(parameters('projectName'),'-vm', copyIndex(1), '-networkInterface'))]"
            }
          ]
        },
        "osProfile": {
          "computerName": "[concat(parameters('projectName'),'-vm', copyIndex(1))]",
          "adminUsername": "[parameters('adminUsername')]",
          "adminPassword": "[parameters('adminPassword')]",
          "windowsConfiguration": {
            "enableAutomaticUpdates": true,
            "provisionVmAgent": true
          }
        }
      }
    },
    {
      "type": "Microsoft.Network/publicIPAddresses",
      "apiVersion": "2018-12-01",
      "name": "[concat(parameters('projectName'),'-vm', copyIndex(1), '-publicIp')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "Standard"
      },
      "copy": {
        "name": "publicIPAddressCopy",
        "count": 3
      },
      "properties": {
        "publicIPAddressVersion": "IPv4",
        "publicIPAllocationMethod": "Static"
      }
    },
    {
      "type": "Microsoft.Network/networkInterfaces",
      "apiVersion": "2018-12-01",
      "name": "[concat(parameters('projectName'),'-vm', copyIndex(1), '-networkInterface')]",
      "location": "[parameters('location')]",
      "copy": {
        "name": "networkInterfaceCopy",
        "count": 3
      },
      "dependsOn": [
        "[resourceId('Microsoft.Network/virtualNetworks/', variables('vNetName'))]",
        "[resourceId('Microsoft.Network/loadBalancers/', variables('lbName'))]",
        "[resourceId('Microsoft.Network/networkSecurityGroups/', variables('nsgName'))]",
        "publicIPAddressCopy"
      ],
      "properties": {
        "ipConfigurations": [
          {
            "name": "ipconfig1",
            "properties": {
              "privateIPAllocationMethod": "Dynamic",
              "subnet": {
                "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('vNetName'), variables('vNetSubnetName'))]"
              },
              "publicIpAddress": {
                "id": "[resourceId('Microsoft.Network/publicIpAddresses', concat(parameters('projectName'),'-vm', copyIndex(1), '-publicIp'))]"
              },
              "loadBalancerBackendAddressPools": [
                {
                  "id": "[resourceId('Microsoft.Network/loadBalancers/backendAddressPools', variables('lbName'), variables('lbBackendPoolName'))]"
                }
              ]
            }
          }
        ],
        "networkSecurityGroup": {
          "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('nsgName'))]"
        }
      }
    },
    {
      "type": "Microsoft.Compute/virtualMachines/extensions",
      "apiVersion": "2018-10-01",
      "name": "[concat(parameters('projectName'),'-vm', copyIndex(1), '/', 'InstallWebServer')]",
      "location": "[parameters('location')]",
      "copy": {
        "name": "extensionCopy",
        "count": 3
      },
      "dependsOn": [
        "vmCopy"
      ],
      "properties": {
        "publisher": "Microsoft.Compute",
        "type": "CustomScriptExtension",
        "typeHandlerVersion": "1.7",
        "autoUpgradeMinorVersion": true,
        "settings": {
          "commandToExecute": "powershell.exe Install-WindowsFeature -name Web-Server -IncludeManagementTools && powershell.exe remove-item 'C:\\inetpub\\wwwroot\\iisstart.htm' && powershell.exe Add-Content -Path 'C:\\inetpub\\wwwroot\\iisstart.htm' -Value $('Hello World from ' + $env:computername)"
        }
      }
    }
  ]
}

Multiple Azure resources have been defined in the template:

To find more templates that are related to Azure Load Balancer, see Azure Quickstart Templates.

Deploy the template

  1. Select Try it from the following code block to open Azure Cloud Shell, and then follow the instructions to sign in to Azure.

    $projectName = Read-Host -Prompt "Enter a project name with 12 or less letters or numbers that is used to generate Azure resource names"
    $location = Read-Host -Prompt "Enter the location (i.e. centralus)"
    $adminUserName = Read-Host -Prompt "Enter the virtual machine administrator account name"
    $adminPassword = Read-Host -Prompt "Enter the virtual machine administrator password" -AsSecureString
    
    $resourceGroupName = "${projectName}rg"
    $templateUri = "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/101-load-balancer-standard-create/azuredeploy.json"
    
    New-AzResourceGroup -Name $resourceGroupName -Location $location
    New-AzResourceGroupDeployment -ResourceGroupName $resourceGroupName -TemplateUri $templateUri -projectName $projectName -location $location -adminUsername $adminUsername -adminPassword $adminPassword
    
    Write-Host "Press [ENTER] to continue."
    

    Wait until you see the prompt from the console.

  2. Select Copy from the previous code block to copy the PowerShell script.

  3. Right-click the shell console pane and then select Paste.

  4. Enter the values.

    The template deployment creates three availability zones. Availability zones are supported only in certain regions. Use one of the supported regions. If you aren't sure, enter centralus.

    The resource group name is the project name with rg appended. You need the resource group name in the next section.

It takes about 10 minutes to deploy the template. When completed, the output is similar to:

Azure Standard Load Balancer Resource Manager template PowerShell deployment output

Azure PowerShell is used to deploy the template. In addition to Azure PowerShell, you can also use the Azure portal, Azure CLI, and REST API. To learn other deployment methods, see Deploy templates.

Review deployed resources

  1. Sign in to the Azure portal.

  2. Select Resource groups from the left pane.

  3. Select the resource group that you created in the previous section. The default resource group name is the project name with rg appended.

  4. Select the load balancer. Its default name is the project name with -lb appended.

  5. Copy only the IP address part of the public IP address, and then paste it into the address bar of your browser.

    Azure standard load balancer Resource Manager template public IP

    The browser displays the default page of the Internet Information Services (IIS) web server.

    IIS web server

To see the load balancer distribute traffic across all three VMs, you can force a refresh of your web browser from the client machine.

Clean up resources

When you no longer need them, delete the resource group, the load balancer, and all related resources. To do so, go to the Azure portal, select the resource group that contains the load balancer, and then select Delete resource group.

Next steps

In this quickstart, you created a Standard load balancer, attached VMs to it, configured the load-balancer traffic rule, did a health probe, and then tested the load balancer.

To learn more, continue to the tutorials for Load Balancer.