在 Azure Resource Manager 模板中部署资源或属性的多个实例

本文介绍如何有条件地部署资源,以及如何在 Azure 资源管理器模板中进行迭代操作,以创建资源的多个实例。

有条件地部署资源

当必须在部署过程中决定是创建资源的一个实例,还是不创建资源实例时,请使用 condition 元素。 此元素的值将解析为 true 或 false。 如果值为 true,则部署资源。 如果值为 false,则不部署资源。 例如,若要指定是要部署新的存储帐户还是使用现有存储帐户,请使用:

{
    "condition": "[equals(parameters('newOrExisting'),'new')]",
    "type": "Microsoft.Storage/storageAccounts",
    "name": "[variables('storageAccountName')]",
    "apiVersion": "2017-06-01",
    "location": "[resourceGroup().location]",
    "sku": {
        "name": "[variables('storageAccountType')]"
    },
    "kind": "Storage",
    "properties": {}
}

资源迭代

当必须在部署过程中决定是创建资源的一个实例还是多个实例时,请将 copy 元素添加到资源类型。 在 copy 元素中,为此循环指定迭代次数和名称。 计数值必须是不超过 800 的正整数。

要多次创建的资源将采用以下格式:

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "resources": [
        {
            "apiVersion": "2016-01-01",
            "type": "Microsoft.Storage/storageAccounts",
            "name": "[concat(copyIndex(),'storage', uniqueString(resourceGroup().id))]",
            "location": "[resourceGroup().location]",
            "sku": {
                "name": "Standard_LRS"
            },
            "kind": "Storage",
            "properties": {},
            "copy": {
                "name": "storagecopy",
                "count": 3
            }
        }
    ],
    "outputs": {}
}

请注意,每个资源的名称都包括 copyIndex() 函数,用于返回循环中的当前迭代。 copyIndex() 从零开始。 因此,以下示例:

"name": "[concat('storage', copyIndex())]",

将创建以下名称:

  • storage0
  • storage1
  • storage2。

若要偏移索引值,可以在 copyIndex() 函数中传递一个值。 要执行的迭代次数仍被指定在 copy 元素中,但 copyIndex 的值已按指定的值发生了偏移。 因此,以下示例:

"name": "[concat('storage', copyIndex(1))]",

将创建以下名称:

  • storage1
  • storage2
  • storage3

处理数组时可以使用复制操作,因为可对数组中的每个元素执行迭代操作。 可以对数组使用 length 函数来指定迭代计数,并使用 copyIndex 来检索数组中的当前索引。 因此,以下示例:

"parameters": { 
  "org": { 
     "type": "array", 
     "defaultValue": [ 
         "contoso", 
         "fabrikam", 
         "coho" 
      ] 
  }
}, 
"resources": [ 
  { 
      "name": "[concat('storage', parameters('org')[copyIndex()])]", 
      "copy": { 
         "name": "storagecopy", 
         "count": "[length(parameters('org'))]" 
      }, 
      ...
  } 
]

将创建以下名称:

  • storagecontoso
  • storagefabrikam
  • storagecoho

默认情况下,资源管理器并行创建资源。 因此,创建顺序是不确定的。 但是,你可能希望将资源指定为按顺序部署。 例如,在更新生产环境时,可能需要错开更新,使任何一次仅更新一定数量。

若要按顺序部署资源的多个实例,请将 mode 设置为 serial,将 batchSize 设置为要一次部署的实例数。 在串行模式下,Resource Manager 将在循环中创建早前实例的依赖项,以便在前一个批处理完成之前它不会启动一个批处理。

例如,若要按顺序一次部署两个存储帐户,请使用:

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "resources": [
        {
            "apiVersion": "2016-01-01",
            "type": "Microsoft.Storage/storageAccounts",
            "name": "[concat(copyIndex(),'storage', uniqueString(resourceGroup().id))]",
            "location": "[resourceGroup().location]",
            "sku": {
                "name": "Standard_LRS"
            },
            "kind": "Storage",
            "properties": {},
            "copy": {
                "name": "storagecopy",
                "count": 4,
                "mode": "serial",
                "batchSize": 2
            }
        }
    ],
    "outputs": {}
}

mode 属性也接受 parallel(它是默认值)。

属性迭代

若要为资源中的某个属性创建多个值,请在 properties 元素中添加 copy 数组。 此数组包含对象,每个对象具有以下属性:

  • name - 要为其创建多个值的属性的名称
  • count - 要创建的值数
  • input - 一个对象,其中包含要赋给该属性的值

以下示例演示如何将 copy 应用到虚拟机上的 dataDisks 属性:

{
  "name": "examplevm",
  "type": "Microsoft.Compute/virtualMachines",
  "apiVersion": "2017-03-30",
  "properties": {
    "storageProfile": {
      "copy": [{
          "name": "dataDisks",
          "count": 3,
          "input": {
              "lun": "[copyIndex('dataDisks')]",
              "createOption": "Empty",
              "diskSizeGB": "1023"
          }
      }],
      ...

请注意,在属性迭代中使用 copyIndex 时,必须提供迭代的名称。 在资源迭代中使用该元素时,不需要提供迭代名称。

Resource Manager 在部署期间会扩展 copy 数组。 该数组的名称将成为属性的名称。 输入值将成为对象属性。 已部署的模板将成为:

{
  "name": "examplevm",
  "type": "Microsoft.Compute/virtualMachines",
  "apiVersion": "2017-03-30",
  "properties": {
    "storageProfile": {
      "dataDisks": [
          {
              "lun": 0,
              "createOption": "Empty",
              "diskSizeGB": "1023"
          },
          {
              "lun": 1,
              "createOption": "Empty",
              "diskSizeGB": "1023"
          },
          {
              "lun": 2,
              "createOption": "Empty",
              "diskSizeGB": "1023"
          }
      }],
      ...

可将资源迭代和属性迭代结合使用。 按名称引用属性迭代。

{
    "type": "Microsoft.Network/virtualNetworks",
    "name": "[concat(parameters('vnetname'), copyIndex())]",
    "apiVersion": "2016-06-01",
    "copy":{
        "count": 2,
        "name": "vnetloop"
    },
    "location": "[resourceGroup().location]",
    "properties": {
        "addressSpace": {
            "addressPrefixes": [
                "[parameters('addressPrefix')]"
            ]
        },
        "copy": [
            {
                "name": "subnets",
                "count": 2,
                "input": {
                    "name": "[concat('subnet-', copyIndex('subnets'))]",
                    "properties": {
                        "addressPrefix": "[variables('subnetAddressPrefix')[copyIndex('subnets')]]"
                    }
                }
            }
        ]
    }
}

变量迭代

若要创建某个变量的多个实例,请在 variables 节使用 copy 元素。 可以使用相关的值创建对象的多个实例,然后将这些值分配给资源的实例。 可以使用复制创建带数组属性的对象,或者创建数组。 下例说明了这两种方法:

{
  "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {},
  "variables": {
    "disk-array-on-object": {
      "copy": [
        {
          "name": "disks",
          "count": 5,
          "input": {
            "name": "[concat('myDataDisk', copyIndex('disks', 1))]",
            "diskSizeGB": "1",
            "diskIndex": "[copyIndex('disks')]"
          }
        }
      ]
    },
    "copy": [
      {
        "name": "disks-top-level-array",
        "count": 5,
        "input": {
          "name": "[concat('myDataDisk', copyIndex('disks-top-level-array', 1))]",
          "diskSizeGB": "1",
          "diskIndex": "[copyIndex('disks-top-level-array')]"
        }
      }
    ]
  },
  "resources": [],
  "outputs": {
    "exampleObject": {
      "value": "[variables('disk-array-on-object')]",
      "type": "object"
    },
    "exampleArrayOnObject": {
      "value": "[variables('disk-array-on-object').disks]",
      "type" : "array"
    },
    "exampleArray": {
      "value": "[variables('disks-top-level-array')]",
      "type" : "array"
    }
  }
}

依赖于循环中的资源

可以使用 dependsOn 元素指定一个资源在另一个资源之后部署。 若要部署的资源依赖于循环中的资源集合,请在 dependsOn 元素中提供 copy 循环的名称。 以下示例演示了如何在部署虚拟机之前部署三个存储帐户。 此处并未显示完整的虚拟机定义。 请注意,copy 元素的名称设置为 storagecopy,而虚拟机的 dependsOn 元素也设置为 storagecopy

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {},
    "resources": [
        {
            "apiVersion": "2016-01-01",
            "type": "Microsoft.Storage/storageAccounts",
            "name": "[concat(copyIndex(),'storage', uniqueString(resourceGroup().id))]",
            "location": "[resourceGroup().location]",
            "sku": {
                "name": "Standard_LRS"
            },
            "kind": "Storage",
            "properties": {},
            "copy": {
                "name": "storagecopy",
                "count": 3
            }
        },
        {
            "apiVersion": "2015-06-15", 
            "type": "Microsoft.Compute/virtualMachines", 
            "name": "[concat('VM', uniqueString(resourceGroup().id))]",  
            "dependsOn": ["storagecopy"],
            ...
        }
    ],
    "outputs": {}
}

子资源的迭代

不能对子资源使用 copy 循环。 要创建子资源的多个实例,而该子资源通常在其他资源中定义为嵌套资源,则必须将该资源创建为顶级资源。 可以通过 type 和 name 属性定义与父资源的关系。

例如,假设用户通常会将某个数据集定义为数据工厂中的子资源。

"resources": [
{
    "type": "Microsoft.DataFactory/datafactories",
    "name": "exampleDataFactory",
    ...
    "resources": [
    {
        "type": "datasets",
        "name": "exampleDataSet",
        "dependsOn": [
            "exampleDataFactory"
        ],
        ...
    }
}]

要创建数据集的多个实例,请将数据集移出数据工厂。 数据集必须与数据工厂位于同一层级,但仍属数据工厂的子资源。 可以通过 type 和 name 属性保留数据集和数据工厂之间的关系。 由于类型不再可以从其在模板中的位置推断,因此必须按以下格式提供完全限定的类型: {resource-provider-namespace}/{parent-resource-type}/{child-resource-type}

若要与数据工厂的实例建立父/子关系,提供的数据集的名称应包含父资源名称。 使用以下格式: {parent-resource-name}/{child-resource-name}

以下示例演示实现过程:

"resources": [
{
    "type": "Microsoft.DataFactory/datafactories",
    "name": "exampleDataFactory",
    ...
},
{
    "type": "Microsoft.DataFactory/datafactories/datasets",
    "name": "[concat('exampleDataFactory', '/', 'exampleDataSet', copyIndex())]",
    "dependsOn": [
        "exampleDataFactory"
    ],
    "copy": { 
        "name": "datasetcopy", 
        "count": "3" 
    } 
    ...
}]

示例模板

以下示例显示了创建多个资源或属性的常用方案。

模板 说明
复制存储 部署多个名称中有索引号的存储帐户。
串行复制存储 以一次一个的方式部署多个存储帐户。 名称包含索引号。
使用数组的复制存储 部署多个存储帐户。 名称包含数组中的值。
使用新的或现有的虚拟网络、存储和公共 IP 的 VM 有条件地通过虚拟机部署新的或现有的资源。
数据磁盘数可变的 VM 部署 通过虚拟机部署多个数据磁盘。
复制变量 演示循环访问变量的不同方式。
多项安全规则 将多项安全规则部署到网络安全组。 它从参数构造安全规则。

后续步骤