Compartilhar via


Loops iterativos no Bicep

Este artigo mostra como usar a sintaxe for para iterar sobre itens em uma coleção. Há suporte para essa funcionalidade da v0.3.1 em diante. É possível usar loops para definir várias cópias de um recurso, módulo, variável, propriedade ou saída. Use loops para evitar a sintaxe repetida no arquivo Bicep e para definir dinamicamente o número de cópias a serem criadas durante a implantação. Confira o Guia de início rápido: Criar várias instâncias de recurso no Bicep para um guia rápido sobre como usar sintaxes diferentes for para criar várias instâncias de recurso no Bicep.

Para usar loops para criar vários recursos ou módulos, cada instância deve ter um valor exclusivo para a name propriedade. Você pode usar o valor de índice ou valores exclusivos em matrizes ou coleções para criar os nomes.

Recursos de treinamento

Para obter diretrizes passo a passo sobre loops, consulte o módulo Criar arquivos Bicep flexíveis usando o módulo de condições e loops no Microsoft Learn.

Sintaxe de loop

Os loops podem ser declarados por:

  • Usando um índice de número inteiro. Essa opção funciona quando seu cenário é: "Quero criar este número de instâncias". A função range cria uma matriz de inteiros que começa no índice inicial e contém o número de elementos especificados. Dentro do loop, é possível usar o índice de números inteiros para modificar valores. Para saber mais, consulte Índice de números inteiros.

    [for <index> in range(<startIndex>, <numberOfElements>): {
      ...
    }]
    
  • Usando itens em uma matriz: essa opção funciona quando seu cenário é: "Quero criar uma instância para cada elemento em uma matriz". Dentro do loop, você pode usar o valor do elemento de matriz atual para modificar valores. Para obter mais informações, confira Elementos de matriz.

    [for <item> in <collection>: {
      ...
    }]
    
  • Usando itens em um objeto de dicionário: essa opção funciona quando seu cenário é: "Quero criar uma instância para cada item em um objeto". A função de itens converte o objeto em uma matriz. Dentro do loop, é possível usar propriedades do objeto para criar valores. Para saber mais, confira Objeto de dicionário.

    [for <item> in items(<object>): {
      ...
    }]
    
  • Usando índice inteiro e itens em uma matriz: essa opção funciona quando seu cenário é: "Quero criar uma instância para cada elemento em uma matriz, mas também preciso do índice atual para criar outro valor". Para obter mais informações, consulte a matriz e o índice loop.

    [for (<item>, <index>) in <collection>: {
      ...
    }]
    
  • Adicionando uma implantação condicional: essa opção funciona quando seu cenário é: "Quero criar várias instâncias, mas só quero implantar cada instância quando uma condição for verdadeira". Para obter mais informações, consulte Loop com condição.

    [for <item> in <collection>: if(<condition>) {
      ...
    }]
    

Limites de loop

O uso de loops no Bicep tem estas limitações:

  • Os loops do Bicep só funcionam com valores que podem ser determinados no início da implantação.
  • As iterações de loop não podem ser um número negativo ou exceder 800 iterações.
  • Como um recurso não pode fazer loop com recursos filho aninhados, transforme os recursos filho em recursos de nível superior. Para obter mais informações, consulte Iteração para um recurso filho.
  • Para fazer loop em vários níveis de propriedade, use a função maplambda.

Índice de número inteiro

Para obter um exemplo simples de como usar um índice, crie uma variável que contenha uma matriz de cadeias de caracteres:

param itemCount int = 5

var stringArray = [for i in range(0, itemCount): 'item${(i + 1)}']

output arrayResult array = stringArray

A saída retorna uma matriz com os seguintes elementos:

[
  "item1",
  "item2",
  "item3",
  "item4",
  "item5"
]

O exemplo a seguir cria o número de contas de armazenamento especificadas no parâmetro storageCount. Ele retorna três propriedades para cada conta de armazenamento:

param ___location string = resourceGroup().___location
param storageCount int = 2

resource storageAcct 'Microsoft.Storage/storageAccounts@2025-06-01' = [for i in range(0, storageCount): {
  name: '${i}storage${uniqueString(resourceGroup().id)}'
  ___location: ___location
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'Storage'
}]

output storageInfo array = [for i in range(0, storageCount): {
  id: storageAcct[i].id
  blobEndpoint: storageAcct[i].properties.primaryEndpoints.blob
  status: storageAcct[i].properties.statusOfPrimary
}]

Observe que o índice i é usado na criação do nome do recurso da conta de armazenamento.

O próximo exemplo implanta um módulo várias vezes:

param ___location string = resourceGroup().___location
param storageCount int = 2

var baseName = 'store${uniqueString(resourceGroup().id)}'

module stgModule './storageAccount.bicep' = [for i in range(0, storageCount): {
  name: '${i}deploy${baseName}'
  params: {
    storageName: '${i}${baseName}'
    ___location: ___location
  }
}]

output storageAccountEndpoints array = [for i in range(0, storageCount): {
  endpoint: stgModule[i].outputs.storageEndpoint
}]

Elementos da matriz

O exemplo a seguir cria uma conta de armazenamento para cada nome fornecido no parâmetro storageNames. Observe que a propriedade de nome para cada instância de recurso deve ser exclusiva:

param ___location string = resourceGroup().___location
param storageNames array = [
  'contoso'
  'fabrikam'
  'coho'
]

resource storageAcct 'Microsoft.Storage/storageAccounts@2025-06-01' = [for name in storageNames: {
  name: '${name}${uniqueString(resourceGroup().id)}'
  ___location: ___location
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'Storage'
}]

O exemplo a seguir itera em uma matriz para definir uma propriedade. Ele cria duas sub-redes em uma rede virtual. Observe que os nomes de sub-rede devem ser exclusivos:

param rgLocation string = resourceGroup().___location

var subnets = [
  {
    name: 'api'
    subnetPrefix: '10.144.0.0/24'
  }
  {
    name: 'worker'
    subnetPrefix: '10.144.1.0/24'
  }
]

resource vnet 'Microsoft.Network/virtualNetworks@2025-01-01' = {
  name: 'vnet'
  ___location: rgLocation
  properties: {
    addressSpace: {
      addressPrefixes: [
        '10.144.0.0/20'
      ]
    }
    subnets: [for subnet in subnets: {
      name: subnet.name
      properties: {
        addressPrefix: subnet.subnetPrefix
      }
    }]
  }
}

Matriz e índice

O exemplo a seguir usa o elemento de matriz e o valor do índice ao definir a conta de armazenamento:

param storageAccountNamePrefix string

var storageConfigurations = [
  {
    suffix: 'local'
    sku: 'Standard_LRS'
  }
  {
    suffix: 'geo'
    sku: 'Standard_GRS'
  }
]

resource storageAccountResources 'Microsoft.Storage/storageAccounts@2025-06-01' = [for (config, i) in storageConfigurations: {
  name: '${storageAccountNamePrefix}${config.suffix}${i}'
  ___location: resourceGroup().___location
  sku: {
    name: config.sku
  }
  kind: 'StorageV2'
}]

O próximo exemplo usa os elementos de uma matriz e um índice para gerar informações sobre os novos recursos:

param ___location string = resourceGroup().___location
param orgNames array = [
  'Contoso'
  'Fabrikam'
  'Coho'
]

resource nsg 'Microsoft.Network/networkSecurityGroups@2025-01-01' = [for name in orgNames: {
  name: 'nsg-${name}'
  ___location: ___location
}]

output deployedNSGs array = [for (name, i) in orgNames: {
  orgName: name
  nsgName: nsg[i].name
  resourceId: nsg[i].id
}]

Objeto de dicionário

Para iterar sobre elementos em um objeto de dicionário, use a itemsfunção, que converte o objeto em uma matriz. Use a propriedade value para obter propriedades sobre os objetos. Observe que os nomes de recursos nsg devem ser exclusivos.

param nsgValues object = {
  nsg1: {
    name: 'nsg-westus1'
    ___location: 'westus'
  }
  nsg2: {
    name: 'nsg-east1'
    ___location: 'eastus'
  }
}

resource nsg 'Microsoft.Network/networkSecurityGroups@2025-01-01' = [for nsg in items(nsgValues): {
  name: nsg.value.name
  ___location: nsg.value.___location
}]

Loop com condição

Em recursos e módulos, é possível adicionar uma expressão if com a sintaxe de loop para implantar condicionalmente a coleção.

O exemplo a seguir mostra um loop combinado com uma instrução de condição. Neste exemplo, uma única condição é aplicada a todas as instâncias do módulo:

param ___location string = resourceGroup().___location
param storageCount int = 2
param createNewStorage bool = true

var baseName = 'store${uniqueString(resourceGroup().id)}'

module stgModule './storageAccount.bicep' = [for i in range(0, storageCount): if(createNewStorage) {
  name: '${i}deploy${baseName}'
  params: {
    storageName: '${i}${baseName}'
    ___location: ___location
  }
}]

O exemplo a seguir mostra como aplicar uma condição específica ao elemento atual na matriz:

resource parentResources 'Microsoft.Example/examples@2024-06-06' = [for parent in parents: if(parent.enabled) {
  name: parent.name
  properties: {
    children: [for child in parent.children: {
      name: child.name
      setting: child.settingValue
    }]
  }
}]

Implantar em lotes

Os recursos do Azure são implantados em paralelo por padrão. Quando você usa um loop para criar várias instâncias de um tipo de recurso, essas instâncias são todas implantadas ao mesmo tempo. A ordem em que eles são criados não é garantida. Não há um limite para o número de recursos implantados em paralelo além do limite total de 800 recursos no arquivo Bicep.

Talvez você não queira atualizar todas as instâncias de um tipo de recurso ao mesmo tempo. Por exemplo, ao atualizar um ambiente de produção, talvez você queira escalonar as atualizações para que apenas um determinado número seja atualizado a qualquer momento. Você pode especificar um subconjunto das instâncias a serem agrupadas em lote e implantadas ao mesmo tempo. As outras instâncias esperam esse lote ser concluído.

Para implantar serialmente instâncias de um recurso, adicione o batchSize decorador. Defina seu valor como o número de instâncias a serem implantadas simultaneamente. Uma dependência é criada durante instâncias anteriores no loop, portanto, ela não inicia um lote até que o lote anterior seja concluído.

param ___location string = resourceGroup().___location

@batchSize(2)
resource storageAcct 'Microsoft.Storage/storageAccounts@2025-06-01' = [for i in range(0, 4): {
  name: '${i}storage${uniqueString(resourceGroup().id)}'
  ___location: ___location
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'Storage'
}]

Na implantação sequencial, defina o tamanho do lote como 1.

O decorador batchSize está no namespace sys. Se você precisar diferenciar este decorador de outro item com o mesmo nome, preceda o decorador com sys: @sys.batchSize(2)

Iteração para um recurso filho

Para criar mais de uma instância de um recurso filho, ambos os seguintes arquivos Bicep dão suporte a esta tarefa:

Recursos filhos aninhados

param ___location string = resourceGroup().___location

resource stg 'Microsoft.Storage/storageAccounts@2025-06-01' = {
  name: 'examplestorage'
  ___location: ___location
  kind: 'StorageV2'
  sku: {
    name: 'Standard_LRS'
  }
  resource service 'fileServices' = {
    name: 'default'
    resource share 'shares' = [for i in range(0, 3): {
      name: 'exampleshare${i}'
    }]
  }
}

Recursos filhos de nível superior

resource stg 'Microsoft.Storage/storageAccounts@2025-06-01' = {
  name: 'examplestorage'
  ___location: resourceGroup().___location
  kind: 'StorageV2'
  sku: {
    name: 'Standard_LRS'
  }
}

resource service 'Microsoft.Storage/storageAccounts/fileServices@2025-06-01' = {
  name: 'default'
  parent: stg
}

resource share 'Microsoft.Storage/storageAccounts/fileServices/shares@2025-06-01' = [for i in range(0, 3): {
  name: 'exampleshare${i}'
  parent: service
}]

Coleções de recurso/módulo de referência

A função do modelo do Azure Resource Manager (modelo ARM) references retorna uma matriz de objetos que representam os estados de tempo de execução de uma coleção de recursos. Como não há uma função de references explícita no Bicep e o uso simbólico da coleção é empregado diretamente, o Bicep a converte em um modelo do ARM que usa a função references do modelo do ARM enquanto o código é gerado. Para o recurso de tradução que usa a função references para transformar coleções simbólicas em modelos ARM, é necessário possuir a versão 0.20.X ou superior do CLI do Bicep. Além disso, no arquivo bicepconfig.json , a symbolicNameCodegen configuração deve ser apresentada e definida como true.

As saídas dos dois exemplos no Índice inteiro podem ser gravadas como:

param ___location string = resourceGroup().___location
param storageCount int = 2

resource storageAcct 'Microsoft.Storage/storageAccounts@2025-06-01' = [for i in range(0, storageCount): {
  name: '${i}storage${uniqueString(resourceGroup().id)}'
  ___location: ___location
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'Storage'
}]

output storageInfo array = map(storageAcct, store => {
  blobEndpoint: store.properties.primaryEndpoints
  status: store.properties.statusOfPrimary
})

output storageAccountEndpoints array = map(storageAcct, store => store.properties.primaryEndpoints)

Esse arquivo Bicep é transpilado para o seguinte modelo JSON do ARM que usa a references função:

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "languageVersion": "1.10-experimental",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "___location": {
      "type": "string",
      "defaultValue": "[resourceGroup().___location]"
    },
    "storageCount": {
      "type": "int",
      "defaultValue": 2
    }
  },
  "resources": {
    "storageAcct": {
      "copy": {
        "name": "storageAcct",
        "count": "[length(range(0, parameters('storageCount')))]"
      },
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2023-04-01",
      "name": "[format('{0}storage{1}', range(0, parameters('storageCount'))[copyIndex()], uniqueString(resourceGroup().id))]",
      "___location": "[parameters('___location')]",
      "sku": {
        "name": "Standard_LRS"
      },
      "kind": "Storage"
    }
  },
  "outputs": {
    "storageInfo": {
      "type": "array",
      "value": "[map(references('storageAcct', 'full'), lambda('store', createObject('blobEndpoint', lambdaVariables('store').properties.primaryEndpoints, 'status', lambdaVariables('store').properties.statusOfPrimary)))]"
    },
    "storageAccountEndpoints": {
      "type": "array",
      "value": "[map(references('storageAcct', 'full'), lambda('store', lambdaVariables('store').properties.primaryEndpoints))]"
    }
  }
}

Observe que, no modelo JSON do ARM anterior, languageVersion deve ser definido como 1.10-experimentale o elemento do recurso é um objeto em vez de uma matriz.

Próximas etapas

Para saber como criar arquivos Bicep, consulte a estrutura e a sintaxe do arquivo Bicep.