loading...

Quick Tips for Advanced Azure Resource Manager Templates deployment with Visual Studio 2017

pnmcosta profile image Pedro Maia Costa ・3 min read

With Visual Studio (install Azure SDK with it) you can now create a Azure Resource Group project to manage your resources in multiple Azure Subscriptions.

create

There are some excellent guides online about how Visual Studio works with the Json templates, I got started with this video by Eliot Mansfield and the source code on GitHub because I wanted to make sure I started in a modular approach for my own resources and any that clients may require.

I'm half way building my project:

project

But I can already deploy key-vaults, storage accounts, virtual networks, vnet gateways, virtual machines, etc all organised, parameterized and maintained within my resource groups, all in a few clicks:

deploy

If anyone would like to embark in such a project here are some tips that may save you some time:

  • Make sure templates are modular, naming resources appropriately is a must, I've taken Eliot's approach and prefix everything with the resource type, remember resources are not deleted when redeploying templates, you can keep your infrastructure up to date by modifying the templates and rerunning in most cases (I think, haven't tested all scenarios, but hope so!)
  • Use linked templates whenever possible, but remember these need to be published to an online location. If you're not storing the templates publicly, use a storage account from Azure.
  • If you use the _artifactsLocation and _artifactsLocationSasToken parameters in the template, when deploying via Visual Studio it will ask for a Artifact storage account where the Deploy-AzureResourceGroup.ps1 will upload all your templates and any files set as Content in the project's file properties (F4 when file selected in Solution Explorer) and replace the parameter values. But never include these parameters values manually in a parameters file as the deploy script will fail when trying to replace those with the generated values.
  • I have not tested a linked template also linking to another template, seems untidy to me having to pass along the generated artifacts storage keys to the linked template, so I've been avoiding that.
  • Build the template links in variables, below is an example from one of my templates that uses the deploy scripts generated storage account location and SasToken parameters to access the container, click here to find out more about the SasToken.

    {
        "variables": {
            "templates": {
              "vm": {
                "folder": "nestedtemplates",
                "fileName": "vm.json"
              },
              "deploy": {
                "folder": "rg-lab-superadmin",
                "fileName": "deploy.sh"
              }
            },
            "templateLinks": {
              "vm": "[concat(parameters('_artifactsLocation'), '/', variables('templates').vm.folder, '/', variables('templates').vm.fileName, parameters('_artifactsLocationSasToken'))]",
              "deploy": "[concat(parameters('_artifactsLocation'),  '/', variables('templates').deploy.folder, '/', variables('templates').deploy.fileName, parameters('_artifactsLocationSasToken'))]"
            }
        }
    }
    
  • You can use the same principal of the artifacts location above for scripts you want to execute on a targeted VM with the custom script extension.

  • Custom scripts on VM's should be redeployable to the same VM over and over again, as you may need to redeploy a whole resource group that includes the VM and those scripts need to consider that.

  • VNet resources must be in the same location but not necessarily the same resource group, you can plan for this within the templates, for example whenever I need a vnet resource I also ask for the resource group it's in so you can create the appropriate resourceId() on your template. A common scenario is when you create a VM, my template also created the NIC and this needs to be referenced properly to the vnet that may be on another resource group.

  • It is not possible yet to create container in Storage Accounts directly with an ARM template, however a work round is to include a VM on your template and run a custom script on it that would create the container on the storage account using the CLI, Powershell or other Azure management options.

  • Thanks to @4c74356b41 on SO, I got taught that you can call object properties dynamically by name "[reference(x)[parameter(y)]]" in nested [] if you ever require to do so.

I will try and keep this post updated as I keep developing the infrastructure for my requirements.

Discussion

markdown guide
 

"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"kind": "Storage",
"name": "[variables('storageName')]",
"apiVersion": "2018-07-01",
"location": "[variables('location')]",
"resources": [
{
"type": "blobServices/containers",
"apiVersion": "2018-03-01-preview",
"name": "[concat('default/', variables('storageBlobName'))]",
"properties": {
"publicAccess": "Blob"
},
"dependsOn": ["[variables('storageName')]"]
}
]
}
]

To create a storage container using ARM template

 

Sweet, thanks, I knew it would come up at some point. Thanks for the sample.