在 Azure 资源管理器模板中部署资源或属性的多个实例Deploy more than one instance of a resource or property in Azure Resource Manager Templates

本文介绍了如何在 Azure 资源管理器模板中进行迭代操作,以创建多个资源实例。This article shows you how to iterate in your Azure Resource Manager template to create more than one instance of a resource. 如需指定究竟是否部署资源,请参阅 condition 元素If you need to specify whether a resource is deployed at all, see condition element.

有关教程,请参阅教程:使用资源管理器模板创建多个资源实例For a tutorial, see Tutorial: create multiple resource instances using Resource Manager templates.

Note

本文进行了更新,以便使用新的 Azure PowerShell Az 模块。This article has been updated to use the new Azure PowerShell Az module. 你仍然可以使用 AzureRM 模块,至少在 2020 年 12 月之前,它将继续接收 bug 修补程序。You can still use the AzureRM module, which will continue to receive bug fixes until at least December 2020. 若要详细了解新的 Az 模块和 AzureRM 兼容性,请参阅新 Azure Powershell Az 模块简介To learn more about the new Az module and AzureRM compatibility, see Introducing the new Azure PowerShell Az module. 有关 Az 模块安装说明,请参阅安装 Azure PowerShellFor Az module installation instructions, see Install Azure PowerShell.

资源迭代Resource iteration

当必须在部署过程中决定是创建资源的一个实例还是多个实例时,请将 copy 元素添加到资源类型。When you must decide during deployment to create one or more instances of a resource, add a copy element to the resource type. 在 copy 元素中,为此循环指定迭代次数和名称。In the copy element, you specify the number of iterations and a name for this loop. 计数值必须是不超过 800 的正整数。The count value must be a positive integer and can't be more than 800.

要多次创建的资源采用以下格式:The resource to create several times takes the following format:

{
  "$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() 函数,用于返回循环中的当前迭代。Notice that the name of each resource includes the copyIndex() function, which returns the current iteration in the loop. copyIndex() 从零开始。copyIndex() is zero-based. 因此,以下示例:So, the following example:

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

将创建以下名称:Creates these names:

  • storage0storage0
  • storage1storage1
  • storage2。storage2.

若要偏移索引值,可以在 copyIndex() 函数中传递一个值。To offset the index value, you can pass a value in the copyIndex() function. 要执行的迭代次数仍被指定在 copy 元素中,但 copyIndex 的值已按指定的值发生了偏移。The number of iterations to perform is still specified in the copy element, but the value of copyIndex is offset by the specified value. 因此,以下示例:So, the following example:

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

将创建以下名称:Creates these names:

  • storage1storage1
  • storage2storage2
  • storage3storage3

处理数组时可以使用复制操作,因为可对数组中的每个元素执行迭代操作。The copy operation is helpful when working with arrays because you can iterate through each element in the array. 可以对数组使用 length 函数来指定迭代计数,并使用 copyIndex 来检索数组中的当前索引。Use the length function on the array to specify the count for iterations, and copyIndex to retrieve the current index in the array. 因此,以下示例:So, the following example:

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

将创建以下名称:Creates these names:

  • storagecontosostoragecontoso
  • storagefabrikamstoragefabrikam
  • storagecohostoragecoho

默认情况下,资源管理器并行创建资源。By default, Resource Manager creates the resources in parallel. 不会保证它们的创建顺序。The order in which they're created isn't guaranteed. 但是,你可能希望将资源指定为按顺序部署。However, you may want to specify that the resources are deployed in sequence. 例如,在更新生产环境时,可能需要错开更新,使任何一次仅更新一定数量。For example, when updating a production environment, you may want to stagger the updates so only a certain number are updated at any one time.

若要按顺序部署多个资源实例,请将 mode 设置为“串行”,并将 batchSize 设置为一次要部署的实例数量 。To serially deploy more than one instance of a resource, set mode to serial and batchSize to the number of instances to deploy at a time. 在串行模式下,资源管理器会在循环中创建早前实例的依赖项,以便在前一个批处理完成之前它不会启动一个批处理。With serial mode, Resource Manager creates a dependency on earlier instances in the loop, so it doesn't start one batch until the previous batch completes.

例如,若要按顺序一次部署两个存储帐户,请使用:For example, to serially deploy storage accounts two at a time, use:

{
  "$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(它是默认值)。The mode property also accepts parallel, which is the default value.

有关将副本与嵌套的模板配合使用的信息,请参阅使用副本For information about using copy with nested templates, see Using copy.

属性迭代Property iteration

若要为资源上的属性创建多个值,请在属性元素中添加一个 copy 数组。To create more than one value for a property on a resource, add a copy array in the properties element. 此数组包含对象,每个对象具有以下属性:This array contains objects, and each object has the following properties:

  • 名称 - 要创建多个值的属性的名称name - the name of the property to create several values for
  • 计数 - 要创建的值的数目。count - the number of values to create. 计数值必须是不超过 800 的正整数。The count value must be a positive integer and can't be more than 800.
  • input - 一个对象,其中包含要赋给该属性的值input - an object that contains the values to assign to the property

以下示例演示如何将 copy 应用到虚拟机上的 dataDisks 属性:The following example shows how to apply copy to the dataDisks property on a virtual machine:

{
  "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 时,必须提供迭代的名称。Notice that when using copyIndex inside a property iteration, you must provide the name of the iteration. 与资源迭代一起使用时,无需提供名称。You don't have to provide the name when used with resource iteration.

Resource Manager 在部署期间会扩展 copy 数组。Resource Manager expands the copy array during deployment. 该数组的名称将成为属性的名称。The name of the array becomes the name of the property. 输入值将成为对象属性。The input values become the object properties. 已部署的模板将成为:The deployed template becomes:

{
  "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"
        }
      ],
      ...

copy 元素是一个数组,因此,可以为资源指定多个属性。The copy element is an array so you can specify more than one property for the resource. 为要创建的每个属性添加一个对象。Add an object for each property to create.

{
  "name": "string",
  "type": "Microsoft.Network/loadBalancers",
  "apiVersion": "2017-10-01",
  "properties": {
    "copy": [
      {
        "name": "loadBalancingRules",
        "count": "[length(parameters('loadBalancingRules'))]",
        "input": {
          ...
        }
      },
      {
        "name": "probes",
        "count": "[length(parameters('loadBalancingRules'))]",
        "input": {
          ...
        }
      }
    ]
  }
}

可将资源迭代和属性迭代结合使用。You can use resource and property iteration together. 按名称引用属性迭代。Reference the property iteration by name.

{
  "type": "Microsoft.Network/virtualNetworks",
  "name": "[concat(parameters('vnetname'), copyIndex())]",
  "apiVersion": "2018-04-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')]]"
          }
        }
      }
    ]
  }
}

变量迭代Variable iteration

若要创建变量的多个实例,请在变量部分中使用 copy 属性。To create multiple instances of a variable, use the copy property in the variables section. 可以创建一个由 input 属性中的值构造的元素数组。You create an array of elements constructed from the value in the input property. 可以在变量中使用 copy 属性,或在变量部分的顶层使用该属性。You can use the copy property within a variable, or at the top level of the variables section. 在变量迭代中使用 copyIndex 时,必须提供迭代的名称。When using copyIndex inside a variable iteration, you must provide the name of the iteration.

如需通过简单示例来了解如何创建字符串值的数组,请参阅复制数组模板For a simple example of creating an array of string values, see copy array template.

以下示例演示了使用动态构造的元素创建数组变量的多种不同方法。The following example shows several different ways to create array variables with dynamically constructed elements. 它演示如何在变量中使用副本来创建对象和字符串的数组。It shows how to use copy inside a variable to create arrays of objects and strings. 它还演示如何在顶层使用副本来创建对象、字符串和整数的数组。It also shows how to use copy at the top level to create arrays of objects, strings, and integers.

{
  "$schema": "https://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')]"
          }
        },
        {
          "name": "diskNames",
          "count": 5,
          "input": "[concat('myDataDisk', copyIndex('diskNames', 1))]"
        }
      ]
    },
    "copy": [
      {
        "name": "top-level-object-array",
        "count": 5,
        "input": {
          "name": "[concat('myDataDisk', copyIndex('top-level-object-array', 1))]",
          "diskSizeGB": "1",
          "diskIndex": "[copyIndex('top-level-object-array')]"
        }
      },
      {
        "name": "top-level-string-array",
        "count": 5,
        "input": "[concat('myDataDisk', copyIndex('top-level-string-array', 1))]"
      },
      {
        "name": "top-level-integer-array",
        "count": 5,
        "input": "[copyIndex('top-level-integer-array')]"
      }
    ]
  },
  "resources": [],
  "outputs": {
    "exampleObject": {
      "value": "[variables('disk-array-on-object')]",
      "type": "object"
    },
    "exampleArrayOnObject": {
      "value": "[variables('disk-array-on-object').disks]",
      "type" : "array"
    },
    "exampleObjectArray": {
      "value": "[variables('top-level-object-array')]",
      "type" : "array"
    },
    "exampleStringArray": {
      "value": "[variables('top-level-string-array')]",
      "type" : "array"
    },
    "exampleIntegerArray": {
      "value": "[variables('top-level-integer-array')]",
      "type" : "array"
    }
  }
}

创建的变量的类型取决于输入对象。The type of variable that gets created depends on the input object. 例如,在上一示例中名为 top-level-object-array 的变量返回:For example, the variable named top-level-object-array in the preceding example returns:

[
  {
    "name": "myDataDisk1",
    "diskSizeGB": "1",
    "diskIndex": 0
  },
  {
    "name": "myDataDisk2",
    "diskSizeGB": "1",
    "diskIndex": 1
  },
  {
    "name": "myDataDisk3",
    "diskSizeGB": "1",
    "diskIndex": 2
  },
  {
    "name": "myDataDisk4",
    "diskSizeGB": "1",
    "diskIndex": 3
  },
  {
    "name": "myDataDisk5",
    "diskSizeGB": "1",
    "diskIndex": 4
  }
]

名为 top-level-string-array 的变量返回:And, the variable named top-level-string-array returns:

[
  "myDataDisk1",
  "myDataDisk2",
  "myDataDisk3",
  "myDataDisk4",
  "myDataDisk5"
]

依赖于循环中的资源Depend on resources in a loop

可以使用 dependsOn 元素指定一个资源在另一个资源之后部署。You specify that a resource is deployed after another resource by using the dependsOn element. 若要部署的资源依赖于循环中的资源集合,请在 dependsOn 元素中提供 copy 循环的名称。To deploy a resource that depends on the collection of resources in a loop, provide the name of the copy loop in the dependsOn element. 以下示例演示了如何在部署虚拟机之前部署三个存储帐户。The following example shows how to deploy three storage accounts before deploying the Virtual Machine. 此处并未显示完整的虚拟机定义。The full Virtual Machine definition isn't shown. 请注意,copy 元素的名称设置为 storagecopy,而虚拟机的 dependsOn 元素也设置为 storagecopyNotice that the copy element has name set to storagecopy and the dependsOn element for the Virtual Machines is also set to 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": {}
}

子资源的迭代Iteration for a child resource

不能对子资源使用 copy 循环。You can't use a copy loop for a child resource. 要创建通常定义为嵌套在另一个资源中的资源的多个实例,必须将该资源创建为顶级资源。To create more than one instance of a resource that you typically define as nested within another resource, you must instead create that resource as a top-level resource. 可以通过 type 和 name 属性定义与父资源的关系。You define the relationship with the parent resource through the type and name properties.

例如,假设用户通常会将某个数据集定义为数据工厂中的子资源。For example, suppose you typically define a dataset as a child resource within a data factory.

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

若要创建多个数据集,请将其移出数据工厂。To create more than one data set, move it outside of the data factory. 数据集必须与数据工厂处于同一级别,但它仍是数据工厂的子资源。The dataset must be at the same level as the data factory, but it's still a child resource of the data factory. 可以通过 type 和 name 属性保留数据集和数据工厂之间的关系。You preserve the relationship between data set and data factory through the type and name properties. 由于类型不再可以从其在模板中的位置推断,因此必须按以下格式提供完全限定的类型: {resource-provider-namespace}/{parent-resource-type}/{child-resource-type}Since type can no longer be inferred from its position in the template, you must provide the fully qualified type in the format: {resource-provider-namespace}/{parent-resource-type}/{child-resource-type}.

若要与数据工厂的实例建立父/子关系,提供的数据集的名称应包含父资源名称。To establish a parent/child relationship with an instance of the data factory, provide a name for the data set that includes the parent resource name. 使用以下格式: {parent-resource-name}/{child-resource-name}Use the format: {parent-resource-name}/{child-resource-name}.

以下示例演示实现过程:The following example shows the implementation:

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

示例模板Example templates

以下示例展示了创建资源或属性的多个实例的常见方案。The following examples show common scenarios for creating more than one instance of a resource or property.

模板Template 说明Description
复制存储Copy storage 部署名称中带索引号的多个存储帐户。Deploys more than one storage account with an index number in the name.
串行复制存储Serial copy storage 一次部署多个存储帐户。Deploys several storage accounts one at time. 名称包含索引号。The name includes the index number.
使用数组的复制存储Copy storage with array 部署多个存储帐户。Deploys several storage accounts. 名称包含数组中的值。The name includes a value from an array.
数据磁盘数可变的 VM 部署VM deployment with a variable number of data disks 通过虚拟机部署多个数据磁盘。Deploys several data disks with a virtual machine.
复制变量Copy variables 演示循环访问变量的不同方式。Demonstrates the different ways of iterating on variables.
多项安全规则Multiple security rules 将多个安全规则部署到网络安全组。Deploys several security rules to a network security group. 它从参数构造安全规则。It constructs the security rules from a parameter. 有关参数,请参阅多个 NSG 参数文件For the parameter, see multiple NSG parameter file.

后续步骤Next steps