This post offers a sample ARM template for creating Azure virtual networks (Vnets), with accompanying subnets. What’s different about this example is that it permits the creation of Azure Vnets in multiple subscriptions and resource groups. It’s part one of a two-part sample. The second part demonstrates how to peer Vnets that may be in different subscriptions. I’ll be posting that sample in a couple of weeks.
<rant>
Today, most cloud architects have adopted wholesale the DevOps shibboleth that declarative languages (e.g. JSON or YAML) are “better” for deploying cloud assets than procedural languages (e.g. PowerShell or bash). I may be alone on this, but I don’t agree. Consider the complexity it takes in a declarative language like JSON to do something simple like loop through an array of to-be-created virtual networks versus a foreach
loop in PowerShell. The benefits of declarative approaches, which boil down to idempotency, pale next to the functionality, clarity and maintainability of scripting languages.
Update 2018-07-16: for a PowerShell alternative to this ARM template, see this post.
</rant>
In Azure Resource Manager (ARM) templates, you typically deploy to a single resource group in a single subscription. But what if you want to deploy virtual networks to different resource groups in different subscriptions? It can be done, but it requires using an Azure resource of type Microsoft.Resources/deployments
. This resource allows specification of both a resourceGroup
name and a subscriptionId
name in the deployments
object. The values for these names can, of course, come from a parameter.
Update 2019-03-18: Here are links to the other posts in this series:
A sample ARM template to peer Vnets
Create user-defined routes and associate them with subnets using ARM
Sample ARM templates to create network security groups and attach them to Vnets
A nested template can be the resource that’s deployed by type deployments
. In this example, we use the fact that the nested template refers to a different different subscription and resource group than specified at deployment time to deploy resources in locations other than those supplied when the template is submitted to ARM.
So, how do we allow for multiple Vnets in a single deployment? A resource-level copy
function is used to “loop” through the multiple virtual networks specified in the parameter array. The parameters for subscription, resource group and location are copied from the input parameter array into unique invocations of the nested template.
Since we want to create the subnets for each Vnet, they are contained in a sub-array of each Vnet in the parameters file. Instead of a resource-level copy
, a parameter copy
for the subnets
name array associates the subnets in the parameters with the correct Vnet.
Note that this template assumes that you have created your subscriptions and the target resource groups in advance.
I hope you find this useful and look forward to your comments.
Here’s the template file, followed by the parameter file. Both are (c) 2018 Air11 Technology LLC and are licensed under the Apache OpenSource 2.0 license, https://opensource.org/licenses/Apache-2.0
{ "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json", "contentVersion": "1.0.0.0", "parameters": { "ParameterArray": { "type": "array" } }, "variables": {}, "resources": [ { "apiVersion": "2017-05-10", "name": "[concat('Deploy-',parameters('ParameterArray')[copyIndex('Vnets')].VnetName)]", "type": " ", "resourceGroup": "[parameters('ParameterArray')[copyIndex('Vnets')].ResourceGroupName]", "subscriptionId": "[parameters('ParameterArray')[copyIndex('Vnets')].SubscriptionId]", "copy": { "name": "Vnets", "count": "[length(parameters('ParameterArray'))]" }, "properties": { "mode": "Incremental", "template": { "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": {}, "variables": {}, "resources": [ { "apiVersion": "2017-10-01", "type": "Microsoft.Network/virtualNetworks/", "name": "[parameters('ParameterArray')[copyIndex('Vnets')].VnetName]", "location": "[parameters('ParameterArray')[copyIndex('Vnets')].Region]", "properties": { "addressSpace": { "addressPrefixes": [ "[parameters('ParameterArray')[copyIndex('Vnets')].VnetAddressSpace]" ] }, "copy": [ { "name": "subnets", "count": "[length(parameters('ParameterArray')[copyIndex('Vnets')].Subnets)]", "input": { "name": "[parameters('ParameterArray')[copyIndex('Vnets')].Subnets[copyIndex('subnets')].name]", "properties": { "addressPrefix": "[parameters('ParameterArray')[copyIndex('Vnets')].Subnets[copyIndex('subnets')].addressPrefix]" } } } ] } } ] } } } ], "outputs": {} }
{ "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "0.0.0.1", "parameters": { "ParameterArray": { "value": [ { "VnetName": "VnetInSubA", "ResourceGroupName": "RgInSubA", "SubscriptionId": "ffffffff-0000-0000-0000-aaaaaaaaaaaa", "VnetAddressSpace": "10.66.0.0/16", "Region": "eastus2", "Subnets": [ { "name": "subnet-10-66-1-0-24", "addressPrefix": "10.66.1.0/24" }, { "name": "subnet-10-66-1-0-24", "addressPrefix": "10.66.2.0/24" }, { "name": "subnet-10-66-3-0-24", "addressPrefix": "10.66.3.0/24" }, { "name": "subnet-10-66-4-0-24", "addressPrefix": "10.66.4.0/24" }, { "name": "subnet-10-66-5-0-24", "addressPrefix": "10.66.5.0/24" } ] }, { "VnetName": "VnetInSubB", "ResourceGroupName": "RgInSubB", "SubscriptionId": "ffffffff-0000-0000-0000-bbbbbbbbbbbb", "VnetAddressSpace": "10.64.0.0/16", "Region": "eastus", "Subnets": [ { "name": "subnet-10-64-1-0-slash-24", "addressPrefix": "10.64.1.0/24" }, { "name": "subnet-10-64-2-0-slash-24", "addressPrefix": "10.64.2.0/24" }, { "name": "subnet-10-64-3-0-slash-24", "addressPrefix": "10.64.3.0/24" }, { "name": "subnet-10-64-4-0-slash-24", "addressPrefix": "10.64.4.0/24" }, { "name": "subnet-10-64-5-0-slash-24", "addressPrefix": "10.64.5.0/24" }, { "name": "subnet-10-64-6-0-slash-24", "addressPrefix": "10.64.6.0/24" } ] } ] } } }
Leave a Reply