Deploying an Auto-Scaling VM Scale Set with a Custom Disk Image

With the disk image location on hand; I was able to use an ARM template to deploy my scale set while specifying my custom disk image.

Creating the Scale Set Template

Although I was a coder at one time and know my way around ARM templates a bit, I will be the first to admit that I am not an ARM template expert.  Lucky for me, there are scale set ARM templates published all over the internet.  All I had to do was pull one down and modify it for my needs.

After pulling down this scale set ARM template, I went ahead and made a few minor modifications:

  • Added custom disk reference (see orange code below)
  • Added autoscale code (see red code below)
  • Changed name reference (just some template cleanup)
  • Changed instance values (see blue code below)

The complete template, including the autoscale settings is below:

 
 
  1. {
  2. "$schema": "http://schema.management.azure.com/schemas/2015-01-01-preview/deploymentTemplate.json",
  3. "contentVersion": "1.0.0.0",
  4. "parameters": {
  5. "vmSku": {
  6. "defaultValue": "Standard_DS1_V2",
  7. "type": "String",
  8. "metadata": {
  9. "description": "Size of VMs in the VM Scale Set."
  10. }
  11. },
  12. "vmssName": {
  13. "type": "string",
  14. "metadata": {
  15. "description": "Name of the VM scale set."
  16. }
  17.       },
  18. "instanceCount": {
  19. "maxValue": 3,
  20. "type": "Int",
  21. "metadata": {
  22. "description": "Number of VM instances (100 or less)."
  23. }
  24. },
  25. "adminUsername": {
  26. "type": "String",
  27. "metadata": {
  28. "description": "Admin username on all VMs."
  29. }
  30. },
  31. "adminPassword": {
  32. "type": "SecureString",
  33. "metadata": {
  34. "description": "Admin password on all VMs."
  35. }
  36. },
  37. "osType": {
  38. "allowedValues": [
  39. "Windows",
  40. "Linux"
  41. ],
  42. "type": "String"
  43. }
  44. },
  45. "variables": {
  46. "namingInfix": "[toLower(substring(concat(parameters('vmssName'), uniqueString(resourceGroup().id)), 0, 9))]",
  47. "longNamingInfix": "[toLower(parameters('vmssName'))]",
  48. "vhdContainerName": "[concat(variables('namingInfix'), 'vhd')]",
  49. "addressPrefix": "10.0.0.0/16",
  50. "subnetPrefix": "10.0.0.0/24",
  51. "virtualNetworkName": "[concat(variables('namingInfix'), 'vnet')]",
  52. "publicIPAddressName": "[concat(variables('namingInfix'), 'pip')]",
  53. "subnetName": "[concat(variables('namingInfix'), 'subnet')]",
  54. "loadBalancerName": "[concat(variables('namingInfix'), 'lb')]",
  55. "publicIPAddressID": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]",
  56. "lbID": "[resourceId('Microsoft.Network/loadBalancers',variables('loadBalancerName'))]",
  57. "natPoolName": "[concat(variables('namingInfix'), 'natpool')]",
  58. "bePoolName": "[concat(variables('namingInfix'), 'bepool')]",
  59. "natStartPort": 50000,
  60. "natEndPort": 50119,
  61. "natBackendPort": 22,
  62. "nicName": "[concat(variables('namingInfix'), 'nic')]",
  63. "ipConfigName": "[concat(variables('namingInfix'), 'ipconfig')]",
  64. "frontEndIPConfigID": "[concat(variables('lbID'),'/frontendIPConfigurations/loadBalancerFrontEnd')]",
  65. "computeApiVersion": "2016-04-30-preview",
  66. "networkApiVersion": "2016-03-30",
  67.       "insightsApiVersion": "2015-04-01",
  68.       "location": "[resourceGroup().location]"
  69. },
  70. "resources": [
  71. {
  72. "type": "Microsoft.Network/virtualNetworks",
  73. "name": "[variables('virtualNetworkName')]",
  74. "apiVersion": "[variables('networkApiVersion')]",
  75. "location": "[resourceGroup().location]",
  76. "properties": {
  77. "addressSpace": {
  78. "addressPrefixes": [
  79. "[variables('addressPrefix')]"
  80. ]
  81. },
  82. "subnets": [
  83. {
  84. "name": "[variables('subnetName')]",
  85. "properties": {
  86. "addressPrefix": "[variables('subnetPrefix')]"
  87. }
  88. }
  89. ]
  90. }
  91. },
  92. {
  93. "type": "Microsoft.Network/publicIPAddresses",
  94. "name": "[variables('publicIPAddressName')]",
  95. "apiVersion": "[variables('networkApiVersion')]",
  96. "location": "[resourceGroup().location]",
  97. "properties": {
  98. "publicIPAllocationMethod": "Dynamic",
  99. "dnsSettings": {
  100. "domainNameLabel": "[variables('longNamingInfix')]"
  101. }
  102. }
  103. },
  104. {
  105. "type": "Microsoft.Network/loadBalancers",
  106. "name": "[variables('loadBalancerName')]",
  107. "apiVersion": "[variables('networkApiVersion')]",
  108. "location": "[resourceGroup().location]",
  109. "properties": {
  110. "frontendIPConfigurations": [
  111. {
  112. "name": "LoadBalancerFrontEnd",
  113. "properties": {
  114. "publicIPAddress": {
  115. "id": "[variables('publicIPAddressID')]"
  116. }
  117. }
  118. }
  119. ],
  120. "backendAddressPools": [
  121. {
  122. "name": "[variables('bePoolName')]"
  123. }
  124. ],
  125. "inboundNatPools": [
  126. {
  127. "name": "[variables('natPoolName')]",
  128. "properties": {
  129. "frontendIPConfiguration": {
  130. "id": "[variables('frontEndIPConfigID')]"
  131. },
  132. "protocol": "tcp",
  133. "frontendPortRangeStart": "[variables('natStartPort')]",
  134. "frontendPortRangeEnd": "[variables('natEndPort')]",
  135. "backendPort": "[variables('natBackendPort')]"
  136. }
  137. }
  138. ]
  139. },
  140. "dependsOn": [
  141. "[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]"
  142. ]
  143. },
  144. {
  145. "type": "Microsoft.Compute/virtualMachineScaleSets",
  146. "sku": {
  147. "name": "[parameters('vmSku')]",
  148. "tier": "Standard",
  149. "capacity": "[parameters('instanceCount')]"
  150. },
  151. "name": "[parameters('vmssName')]",
  152. "apiVersion": "[variables('computeApiVersion')]",
  153. "location": "[resourceGroup().location]",
  154. "properties": {
  155. "overprovision": "true",
  156. "upgradePolicy": {
  157. "mode": "Manual"
  158. },
  159. "virtualMachineProfile": {
  160. "storageProfile": {
  161. "imageReference": {
  162. "id": "/subscriptions/9cbf5438-a4a1-4227-8a0d-18e92fe2e472/resourceGroups/vmssdemo/providers/Microsoft.Compute/images/GoldImage"
  163. }
  164. },
  165. "osProfile": {
  166. "computerNamePrefix": "[variables('namingInfix')]",
  167. "adminUsername": "[parameters('adminUsername')]",
  168. "adminPassword": "[parameters('adminPassword')]"
  169. },
  170. "networkProfile": {
  171. "networkInterfaceConfigurations": [
  172. {
  173. "name": "[variables('nicName')]",
  174. "properties": {
  175. "primary": "true",
  176. "ipConfigurations": [
  177. {
  178. "name": "[variables('ipConfigName')]",
  179. "properties": {
  180. "subnet": {
  181. "id": "[concat('/subscriptions/', subscription().subscriptionId,'/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'), '/subnets/', variables('subnetName'))]"
  182. },
  183. "loadBalancerBackendAddressPools": [
  184. {
  185. "id": "[concat('/subscriptions/', subscription().subscriptionId,'/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Network/loadBalancers/', variables('loadBalancerName'), '/backendAddressPools/', variables('bePoolName'))]"
  186. }
  187. ],
  188. "loadBalancerInboundNatPools": [
  189. {
  190. "id": "[concat('/subscriptions/', subscription().subscriptionId,'/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Network/loadBalancers/', variables('loadBalancerName'), '/inboundNatPools/', variables('natPoolName'))]"
  191. }
  192. ]
  193. }
  194. }
  195. ]
  196. }
  197. }
  198. ]
  199. }
  200. }
  201. },
  202. "dependsOn": [
  203. "[concat('Microsoft.Network/loadBalancers/', variables('loadBalancerName'))]",
  204. "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]"
  205. ]
  206. },
  207. {
  208. "type": "Microsoft.Insights/autoscaleSettings",
  209. "apiVersion": "[variables('insightsApiVersion')]",
  210. "name": "autoscalehosts",
  211. "location": "[variables('location')]",
  212. "dependsOn": [
  213. "[concat('Microsoft.Compute/virtualMachineScaleSets/', parameters('vmssName'))]"
  214. ],
  215. "properties": {
  216. "enabled": true,
  217. "name": "autoscalehosts",
  218. "profiles": [
  219. {
  220. "name": "Profile1",
  221. "capacity": {
  222. "minimum": "1",
  223. "maximum": "3",
  224. "default": "1"
  225. },
  226. "rules": [
  227. {
  228. "metricTrigger": {
  229. "metricName": "Percentage CPU",
  230. "metricNamespace": "",
  231. "metricResourceUri": "[concat('/subscriptions/',subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Compute/virtualMachineScaleSets/', parameters('vmSSName'))]",
  232. "timeGrain": "PT1M",
  233. "statistic": "Average",
  234. "timeWindow": "PT5M",
  235. "timeAggregation": "Average",
  236. "operator": "GreaterThan",
  237. "threshold": 60.0
  238. },
  239. "scaleAction": {
  240. "direction": "Increase",
  241. "type": "ChangeCount",
  242. "value": "1",
  243. "cooldown": "PT1M"
  244. }
  245. },
  246. {
  247. "metricTrigger": {
  248. "metricName": "Percentage CPU",
  249. "metricNamespace": "",
  250. "metricResourceUri": "[concat('/subscriptions/',subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Compute/virtualMachineScaleSets/', parameters('vmSSName'))]",
  251. "timeGrain": "PT1M",
  252. "statistic": "Average",
  253. "timeWindow": "PT5M",
  254. "timeAggregation": "Average",
  255. "operator": "LessThan",
  256. "threshold": 30.0
  257. },
  258. "scaleAction": {
  259. "direction": "Decrease",
  260. "type": "ChangeCount",
  261. "value": "1",
  262. "cooldown": "PT1M"
  263. }
  264. }
  265. ]
  266. }
  267. ],
  268. "targetResourceUri": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Compute/virtualMachineScaleSets/', parameters('vmSSName'))]"
  269. }
  270. }
  271. ]
  272. }

 

Click here to join the Understanding Azure Facebook group or here for the latest Azure practice questions, answers, explanations, and reference materials.

Thomas Mitchell

Tom is a 20+ year veteran of the IT industry and carries numerous Microsoft certifications, including the MCSE: Cloud Platform and Infrastructure certification. A Subject Matter Expert in Active Directory and Microsoft Exchange, Tom also possesses expert-level knowledge in several other IT disciplines, including Azure, Storage, and O365/Exchange Online. You can find Tom at his website, on LinkedIn, or on Facebook. Need to reach him by phone? Call 484-334-2790.

"