IaC on Azure – Windows Server Virtual Machine Deployment made easy with ARM Template

2017-02-25-azure-iac-arm-json-template-for-virtual-machine

2 weeks ago, I touched on the topic of Infrastructure as Code (IaC), their benefits and an example on how to consistently create an Azure resource group for deploying a virtual network with a set of subnets and a gateway subnet.

As a continuation of the previous An introduction to Infrastructure as Code (IaC) using Azure Resource Manager (ARM) Template, I will be sharing with you on using Template to consistently create an Azure resource group for deploying a virtual machine with an independent virtual network subnet, and attach a public IP address for remote desktop connection to the virtual machine in the cloud.

Before we begin, it will be advisable to view the previous blog post on how to create a template within Azure Templates service for those that have not view the last blog post. That previous blog post will explain on how to implement the JSON code below where you will have to copy, paste it into the newly created template name (Eg. iaas_virtual_machine_windowserver_v1 ) of your choice, save it and select deploy.

Since I am creating a generic ARM template that must be able to deploy the different types of VM size in all region, the following JSON code will only contain VM Size of A0-A7, D1_v2-D15_v2 and F1-F16 series based on the list in Products available by region. If you are interested in the differences between the different types of VM Size, you can refer to this Sizes for Windows virtual machines in Azure document for more details.

 

Let us begin...

 

1. Copy the JSON code below, paste it into the new ARM Template and save it

 
{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "virtualNetworksName": {
            "type": "string",
            "defaultValue": null,
            "metadata": {
                "description": "The name of the virtual network for the virtual machine."
            }
        },
        "virtualNetworkAddressPrefix": {
            "type": "string",
            "defaultValue": null,
            "minLength": 9,
            "maxLength": 18,
            "metadata": {
                "description": "The IP addresses prefixes for the virtual network. (Eg. 10.1.0.0/16 )"
            }
        },
        "virtualNetworkSubnetName": {
            "type": "string",
            "defaultValue": null,
            "metadata": {
                "description": "The name of the virtual network subnet. (Eg. Subnet-Dev )"
            }
        },
        "virtualNetworkSubnetAddressPrefix": {
            "type": "string",
            "defaultValue": null,
            "minLength": 9,
            "maxLength": 18,
            "metadata": {
                "description": "The IP addresses prefixes for the virtual network. (Eg. 10.1.1.0/24 )"
            }
        },
        "storageAccountsName": {
            "type": "string",
            "defaultValue": null,
            "minLength": 3,
            "maxLength": 24,
            "metadata": {
                "description": "The name of the storage account for storing the virtual machine."
            }
        },
        "virtualMachineName": {
            "type": "string",
            "defaultValue": null,
            "metadata": {
                "description": "The name of the virtual machine."
            }
        },
       "virtualMachineSize": {
           "type": "string",
           "allowedValues": [
               "Standard_A0", "Standard_A1", "Standard_A2", "Standard_A3",
               "Standard_A4", "Standard_A5", "Standard_A6", "Standard_A7",
               
               "Standard_D1_v2", "Standard_D2_v2", "Standard_D3_v2", "Standard_D4_v2",
               "Standard_D5_v2", "Standard_D6_v2", "Standard_D7_v2", "Standard_D8_v2",
               "Standard_D9_v2", "Standard_D10_v2", "Standard_D11_v2", "Standard_D12_v2",
               "Standard_D13_v2", "Standard_D14_v2", "Standard_D15_v2",

               "Standard_F1", "Standard_F2", "Standard_F4", "Standard_F8", "Standard_F16"
           ],
           "defaultValue": "Standard_A0",
           "metadata": {
               "description": "The size of the virtual machine."
           }
       },
       "virtualMachineDataDiskSize": {
            "type": "int",
            "defaultValue": 40,
            "minValue": 10,
            "maxValue": 1023,
            "metadata": {
                "description": "The GB size of the data disk for the virtual machine."
            }
       },
       "virtualMachineSKU":{
           "type": "string",
           "allowedValues": [
               "2008-R2-SP1",
               "2008-R2-SP1-BYOL",
               "2012-Datacenter",
               "2012-Datacenter-BYOL",
               "2012-R2-Datacenter",
               "2012-R2-Datacenter-BYOL",
               "2016-Datacenter",
               "2016-Datacenter-with-Containers",
               "2016-Nano-Server"
           ],
           "defaultValue": "2016-Datacenter",
           "metadata": {
               "description": "The SKU of the Windows Server virtual machine."
           }
       },
        "virtualMachineNetworkInterfacesName": {
            "type": "string",
            "defaultValue": null,
            "metadata": {
                "description": "The name of the network interface for the virtual machine."
            }
        },
        "virtualMachinePublicIPAddressesName": {
            "type": "string",
            "defaultValue": null,
            "metadata": {
                "description": "The name of the public IP addresses for the virtual machine."
            }
        },
        "virtualMachineAdminUsername": {
            "type": "string",
            "defaultValue": null,
            "metadata": {
                "description": "The administrator username for the virtual machine."
            }
        },
        "virtualMachineAdminPassword": {
            "type": "securestring",
            "defaultValue": null,
            "metadata": {
                "description": "The administrator password for the virtual machine."
            }
        },
        "resourceOwnerNameTag": {
            "type": "string",
            "defaultValue": null,
            "metadata": {
                "description": "The name of the resource owner for the Owner Name tag."
            }
        },
        "businessUnitTag": {
            "type": "string",
            "defaultValue": null,
            "metadata": {
                "description": "The name of the department for the Business Unit tag."
            }
        },
        "costCenterTag": {
            "type": "string",
            "defaultValue": null,
            "metadata": {
                "description": "A cost identifier for the Cost Center tag."
            }
        },
        "environmentTag": {
            "allowedValues": [
                null,
                "Development",
                "Staging",
                "Production"
            ],
            "type": "string",
            "defaultValue": null,
            "metadata": {
                "description": "The name for the Environment tag."
            }
        },
        "maintenanceWindowStartTag": {
            "allowedValues": [
                null,
                "Mon 00:00", "Mon 01:00", "Mon 02:00", "Mon 03:00", "Mon 04:00", "Mon 05:00", 
                "Mon 06:00", "Mon 07:00", "Mon 08:00", "Mon 09:00", "Mon 10:00", "Mon 11:00", 
                "Mon 12:00", "Mon 13:00", "Mon 14:00", "Mon 15:00", "Mon 16:00", "Mon 17:00", 
                "Mon 18:00", "Mon 19:00", "Mon 20:00", "Mon 21:00", "Mon 22:00", "Mon 23:00",
                "Tue 00:00", "Tue 01:00", "Tue 02:00", "Tue 03:00", "Tue 04:00", "Tue 05:00",
                "Tue 06:00", "Tue 07:00", "Tue 08:00", "Tue 09:00", "Tue 10:00", "Tue 11:00",
                "Tue 12:00", "Tue 13:00", "Tue 14:00", "Tue 15:00", "Tue 16:00", "Tue 17:00",
                "Tue 18:00", "Tue 19:00", "Tue 20:00", "Tue 21:00", "Tue 22:00", "Tue 23:00",
                "Wed 00:00", "Wed 01:00", "Wed 02:00", "Wed 03:00", "Wed 04:00", "Wed 05:00",
                "Wed 06:00", "Wed 07:00", "Wed 08:00", "Wed 09:00", "Wed 10:00", "Wed 11:00",
                "Wed 12:00", "Wed 13:00", "Wed 14:00", "Wed 15:00", "Wed 16:00", "Wed 17:00",
                "Wed 18:00", "Wed 19:00", "Wed 20:00", "Wed 21:00", "Wed 22:00", "Wed 23:00",
                "Thu 00:00", "Thu 01:00", "Thu 02:00", "Thu 03:00", "Thu 04:00", "Thu 05:00",
                "Thu 06:00", "Thu 07:00", "Thu 08:00", "Thu 09:00", "Thu 10:00", "Thu 11:00",
                "Thu 12:00", "Thu 13:00", "Thu 14:00", "Thu 15:00", "Thu 16:00", "Thu 17:00",
                "Thu 18:00", "Thu 19:00", "Thu 20:00", "Thu 21:00", "Thu 22:00", "Thu 23:00",
                "Fri 00:00", "Fri 01:00", "Fri 02:00", "Fri 03:00", "Fri 04:00", "Fri 05:00",
                "Fri 06:00", "Fri 07:00", "Fri 08:00", "Fri 09:00", "Fri 10:00", "Fri 11:00",
                "Fri 12:00", "Fri 13:00", "Fri 14:00", "Fri 15:00", "Fri 16:00", "Fri 17:00",
                "Fri 18:00", "Fri 19:00", "Fri 20:00", "Fri 21:00", "Fri 22:00", "Fri 23:00",
                "Sat 00:00", "Sat 01:00", "Sat 02:00", "Sat 03:00", "Sat 04:00", "Sat 05:00",
                "Sat 06:00", "Sat 07:00", "Sat 08:00", "Sat 09:00", "Sat 10:00", "Sat 11:00",
                "Sat 12:00", "Sat 13:00", "Sat 14:00", "Sat 15:00", "Sat 16:00", "Sat 17:00",
                "Sat 18:00", "Sat 19:00", "Sat 20:00", "Sat 21:00", "Sat 22:00", "Sat 23:00",
                "Sun 00:00", "Sun 01:00", "Sun 02:00", "Sun 03:00", "Sun 04:00", "Sun 05:00",
                "Sun 06:00", "Sun 07:00", "Sun 08:00", "Sun 09:00", "Sun 10:00", "Sun 11:00",
                "Sun 12:00", "Sun 13:00", "Sun 14:00", "Sun 15:00", "Sun 16:00", "Sun 17:00",
                "Sun 18:00", "Sun 19:00", "Sun 20:00", "Sun 21:00", "Sun 22:00", "Sun 23:00"
            ],
            "type": "string",
            "defaultValue": null,
            "metadata": {
                "description": "The start of the maintenance (Mon, Tue, Wed, Thu, Fri, Sat or Sun HH:mm) schedule of the resource for Maintenance Window Start tag."
            }
        },
        "maintenanceWindowEndTag": {
            "allowedValues": [
                null,
                "Mon 00:00", "Mon 01:00", "Mon 02:00", "Mon 03:00", "Mon 04:00", "Mon 05:00", 
                "Mon 06:00", "Mon 07:00", "Mon 08:00", "Mon 09:00", "Mon 10:00", "Mon 11:00", 
                "Mon 12:00", "Mon 13:00", "Mon 14:00", "Mon 15:00", "Mon 16:00", "Mon 17:00", 
                "Mon 18:00", "Mon 19:00", "Mon 20:00", "Mon 21:00", "Mon 22:00", "Mon 23:00",
                "Tue 00:00", "Tue 01:00", "Tue 02:00", "Tue 03:00", "Tue 04:00", "Tue 05:00",
                "Tue 06:00", "Tue 07:00", "Tue 08:00", "Tue 09:00", "Tue 10:00", "Tue 11:00",
                "Tue 12:00", "Tue 13:00", "Tue 14:00", "Tue 15:00", "Tue 16:00", "Tue 17:00",
                "Tue 18:00", "Tue 19:00", "Tue 20:00", "Tue 21:00", "Tue 22:00", "Tue 23:00",
                "Wed 00:00", "Wed 01:00", "Wed 02:00", "Wed 03:00", "Wed 04:00", "Wed 05:00",
                "Wed 06:00", "Wed 07:00", "Wed 08:00", "Wed 09:00", "Wed 10:00", "Wed 11:00",
                "Wed 12:00", "Wed 13:00", "Wed 14:00", "Wed 15:00", "Wed 16:00", "Wed 17:00",
                "Wed 18:00", "Wed 19:00", "Wed 20:00", "Wed 21:00", "Wed 22:00", "Wed 23:00",
                "Thu 00:00", "Thu 01:00", "Thu 02:00", "Thu 03:00", "Thu 04:00", "Thu 05:00",
                "Thu 06:00", "Thu 07:00", "Thu 08:00", "Thu 09:00", "Thu 10:00", "Thu 11:00",
                "Thu 12:00", "Thu 13:00", "Thu 14:00", "Thu 15:00", "Thu 16:00", "Thu 17:00",
                "Thu 18:00", "Thu 19:00", "Thu 20:00", "Thu 21:00", "Thu 22:00", "Thu 23:00",
                "Fri 00:00", "Fri 01:00", "Fri 02:00", "Fri 03:00", "Fri 04:00", "Fri 05:00",
                "Fri 06:00", "Fri 07:00", "Fri 08:00", "Fri 09:00", "Fri 10:00", "Fri 11:00",
                "Fri 12:00", "Fri 13:00", "Fri 14:00", "Fri 15:00", "Fri 16:00", "Fri 17:00",
                "Fri 18:00", "Fri 19:00", "Fri 20:00", "Fri 21:00", "Fri 22:00", "Fri 23:00",
                "Sat 00:00", "Sat 01:00", "Sat 02:00", "Sat 03:00", "Sat 04:00", "Sat 05:00",
                "Sat 06:00", "Sat 07:00", "Sat 08:00", "Sat 09:00", "Sat 10:00", "Sat 11:00",
                "Sat 12:00", "Sat 13:00", "Sat 14:00", "Sat 15:00", "Sat 16:00", "Sat 17:00",
                "Sat 18:00", "Sat 19:00", "Sat 20:00", "Sat 21:00", "Sat 22:00", "Sat 23:00",
                "Sun 00:00", "Sun 01:00", "Sun 02:00", "Sun 03:00", "Sun 04:00", "Sun 05:00",
                "Sun 06:00", "Sun 07:00", "Sun 08:00", "Sun 09:00", "Sun 10:00", "Sun 11:00",
                "Sun 12:00", "Sun 13:00", "Sun 14:00", "Sun 15:00", "Sun 16:00", "Sun 17:00",
                "Sun 18:00", "Sun 19:00", "Sun 20:00", "Sun 21:00", "Sun 22:00", "Sun 23:00"
            ],
            "type": "string",
            "defaultValue": null,
            "metadata": {
                "description": "The end of the maintenance (Mon, Tue, Wed, Thu, Fri, Sat or Sun HH:mm) schedule of the resource for Maintenance Window End tag."
            }
        },
        "expirationDateTag": {
            "type": "string",
            "defaultValue": "yyyy-MM-dd HH:mm:ss",
            "metadata": {
                "description": "The expiration (yyyy-MM-dd HH:mm:ss) schedule of the resource for Expiration Date tag."
            }
        }
    },
    "variables": {},
    "resources": [
        {
            "comments": "Creates the virtual machine.",
            "type": "Microsoft.Compute/virtualMachines",
            "name": "[parameters('virtualMachineName')]",
            "apiVersion": "2015-06-15",
            "location": "[resourceGroup().location]",
            "tags": {
                "ResourceOwner": "[parameters('resourceOwnerNameTag')]",
                "BusinessUnit": "[parameters('businessUnitTag')]",
                "CostCenter": "[parameters('costCenterTag')]",
                "Environment": "[parameters('environmentTag')]",
                "MaintenanceWindowStart": "[parameters('maintenanceWindowStartTag')]",
                "MaintenanceWindowEnd": "[parameters('maintenanceWindowEndTag')]",
                "ExpirationDate": "[parameters('expirationDateTag')]"
            },
            "properties": {
                "hardwareProfile": {
                    "vmSize": "[parameters('virtualMachineSize')]"
                },
                "storageProfile": {
                    "imageReference": {
                        "publisher": "MicrosoftWindowsServer",
                        "offer": "WindowsServer",
                        "sku": "[parameters('virtualMachineSKU')]",
                        "version": "latest"
                    },
                    "osDisk": {
                        "name": "OperatingSystem",
                        "createOption": "FromImage",
                        "vhd": {
                            "uri": "[concat('https', '://', parameters('storageAccountsName'), '.blob.core.windows.net', concat('/vhds/', parameters('virtualMachineName'),'_OperatingSystem.vhd'))]"
                        },
                        "caching": "ReadWrite"
                    },
                    "dataDisks": [
                        {
                            "name": "Data",
                            "diskSizeGB": "[parameters('virtualMachineDataDiskSize')]",
                            "lun": 0,
                            "vhd": {
                                "uri": "[concat('https', '://', parameters('storageAccountsName'), '.blob.core.windows.net', concat('/vhds/', parameters('virtualMachineName'),'_Data.vhd'))]"
                            },  
                            "createOption": "Empty"
                        }
                    ]
                },
                "osProfile": {
                    "computerName": "[parameters('virtualMachineName')]",
                    "adminUsername": "[parameters('virtualMachineAdminUsername')]",
                    "adminPassword": "[parameters('virtualMachineAdminPassword')]",
                    "windowsConfiguration": {
                        "provisionVMAgent": true,
                        "enableAutomaticUpdates": true
                    },
                    "secrets": []
                },
                "networkProfile": {
                    "networkInterfaces": [
                        {
                            "id": "[resourceId('Microsoft.Network/networkInterfaces', parameters('virtualMachineNetworkInterfacesName'))]"
                        }
                    ]
                }
            },
            "resources": [],
            "dependsOn": [
                "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountsName'))]",
                "[resourceId('Microsoft.Network/networkInterfaces', parameters('virtualMachineNetworkInterfacesName'))]"
            ]
        },
        {
            "comments": "Creates the network interfaces for the virtual machine.",
            "type": "Microsoft.Network/networkInterfaces",
            "name": "[parameters('virtualMachineNetworkInterfacesName')]",
            "apiVersion": "2016-03-30",
            "location": "[resourceGroup().location]",
            "tags": {
                "ResourceOwner": "[parameters('resourceOwnerNameTag')]",
                "BusinessUnit": "[parameters('businessUnitTag')]",
                "CostCenter": "[parameters('costCenterTag')]",
                "Environment": "[parameters('environmentTag')]",
                "MaintenanceWindowStart": "[parameters('maintenanceWindowStartTag')]",
                "MaintenanceWindowEnd": "[parameters('maintenanceWindowEndTag')]",
                "ExpirationDate": "[parameters('expirationDateTag')]"
            },
            "properties": {
                "ipConfigurations": [
                    {
                        "name": "ipconfig1",
                        "properties": {
                            "privateIPAllocationMethod": "Dynamic",
                            "publicIPAddress": {
                                "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('virtualMachinePublicIPAddressesName'))]"
                            },
                            "subnet": {
                                "id": "[concat(resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworksName')), '/subnets/', parameters('virtualNetworkSubnetName'))]"
                            }
                        }
                    }
                ],
                "dnsSettings": {
                    "dnsServers": []
                },
                "enableIPForwarding": false
            },
            "resources": [],
            "dependsOn": [
                "[resourceId('Microsoft.Network/publicIPAddresses', parameters('virtualMachinePublicIPAddressesName'))]",
                "[resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworksName'))]"
            ]
        },
        {
            "comments": "Creates the public IP addresses for the virtual machine.",
            "type": "Microsoft.Network/publicIPAddresses",
            "name": "[parameters('virtualMachinePublicIPAddressesName')]",
            "apiVersion": "2016-03-30",
            "location": "[resourceGroup().location]",
            "tags": {
                "ResourceOwner": "[parameters('resourceOwnerNameTag')]",
                "BusinessUnit": "[parameters('businessUnitTag')]",
                "CostCenter": "[parameters('costCenterTag')]",
                "Environment": "[parameters('environmentTag')]",
                "MaintenanceWindowStart": "[parameters('maintenanceWindowStartTag')]",
                "MaintenanceWindowEnd": "[parameters('maintenanceWindowEndTag')]",
                "ExpirationDate": "[parameters('expirationDateTag')]"
            },
            "properties": {
                "publicIPAllocationMethod": "Dynamic",
                "idleTimeoutInMinutes": 4
            },
            "resources": [],
            "dependsOn": []
        },
        {
            "comments": "Creates the virtual networks for the environment.",
            "type": "Microsoft.Network/virtualNetworks",
            "name": "[parameters('virtualNetworksName')]",
            "apiVersion": "2016-03-30",
            "location": "[resourceGroup().location]",
            "tags": {
                "ResourceOwner": "[parameters('resourceOwnerNameTag')]",
                "BusinessUnit": "[parameters('businessUnitTag')]",
                "CostCenter": "[parameters('costCenterTag')]",
                "Environment": "[parameters('environmentTag')]",
                "MaintenanceWindowStart": "[parameters('maintenanceWindowStartTag')]",
                "MaintenanceWindowEnd": "[parameters('maintenanceWindowEndTag')]",
                "ExpirationDate": "[parameters('expirationDateTag')]"
            },
            "properties": {
                "addressSpace": {
                    "addressPrefixes": [
                        "[parameters('virtualNetworkAddressPrefix')]"
                    ]
                },
                "subnets": [
                    {
                        "name": "[parameters('virtualNetworkSubnetName')]",
                        "properties": {
                            "addressPrefix": "[parameters('virtualNetworkSubnetAddressPrefix')]"
                        }
                    }
                ]
            },
            "resources": [],
            "dependsOn": []
        },
        {
            "comments": "Creates the storage account to store the virtual machine.",
            "type": "Microsoft.Storage/storageAccounts",
            "sku": {
                "name": "Standard_LRS",
                "tier": "Standard"
            },
            "kind": "Storage",
            "name": "[parameters('storageAccountsName')]",
            "apiVersion": "2016-01-01",
            "location": "[resourceGroup().location]",
            "tags": {
                "ResourceOwner": "[parameters('resourceOwnerNameTag')]",
                "BusinessUnit": "[parameters('businessUnitTag')]",
                "CostCenter": "[parameters('costCenterTag')]",
                "Environment": "[parameters('environmentTag')]",
                "MaintenanceWindowStart": "[parameters('maintenanceWindowStartTag')]",
                "MaintenanceWindowEnd": "[parameters('maintenanceWindowEndTag')]",
                "ExpirationDate": "[parameters('expirationDateTag')]"
            },
            "properties": {},
            "resources": [],
            "dependsOn": []
        }
    ]
}

 

2. Select Deploy on the Template that you have just created in Azure Templates with the copied JSON code

2017-02-25-azure-iac-arm-1-templates-deploy-virtual-machine-on-independent-virtual-network-subnet

 

3. Select Purchase and wait for the deployment to complete successfully

2017-02-25-azure-iac-arm-2-templates-virtual-machine-deployment-succeeded

 

4. Once the deployment has succeeded, select the virtual machine in the resource group

2017-02-25-azure-iac-arm-3-templates-view-virtual-machine

 

5. Select the Connect button to download a *.RDP file from Azure

2017-02-25-azure-iac-arm-4-templates-connect-to-virtual-machine

 

6. Open or launch the *.RDP file

2017-02-25-azure-iac-arm-5-templates-launch-virtual-machine-rdp-connection

 

7. Login with your newly deployed virtual machine's local admin credential

2017-02-25-azure-iac-arm-6-templates-input-your-virtual-machine-local-administrator-credential

 

8. Accept the newly deployed virtual machine self-signed certificate to establish the Remote Desktop connection with your machine

2017-02-25-azure-iac-arm-7-templates-select-yes-to-accept-virtual-machine-certificate

 

Conclusion

Voila. As you can see, it is really that simple and easy to perform a virtual machine deployment using a well-defined template. With that, you can hand this template to any developer to perform self-deployment of a virtual machine in Azure that can be consistent, dependable and repeatable for development or testing. And the best part is that you can delete it away and re-provision the virtual machine again with ease constantly.

 

2017-02-25-azure-iac-arm-8-templates-remote-desktop-on-virtual-machine

 

Additional Resources

 

See Also