ARM 模板中的资源迭代

本文介绍如何在 Azure 资源管理器模板(ARM 模板)中创建一个资源的多个实例。 通过将 copy 循环添加到模板的 resources 节,可以动态设置要部署的资源数。 还可以避免重复模板语法。

还可以将 copy 循环用于 propertiesvariablesoutputs

如需指定究竟是否部署资源,请参阅 condition 元素

提示

我们建议使用 Bicep,因为它提供与 ARM 模板相同的功能,并且该语法更易于使用。 若要了解详情,请参阅循环

语法

copy 元素添加到模板的 resources 节可部署资源的多个实例。 copy 元素采用以下常规格式:

"copy": {
  "name": "<name-of-loop>",
  "count": <number-of-iterations>,
  "mode": "serial" <or> "parallel",
  "batchSize": <number-to-deploy-serially>
}

name 属性是标识循环的任何值。 count 属性指定要对该资源类型进行的迭代次数。

使用 modebatchSize 属性指定是并行还是按顺序部署资源。 串行或并行中介绍了这些属性。

复制限制

count 不能超过 800。

count 不能为负数。 如果使用最新版本的 Azure CLI、PowerShell 或 REST API 部署模板,则它可以为零。 具体而言,必须使用:

  • Azure PowerShell 2.6 或更高版本
  • Azure CLI 2.0.74 或更高版本
  • REST API 版本 2019-05-10 或更高版本
  • 链接的部署必须将 API 版本 2019-05-10 或更高版本用于部署资源类型

更早版本的 PowerShell、CLI 和 REST API 不支持将 count 设为零。

完整模式部署与 copy 循环一起使用时要小心。 如果以完整模式重新部署到资源组,则在解析复制循环后会删除模板中未指定的任何资源。

资源迭代

以下示例创建在 storageCount 参数中指定的存储帐户数目。

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]"
    },
    "storageCount": {
      "type": "int",
      "defaultValue": 3
    }
  },
  "resources": [
    {
      "copy": {
        "name": "storagecopy",
        "count": "[length(range(0, parameters('storageCount')))]"
      },
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2022-09-01",
      "name": "[format('{0}storage{1}', range(0, parameters('storageCount'))[copyIndex()], uniqueString(resourceGroup().id))]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "Standard_LRS"
      },
      "kind": "Storage",
      "properties": {}
    }
  ]
}

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

"name": "[format('storage{0}', copyIndex())]",

将创建以下名称:

  • storage0
  • storage1
  • storage2

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

"name": "[format('storage{0}', copyIndex(1))]",

将创建以下名称:

  • storage1
  • storage2
  • storage3

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

以下示例为参数中提供的每个名称创建一个存储帐户。

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "storageNames": {
      "type": "array",
      "defaultValue": [
        "contoso",
        "fabrikam",
        "coho"
      ]
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]"
    }
  },
  "resources": [
    {
      "copy": {
        "name": "storagecopy",
        "count": "[length(parameters('storageNames'))]"
      },
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2022-09-01",
      "name": "[format('{0}{1}', parameters('storageNames')[copyIndex()], uniqueString(resourceGroup().id))]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "Standard_LRS"
      },
      "kind": "Storage",
      "properties": {}
    }
  ]
}

如果要从已部署的资源返回值,可以使用在输出部分中复制

使用符号名称

符号名称将分配给资源复制循环。 循环索引从零开始。 在以下示例中,myStorages[1] 引用资源循环中的第二个资源。

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "languageVersion": "2.0",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]"
    },
    "storageCount": {
      "type": "int",
      "defaultValue": 2
    }
  },
  "resources": {
    "myStorages": {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2022-09-01",
      "name": "[format('{0}storage{1}', copyIndex(), uniqueString(resourceGroup().id))]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "Standard_LRS"
      },
      "kind": "Storage",
      "properties": {},
      "copy": {
        "name": "storagecopy",
        "count": "[parameters('storageCount')]"
      }
    }
  },
  "outputs": {
    "storageEndpoint":{
      "type": "object",
      "value": "[reference('myStorages[1]').primaryEndpoints]"
    }
  }
}

如果索引是运行时值,请自行设置引用的格式。 例如

"outputs": {
  "storageEndpoint":{
    "type": "object",
    "value": "[reference(format('myStorages[{0}]', variables('runtimeIndex'))).primaryEndpoints]"
  }
}

符号名称可用于 dependsOn 数组。 如果符号名称用于复制循环,则循环中的所有资源将添加为依赖项。 有关详细信息,请参阅“依赖于循环中的资源”。

串行或并行

默认情况下,资源管理器并行创建资源。 除了模板中 800 个资源的总限制外,它对并行部署的资源数量没有限制。 不会保证它们的创建顺序。

但是,你可能希望将资源指定为按顺序部署。 例如,在更新生产环境时,可能需要错开更新,使任何一次仅更新一定数量。

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

batchSize 的值不能超过 copy 元素中 count 的值。

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]"
    }
  },
  "resources": [
    {
      "copy": {
        "name": "storagecopy",
        "count": 4,
        "mode": "serial",
        "batchSize": 2
      },
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2022-09-01",
      "name": "[format('{0}storage{1}', range(0, 4)[copyIndex()], uniqueString(resourceGroup().id))]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "Standard_LRS"
      },
      "kind": "Storage",
      "properties": {}
    }
  ]
}

mode 属性也接受“parallel”(默认值)。

子资源的迭代

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

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

{
  "resources": [
    {
      "type": "Microsoft.DataFactory/factories",
      "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/factories",
  "name": "exampleDataFactory",
  ...
},
{
  "type": "Microsoft.DataFactory/factories/datasets",
  "name": "[format('exampleDataFactory/exampleDataSet{0}', copyIndex())]",
  "dependsOn": [
    "exampleDataFactory"
  ],
  "copy": {
    "name": "datasetcopy",
    "count": "3"
  },
  ...
}]

示例模板

以下示例展示了创建资源或属性的多个实例的常见方案。

模板 说明
复制存储 部署名称中带索引号的多个存储帐户。
串行复制存储 一次部署多个存储帐户。 名称包含索引号。
使用数组的复制存储 部署多个存储帐户。 名称包含数组中的值。
复制资源组 部署多个资源组。

后续步骤