VMSS is able to behind both Internal and External Load Balancer, just like VMs. I have modified the template in Github, so you deploy two LBs.
https://github.com/Azure/azure-quickstart-templates/tree/master/201-vmss-linux-nat
Here is a template example:
{ "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json", "contentVersion": "1.0.0.0", "parameters": { "vmSku": { "type": "string", "defaultValue": "Standard_A1", "metadata": { "description": "Size of VMs in the VM Scale Set." } }, "ubuntuOSVersion": { "type": "string", "defaultValue": "16.04-LTS", "allowedValues": [ "14.04.4-LTS", "16.04-LTS" ], "metadata": { "description": "The Ubuntu version for the VM. This will pick a fully patched image of this given Ubuntu version. Allowed values are: 14.04.4-LTS, 16.04-LTS." } }, "vmssName": { "type": "string", "metadata": { "description": "String used as a base for naming resources. Must be 3-61 characters in length and globally unique across Azure. A hash is prepended to this string for some resources, and resource-specific information is appended." }, "maxLength": 61 }, "instanceCount": { "type": "int", "metadata": { "description": "Number of VM instances (100 or less)." }, "maxValue": 100 }, "adminUsername": { "type": "string", "metadata": { "description": "Admin username on all VMs." } }, "adminPassword": { "type": "securestring", "metadata": { "description": "Admin password on all VMs." } } }, "variables": { "namingInfix": "[toLower(substring(concat(parameters('vmssName'), uniqueString(resourceGroup().id)), 0, 9))]", "longNamingInfix": "[toLower(parameters('vmssName'))]", "addressPrefix": "10.0.0.0/16", "subnetPrefix": "10.0.0.0/24", "virtualNetworkName": "[concat(variables('namingInfix'), 'vnet')]", "publicIPAddressName": "[concat(variables('namingInfix'), 'pip')]", "subnetName": "[concat(variables('namingInfix'), 'subnet')]", "vnetID": "[resourceId('Microsoft.Network/virtualNetworks',variables('virtualNetworkName'))]", "subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]", "loadBalancerName": "[concat(variables('namingInfix'), 'lb')]", "iloadBalancerName": "[concat(variables('namingInfix'), 'ilb')]", "publicIPAddressID": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]", "lbID": "[resourceId('Microsoft.Network/loadBalancers',variables('loadBalancerName'))]", "ilbID": "[resourceId('Microsoft.Network/loadBalancers',variables('iloadBalancerName'))]", "natPoolName": "[concat(variables('namingInfix'), 'natpool')]", "bePoolName": "[concat(variables('namingInfix'), 'bepool')]", "natStartPort": 50000, "natEndPort": 50119, "natBackendPort": 22, "nicName": "[concat(variables('namingInfix'), 'nic')]", "ipConfigName": "[concat(variables('namingInfix'), 'ipconfig')]", "frontEndIPConfigID": "[concat(variables('lbID'),'/frontendIPConfigurations/loadBalancerFrontEnd')]", "ifrontEndIPConfigID": "[concat(variables('ilbID'),'/frontendIPConfigurations/loadBalancerFrontEnd')]", "osType": { "publisher": "Canonical", "offer": "UbuntuServer", "sku": "[parameters('ubuntuOSVersion')]", "version": "latest" }, "imageReference": "[variables('osType')]", "computeApiVersion": "2017-03-30", "networkApiVersion": "2017-04-01", "storageApiVersion": "2015-06-15" }, "resources": [ { "type": "Microsoft.Network/virtualNetworks", "name": "[variables('virtualNetworkName')]", "location": "[resourceGroup().location]", "apiVersion": "[variables('networkApiVersion')]", "properties": { "addressSpace": { "addressPrefixes": [ "[variables('addressPrefix')]" ] }, "subnets": [ { "name": "[variables('subnetName')]", "properties": { "addressPrefix": "[variables('subnetPrefix')]" } } ] } }, { "type": "Microsoft.Network/publicIPAddresses", "name": "[variables('publicIPAddressName')]", "location": "[resourceGroup().location]", "apiVersion": "[variables('networkApiVersion')]", "properties": { "publicIPAllocationMethod": "Dynamic", "dnsSettings": { "domainNameLabel": "[variables('longNamingInfix')]" } } }, { "type": "Microsoft.Network/loadBalancers", "name": "[variables('loadBalancerName')]", "location": "[resourceGroup().location]", "apiVersion": "[variables('networkApiVersion')]", "dependsOn": [ "[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]" ], "properties": { "frontendIPConfigurations": [ { "name": "LoadBalancerFrontEnd", "properties": { "publicIPAddress": { "id": "[variables('publicIPAddressID')]" } } } ], "backendAddressPools": [ { "name": "[variables('bePoolName')]" } ], "inboundNatPools": [ { "name": "[variables('natPoolName')]", "properties": { "frontendIPConfiguration": { "id": "[variables('frontEndIPConfigID')]" }, "protocol": "tcp", "frontendPortRangeStart": "[variables('natStartPort')]", "frontendPortRangeEnd": "[variables('natEndPort')]", "backendPort": "[variables('natBackendPort')]" } } ], "loadBalancingRules": [ { "properties": { "frontendIPConfiguration": { "id": "[variables('frontEndIPConfigID')]" }, "backendAddressPool": { "id": "[concat(resourceId('Microsoft.Network/loadBalancers', variables('loadBalancerName')), '/backendAddressPools/', variables('bePoolName'))]" }, "probe": { "id": "[concat(resourceId('Microsoft.Network/loadBalancers', variables('loadBalancerName')), '/probes/lbprobe')]" }, "protocol": "Tcp", "frontendPort": 80, "backendPort": 80, "idleTimeoutInMinutes": 15 }, "name": "lbrule" } ], "probes": [ { "properties": { "protocol": "Tcp", "port": 22, "intervalInSeconds": 15, "numberOfProbes": 2 }, "name": "lbprobe" } ] } }, { "type": "Microsoft.Network/loadBalancers", "name": "[variables('iloadBalancerName')]", "location": "[resourceGroup().location]", "apiVersion": "[variables('networkApiVersion')]", "dependsOn": [ "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" ], "properties": { "frontendIPConfigurations": [ { "name": "LoadBalancerFrontEnd", "properties": { "subnet": { "id": "[variables('subnetRef')]" } } } ], "backendAddressPools": [ { "name": "[variables('bePoolName')]" } ], "loadBalancingRules": [ { "properties": { "frontendIPConfiguration": { "id": "[variables('ifrontEndIPConfigID')]" }, "backendAddressPool": { "id": "[concat(resourceId('Microsoft.Network/loadBalancers', variables('iloadBalancerName')), '/backendAddressPools/', variables('bePoolName'))]" }, "probe": { "id": "[concat(resourceId('Microsoft.Network/loadBalancers', variables('iloadBalancerName')), '/probes/lbprobe')]" }, "protocol": "Tcp", "frontendPort": 80, "backendPort": 80, "idleTimeoutInMinutes": 15 }, "name": "lbrule" } ], "probes": [ { "properties": { "protocol": "Tcp", "port": 22, "intervalInSeconds": 15, "numberOfProbes": 2 }, "name": "lbprobe" } ] } }, { "type": "Microsoft.Compute/virtualMachineScaleSets", "name": "[variables('namingInfix')]", "location": "[resourceGroup().location]", "apiVersion": "[variables('computeApiVersion')]", "dependsOn": [ "[concat('Microsoft.Network/loadBalancers/', variables('loadBalancerName'))]", "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]" ], "sku": { "name": "[parameters('vmSku')]", "tier": "Standard", "capacity": "[parameters('instanceCount')]" }, "properties": { "overprovision": "true", "upgradePolicy": { "mode": "Manual" }, "virtualMachineProfile": { "storageProfile": { "osDisk": { "createOption": "FromImage", "caching": "ReadWrite" }, "imageReference": "[variables('imageReference')]" }, "osProfile": { "computerNamePrefix": "[variables('namingInfix')]", "adminUsername": "[parameters('adminUsername')]", "adminPassword": "[parameters('adminPassword')]" }, "networkProfile": { "networkInterfaceConfigurations": [ { "name": "[variables('nicName')]", "properties": { "primary": "true", "ipConfigurations": [ { "name": "[variables('ipConfigName')]", "properties": { "subnet": { "id": "[concat('/subscriptions/', subscription().subscriptionId,'/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'), '/subnets/', variables('subnetName'))]" }, "loadBalancerBackendAddressPools": [ { "id": "[concat('/subscriptions/', subscription().subscriptionId,'/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Network/loadBalancers/', variables('loadBalancerName'), '/backendAddressPools/', variables('bePoolName'))]" }, { "id": "[concat('/subscriptions/', subscription().subscriptionId,'/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Network/loadBalancers/', variables('iloadBalancerName'), '/backendAddressPools/', variables('bePoolName'))]" } ], "loadBalancerInboundNatPools": [ { "id": "[concat('/subscriptions/', subscription().subscriptionId,'/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Network/loadBalancers/', variables('loadBalancerName'), '/inboundNatPools/', variables('natPoolName'))]" } ] } } ] } } ] } } } } ] }
If you search the template, you will see there are two LBs,
“name”: “[variables(‘iloadBalancerName’)]”, // This is internal LB
“name”: “[variables(‘loadBalancerName’)]”,
After deployment, I have resources like this:
There are two load balancers, both of them have VMSS as the backend pool.
NAT rules are configured on the external LB, so I am able to putty to instances via the LB frontend IP.
Access web from internet
Build up a test VM in the same VNET and access internal LB frontend IP.