Iteración de recursos en las plantillas de ARM

En este artículo se explica cómo se crean varias instancias de un recurso en la plantilla de Azure Resource Manager (plantilla de ARM). Al agregar el bucle de copia a la sección de recursos de la plantilla, puede establecer de forma dinámica el número de recursos que va a implementar. Asimismo, evitará tener que repetir la sintaxis de la plantilla.

También puede usar el bucle de copia con propiedades, variables y salidas.

Si tiene que especificar si un recurso se implementa, consulte Elemento condition.

Sugerencia

Se recomienda Bicep porque ofrece las mismas funcionalidades que las plantillas de ARM y la sintaxis es más fácil de usar. Para más información, consulta loops.

Sintaxis

Agregue el elemento copy a la sección de recursos de la plantilla para implementar varias instancias del recurso. El elemento copy tiene el siguiente formato general:

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

La propiedad name es cualquier valor que identifique el bucle. La propiedad count especifica el número de iteraciones que desea realizar en el tipo de recurso.

Utilice las propiedades mode y batchSize para especificar si los recursos van a implementarse simultáneamente o por orden. Estas propiedades se describen en el artículo En serie o en paralelo.

Límites de copia

El valor de count no puede superar 800.

El valor de count no puede ser un número negativo. Puede ser cero si implementa la plantilla con una versión reciente de la CLI de Azure, PowerShell o la API de REST. Concretamente, se debe usar:

  • Azure PowerShell 2.6 o posterior
  • CLI de Azure 2.0.74 o posterior
  • API de REST versión 2019-05-10 o posterior
  • Las implementaciones vinculadas deben usar la versión 10-05-2019 o posterior de la API para el tipo de recurso de implementación

Las versiones anteriores de PowerShell, la CLI y API REST no admiten un valor de count de cero.

Tenga cuidado al usar la implementación de modo completo con un bucle de copia. Si vuelve a implementar con el modo completo en un grupo de recursos, se eliminan todos los recursos que no se especifican en la plantilla después de resolver el bucle de copia.

Iteración de recursos

En el ejemplo siguiente, se crea el número de cuentas de almacenamiento especificado en el parámetro 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": {}
    }
  ]
}

Tenga en cuenta que el nombre de cada recurso incluye la función copyIndex(), que devuelve la iteración actual del bucle. copyIndex() es de base cero. Así, en el ejemplo siguiente:

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

Crea estos nombres:

  • storage0
  • storage1
  • storage2

Para desplazar el valor de índice, puede pasar un valor en la función copyIndex(). El número de iteraciones se sigue especificando en el elemento copy, pero el valor de copyIndex se desplaza el valor especificado. Así, en el ejemplo siguiente:

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

Crea estos nombres:

  • storage1
  • storage2
  • storage3

La operación de copia es útil al trabajar con matrices, ya que puede iterar a través de cada elemento de la matriz. Use la función length en la matriz para especificar el número de iteraciones, y copyIndex para recuperar el índice actual de la matriz.

En el ejemplo siguiente, se crea una cuenta de almacenamiento para cada uno de los nombres proporcionados en el parámetro.

{
  "$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": {}
    }
  ]
}

Si desea devolver valores de los recursos implementados, puede usar copy en la sección de salidas.

Usar el nombre simbólico

El nombre simbólico se asignará a bucles de copia de recursos. El índice del bucle está basado en cero. En el ejemplo siguiente, myStorages[1] hace referencia al segundo recurso del bucle de recursos.

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

Si el índice es un valor en tiempo de ejecución, dé formato a la referencia usted mismo. Por ejemplo,

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

Los nombres simbólicos se pueden utilizar en matrices dependOn. Si un nombre simbólico es para un bucle de copia, todos los recursos del bucle se agregan como dependencias. Para obtener más información, consulte Depende de los recursos en un bucle.

En serie o en paralelo

Resource Manager crea los recursos en paralelo de forma predeterminada. No se aplica ningún límite en el número de recursos implementados en paralelo, aparte del límite total de 800 recursos de la plantilla. No se garantiza el orden en el que se crean.

Sin embargo, es posible que quiera especificar que los recursos se implementen en secuencia. Por ejemplo, al actualizar un entorno de producción, puede que quiera escalonar las actualizaciones para que solo una cantidad determinada se actualice al mismo tiempo.

Para implementar en serie varias instancias de un recurso, establezca mode en el valor mode y batchSize en el número de instancias que se implementarán a la vez. Con mode establecido en serial, Resource Manager crea una dependencia en las instancias anteriores del bucle, por lo que no se inicia ningún lote hasta que se completa el lote anterior.

El valor de batchSize no puede superar el valor de count en el elemento copy.

{
  "$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": {}
    }
  ]
}

La propiedad mode también acepta mode, que es el valor predeterminado.

Iteración para un recurso secundario

No puede usar un bucle copy en un recurso secundario. Para crear varias instancias de un recurso que se define normalmente como anidado dentro de otro recurso, debe crear dicho recurso como uno de nivel superior. La relación con el recurso principal se define a través de las propiedades type y name.

Por ejemplo, supongamos que suele definir un conjunto de datos como un recurso secundario dentro de una factoría de datos.

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

Para crear más de un conjunto de datos, muévalos fuera de la factoría de datos. El conjunto de datos debe estar en el mismo nivel que la factoría de datos, pero seguirá siendo un recurso secundario de la factoría de datos. La relación entre el conjunto de datos y la factoría de datos se conserva a través de los parámetros type y name. Puesto que la propiedad de type ya no se puede inferir de su posición en la plantilla, debe proporcionar el nombre completo del tipo con el formato: {resource-provider-namespace}/{parent-resource-type}/{child-resource-type}.

Para establecer una relación de principal-secundario con una instancia de la factoría de datos, proporcione un nombre para el conjunto de datos que incluya el nombre de recurso principal. Utilice el formato: {parent-resource-name}/{child-resource-name}.

En el siguiente ejemplo se muestra la implementación.

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

Plantillas de ejemplo

En los ejemplos siguientes se muestran escenarios comunes para crear más de una instancia de un recurso o propiedad.

Plantilla Description
Almacenamiento de copias Implementa más de una cuenta de almacenamiento con un número de índice en el nombre.
Almacenamiento de copias en serie Implementa varias cuentas de almacenamiento, una tras otra. El nombre incluye el número de índice.
Almacenamiento de copias con una matriz Implementa varias cuentas de almacenamiento. El nombre incluye el valor de una matriz.
Copia del grupo de recursos Implementa varios grupos de recursos.

Pasos siguientes