Criar várias instâncias de recursos usando o elemento copy

Concluído

Até agora, você declarou recursos em uma lista de recursos em um modelo. Ao implantar, você obteve uma instância de cada item especificado na lista de recursos. O ideal é criar mais de uma instância de um recurso específico. Por exemplo, pode ser interessante ter várias sub-redes em uma rede virtual.

Considere estas perguntas e estes pontos quando estiver pensando em criar várias instâncias e fazer iterações em constructos:

  • Preciso de mais de uma cópia?: para cenários mais simples, talvez você não precise disso. Para cenários mais avançados, como sub-redes ou máquinas virtuais, talvez seja necessário considerar se você precisa de mais de uma cópia de algo.
  • Sou dependente de um recurso?: normalmente, o Azure Resource Manager é bom em descobrir o que precisa ser construído e em que ordem, para que as referências no modelo do Azure Resource Manager funcionem. No entanto, há situações em que pode ser necessário especificar a ordem.
  • Definir um esquema de nomenclatura: É recomendável dar nomes significativos aos recursos. Por esse motivo, você depende dos parâmetros transmitidos no momento da implantação. Quando você tem várias cópias, o ideal é ter um controle mais granular e basear a nomenclatura na iteração da sequência de cópias em que você está atualmente.
  • Configurar e controlar a criação de recursos: Talvez você queira limitar quantos recursos estão sendo criados em um ambiente de produção. É possível fazer isso configurando a criação de recursos como modo serial ou paralelo.
  • Copiar outros tipos: Os recursos não são a única coisa da qual você pode criar várias cópias e fazer iterações. Na verdade, você pode fazer o mesmo com propriedades, variáveis e saída.
  • Pai-filho: talvez seja necessário configurar relações pai-filho nos seus recursos.

Criar múltiplas instâncias

Você pode usar constructos de loop para evitar pressionamentos de teclas. Se o que você precisar for repetido indefinidamente, for bastante semelhante em nome e tipo e só tiver pequenas diferenças, poderá se beneficiar do uso do elemento copy.

O elemento copy é uma parte do JSON que você pode usar em muitos tipos de constructos, como recursos, propriedades, variáveis e saída. A sintaxe para o elemento copy consiste na chave copy e uma matriz como o valor. Por exemplo: "copy": [].

A matriz usa vários elementos, e cada elemento é um objeto {} que consiste em um conjunto de propriedades. O que essas propriedades são depende do tipo de constructo em que são usadas. Normalmente, todos os constructos do elemento copy têm uma propriedade em comum: count. Essa propriedade decide quantas instâncias você deseja de um determinado tipo de constructo. A maioria dos constructos também permite uma propriedade name que fornece uma referência que você pode citar em outras partes do código. Outras propriedades usadas são específicas do constructo.

Como escolher

Você pode perguntar: "Se eu puder usar o elemento copy em muitos tipos de constructos, qual deverei escolher e quando? E poderei usar mais de um tipo em um modelo?"

Tudo depende de seu caso de uso. Uma iteração de recurso permite que você crie muitas cópias de um recurso, e faz sentido usá-la se você precisa ter muitas contas de armazenamento, por exemplo. Uma iteração de propriedades, por outro lado, permite criar muitas propriedades dentro de um recurso. Trata-se de economizar tempo e pressionamentos de teclas, e você sabe melhor os pontos em que há partes repetidas no modelo.

Use o elemento copy em muitos locais do modelo. Você pode usar um elemento copy para criar muitos recursos, mas também para criar muitas variáveis semelhantes dentro do mesmo modelo.

Como ele funciona

O elemento copy funciona com a avaliação e a substituição da instrução copy. A substituição é o resultado do que você define na instrução copy, repetida tantas vezes quanto você instruiu no campo copy.

O seguinte exemplo mostra a possível aparência de uma definição que usa copy:

"copy": [
  {
    "name": "dataDisks",
    "count": 2,
    "input": {
      "diskSizeGB": 1023,
      "lun": "[copyIndex('dataDisks')]",
      "createOption": "Empty"
    }
  }
]

Observe a entrada count: 2. O valor 2 significa que você deseja que a expressão acima se expanda para duas entradas. O resultado é o seguinte:

"dataDisks": [
{
  "lun": 0,
  "createOption": "Empty",
  "diskSizeGB": 1023
},
{
  "lun": 1,
  "createOption": "Empty",
  "diskSizeGB": 1023
}

Você pode ver que o valor da propriedade name se tornou o nome da propriedade, e o conteúdo da propriedade input se tornou a parte do JSON que é repetida.

Observação

A expressão de copy e sua saída diferem pelo tipo de expressão usada. O exemplo anterior dá uma boa ideia do que acontece quando uma expressão é transformada em uma série de instruções repetidas.

Há limites para o quanto pode ser copiado. Atualmente, o limite é de 800 entradas.

Importante

Para obter mais informações sobre as limitações exatas, confira Iteração de recurso em modelos do ARM.

Controlar a iteração

Há funções auxiliares que ajudam você a se referir a índices específicos na matriz. A função copyIndex() retorna o índice atual. Por exemplo, para a terceira entrada repetida, copyIndex() retorna o valor 2. A sintaxe de copyIndex() é semelhante ao seguinte:

copyIndex(loopName, offset)

A função copyIndex() tem dois parâmetros de entrada diferentes: loopName e offset. O parâmetro offset é sempre opcional e é usado para deslocamento do índice atual. Tudo o que você adiciona como o valor de offset é adicionado ao índice atual. Se o índice atual retornar 2 e você especificar 1 como o deslocamento, a função copyIndex() retornará 3.

O parâmetro loopName é opcional ou obrigatório, dependendo do local em que é usado. É obrigatório se usado dentro de um constructo properties e opcional se usado em uma matriz resources. Veja abaixo um exemplo em que ele é obrigatório:

"properties": {
    "storageProfile": {
      "copy": [
        {
          "name": "dataDisks",
          "count": "[parameters('numberOfDataDisks')]",
          "input": {
            "diskSizeGB": 1023,
            "lun": "[copyIndex('dataDisks')]",
            "createOption": "Empty"
          }
        }
      ]
    }
}

Observe como o elemento copy é usado dentro de um constructo properties e copyIndex() tem o loopName especificado como copyIndex('dataDisks').

Agora, veja um exemplo em que loopName não é obrigatório:

{
  "type": "Microsoft.Network/virtualNetworks",
  "apiVersion": "2018-04-01",
  "name": "[concat(parameters('vnetname'), copyIndex())]",
}

Ele mostra um recurso sendo declarado, e copyIndex() é chamado sem parâmetros, pois está sendo usado no contexto de um recurso.

Configurar a implantação

Quando você usa o elemento copy para recursos, acaba criando vários recursos com aparência semelhante.

Às vezes, convém controlar como os recursos são criados e em que ordem. Os motivos para controlar a ordem podem ser os seguintes:

  • Limitações de ambiente. Dependendo de qual ambiente é feita a implantação, o ideal é limitar o quanto esse ambiente é afetado por uma implantação. Em um ambiente de produção, faz sentido limitar quantos recursos são afetados em determinado momento. Você pode configurar um modo de implantação para controlar o número de recursos implantados simultaneamente.
  • Dependências. Você pode se tornar dependente de algo que já exista antes de se aventurar em criar o recurso de que precisa. Para expressar essa dependência, há um constructo chamado dependsOn.

Modos de implantação e copy

O ideal é garantir que um conjunto de recursos criado pelo constructo copy seja criado antes de qualquer outro elemento. Se esse for o caso, você precisará expressar essa situação. Lembre-se de que o que entra em jogo é o modo de implantação usado pelo Resource Manager. Há dois modos com suporte:

  • Serial. Definir um recurso para esse modo de implantação significa que ele será criado após o outro. Nesse modo, também se espera que você defina a propriedade batchSize para determinar quantos recursos são implantados com esse modo. Um novo lote não pode ser iniciado antes que o lote anterior seja concluído. É interessante limitar os itens dessa forma em um ambiente de produção, por exemplo, nos casos em que pode ser importante limitar o número de recursos afetados em determinado ponto.
  • Paralelo. Este é o modo de implantação padrão. A vantagem é a alta taxa de transferência. Portanto, o modelo é processado mais rapidamente. As desvantagens são que você não pode garantir a ordem, e talvez isso não seja o que você quer para um ambiente de produção.

Dependências

No contexto do elemento copy, você precisa informar o recurso com a dependência de qual seção ele está esperando. Você realiza essa dependência referenciando-a pelo nome com o seguinte JSON:

"resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2019-04-01",
      "name": "[concat(copyIndex(),'storage', uniqueString(resourceGroup().id))]",
      "location": "[resourceGroup().location]",
      "sku": {
        "name": "Standard_LRS"
      },
      "kind": "Storage",
      "copy": {
        "name": "storagecopy",
        "count": 3
      },
      "properties": {}
    },
    {
      "type": "Microsoft.Compute/virtualMachines",
      "apiVersion": "2015-06-15",
      "name": "[concat('VM', uniqueString(resourceGroup().id))]",
      "dependsOn": ["storagecopy"],
    }
  ]

Observe que o elemento copy tem uma propriedade name com o valor storagecopy. O recurso dependente, uma conta de armazenamento, está aguardando a conclusão da operação do elemento copy. Isso é expresso por "dependsOn": ["storagecopy"].

Assim, o modelo do ARM muda para um modo de implantação serial entre esses dois recursos. Isso pode afetar a velocidade da taxa de transferência da implantação, mas você expressou que se preocupa com determinada ordem de implantação, que agora tem precedência.