Iteração de recursos em modelos do ARM

Este artigo mostra-lhe como criar mais do que uma instância de um recurso no modelo de Resource Manager do Azure (modelo do ARM). Ao adicionar o ciclo de cópia à secção de recursos do modelo, pode definir dinamicamente o número de recursos a implementar. Também evita ter de repetir a sintaxe do modelo.

Também pode utilizar o ciclo de cópia com propriedades, variáveis e saídas.

Se precisar de especificar se um recurso está implementado, veja o elemento de condição.

Dica

Recomendamos o Bicep porque oferece as mesmas capacidades que os modelos do ARM e a sintaxe é mais fácil de utilizar. Para saber mais, veja ciclos.

Syntax

Adicione o copy elemento à secção recursos do modelo para implementar várias instâncias do recurso. O copy elemento tem o seguinte formato geral:

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

A name propriedade é qualquer valor que identifique o ciclo. A count propriedade especifica o número de iterações que pretende para o tipo de recurso.

Utilize as mode propriedades e batchSize para especificar se os recursos são implementados em paralelo ou em sequência. Estas propriedades estão descritas em Série ou Em Paralelo.

Copiar limites

A contagem não pode exceder os 800.

A contagem não pode ser um número negativo. Pode ser zero se implementar o modelo com uma versão recente da CLI do Azure, do PowerShell ou da API REST. Especificamente, tem de utilizar:

  • Azure PowerShell 2.6 ou posterior
  • CLI do Azure 2.0.74 ou posterior
  • Versão da API REST 2019-05-10 ou posterior
  • As implementações ligadas têm de utilizar a versão da API 2019-05-10 ou posterior para o tipo de recurso de implementação

As versões anteriores do PowerShell, da CLI e da API REST não suportam zero para contagem.

Tenha cuidado ao utilizar a implementação do modo completo com o ciclo de cópia. Se voltar a implementar com o modo completo num grupo de recursos, todos os recursos que não forem especificados no modelo após a resolução do ciclo de cópia serão eliminados.

Iteração de recursos

O exemplo seguinte cria o número de contas de armazenamento especificadas no storageCount parâmetro.

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

Repare que o nome de cada recurso inclui a copyIndex() função, que devolve a iteração atual no ciclo. copyIndex() é baseado em zero. Assim, o exemplo seguinte:

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

Cria estes nomes:

  • storage0
  • armazenamento1
  • storage2

Para compensar o valor do índice, pode transmitir um valor na função copyIndex() . O número de iterações ainda é especificado no elemento copy, mas o valor de copyIndex é compensado pelo valor especificado. Assim, o exemplo seguinte:

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

Cria estes nomes:

  • armazenamento1
  • storage2
  • storage3

A operação de cópia é útil ao trabalhar com matrizes porque pode iterar através de cada elemento na matriz. Utilize a length função na matriz para especificar a contagem de iterações e copyIndex para obter o índice atual na matriz.

O exemplo seguinte cria uma conta de armazenamento para cada nome fornecido no 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": {}
    }
  ]
}

Se quiser devolver valores dos recursos implementados, pode utilizar a cópia na secção saídas.

Utilizar nome simbólico

O nome simbólico será atribuído a ciclos de cópia de recursos. O índice de ciclo é baseado em zero. No exemplo seguinte, myStorages[1] faz referência ao segundo recurso no ciclo 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]"
    }
  }
}

Se o índice for um valor de runtime, formate a referência. Por exemplo

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

Os nomes simbólicos podem ser utilizados em matrizes dependsOn. Se um nome simbólico for para um ciclo de cópia, todos os recursos no ciclo são adicionados como dependências. Para obter mais informações, veja Depende dos recursos num ciclo.

Série ou Paralelo

Por predefinição, Resource Manager cria os recursos em paralelo. Não aplica limites ao número de recursos implementados em paralelo, para além do limite total de 800 recursos no modelo. A ordem pela qual são criadas não é garantida.

No entanto, poderá querer especificar que os recursos são implementados em sequência. Por exemplo, ao atualizar um ambiente de produção, poderá querer escalonar as atualizações para que apenas um determinado número seja atualizado em qualquer altura.

Para implementar em série mais do que uma instância de um recurso, defina mode como série e batchSize para o número de instâncias a implementar de cada vez. Com o modo de série, Resource Manager cria uma dependência em instâncias anteriores no ciclo, pelo que não inicia um lote até que o lote anterior seja concluído.

O valor para batchSize não pode exceder o valor para count no 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": {}
    }
  ]
}

A mode propriedade também aceita paralelo, que é o valor predefinido.

Iteração de um recurso subordinado

Não pode utilizar um ciclo de cópia para um recurso subordinado. Para criar mais do que uma instância de um recurso que normalmente define como aninhado noutro recurso, tem de criar esse recurso como um recurso de nível superior. Define a relação com o recurso principal através das propriedades de tipo e nome.

Por exemplo, suponha que normalmente define um conjunto de dados como um recurso subordinado numa fábrica de dados.

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

Para criar mais do que um conjunto de dados, mova-o para fora da fábrica de dados. O conjunto de dados tem de estar ao mesmo nível da fábrica de dados, mas continua a ser um recurso subordinado da fábrica de dados. Preserva a relação entre o conjunto de dados e a fábrica de dados através das propriedades de tipo e nome. Uma vez que o tipo já não pode ser inferido a partir da respetiva posição no modelo, tem de fornecer o tipo completamente qualificado no formato: {resource-provider-namespace}/{parent-resource-type}/{child-resource-type}.

Para estabelecer uma relação principal/subordinada com uma instância da fábrica de dados, forneça um nome para o conjunto de dados que inclui o nome do recurso principal. Utilize o formato: {parent-resource-name}/{child-resource-name}.

O exemplo seguinte mostra a implementação.

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

Modelos de exemplo

Os exemplos seguintes mostram cenários comuns para criar mais do que uma instância de um recurso ou propriedade.

Modelo Description
Copiar armazenamento Implementa mais do que uma conta de armazenamento com um número de índice no nome.
Armazenamento de cópias em série Implementa várias contas de armazenamento uma de cada vez. O nome inclui o número do índice.
Copiar armazenamento com matriz Implementa várias contas de armazenamento. O nome inclui um valor de uma matriz.
Copiar grupo de recursos Implementa vários grupos de recursos.

Passos seguintes