Iterativa loopar i Bicep

Den här artikeln visar hur du använder syntaxen for för att iterera över objekt i en samling. Den här funktionen stöds från och med v0.3.1. Du kan använda loopar för att definiera flera kopior av en resurs, modul, variabel, egenskap eller utdata. Använd loopar för att undvika upprepad syntax i Bicep-filen och för att dynamiskt ange antalet kopior som ska skapas under distributionen. Information om hur du går igenom en snabbstart finns i Snabbstart: Skapa flera instanser.

Om du vill använda loopar för att skapa flera resurser eller moduler måste varje instans ha ett unikt värde för namnegenskapen. Du kan använda indexvärdet eller unika värden i matriser eller samlingar för att skapa namnen.

Utbildningsresurser

Om du hellre vill lära dig mer om loopar via stegvis vägledning kan du läsa Skapa flexibla Bicep-mallar med hjälp av villkor och loopar.

Loopsyntax

Loopar kan deklareras av:

  • Använda ett heltalsindex. Det här alternativet fungerar när ditt scenario är: "Jag vill skapa så här många instanser." Intervallfunktionen skapar en matris med heltal som börjar vid startindexet och innehåller antalet angivna element. I loopen kan du använda heltalsindexet för att ändra värden. Mer information finns i Heltalsindex.

    [for <index> in range(<startIndex>, <numberOfElements>): {
      ...
    }]
    
  • Använda objekt i en matris. Det här alternativet fungerar när scenariot är: "Jag vill skapa en instans för varje element i en matris." I loopen kan du använda värdet för det aktuella matriselementet för att ändra värden. Mer information finns i Matriselement.

    [for <item> in <collection>: {
      ...
    }]
    
  • Använda objekt i ett ordlisteobjekt. Det här alternativet fungerar när scenariot är: "Jag vill skapa en instans för varje objekt i ett objekt." Objektfunktionen konverterar objektet till en matris. I loopen kan du använda egenskaper från objektet för att skapa värden. Mer information finns i Ordlisteobjekt.

    [for <item> in items(<object>): {
      ...
    }]
    
  • Använda heltalsindex och objekt i en matris. Det här alternativet fungerar när scenariot är: "Jag vill skapa en instans för varje element i en matris, men jag behöver också det aktuella indexet för att skapa ett annat värde." Mer information finns i Loopmatris och index.

    [for (<item>, <index>) in <collection>: {
      ...
    }]
    
  • Lägga till en villkorsstyrd distribution. Det här alternativet fungerar när ditt scenario är: "Jag vill skapa flera instanser, men för varje instans vill jag bara distribuera när ett villkor är sant." Mer information finns i Loopa med villkor.

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

Loopgränser

Att använda loopar i Bicep har följande begränsningar:

  • Bicep-loopar fungerar bara med värden som kan fastställas i början av distributionen.
  • Loop-iterationer kan inte vara ett negativt tal eller överskrida 800 iterationer.
  • Det går inte att loopa en resurs med kapslade underordnade resurser. Ändra underordnade resurser till resurser på den översta nivån. Se Iteration för en underordnad resurs.
  • Om du vill loopa på flera nivåer av egenskaper använder du funktionen lambda map.

Heltalsindex

Ett enkelt exempel på hur du använder ett index är att skapa en variabel som innehåller en matris med strängar.

param itemCount int = 5

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

output arrayResult array = stringArray

Utdata returnerar en matris med följande värden:

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

I nästa exempel skapas det antal lagringskonton som anges i parametern storageCount . Den returnerar tre egenskaper för varje lagringskonto.

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

resource storageAcct 'Microsoft.Storage/storageAccounts@2022-09-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
}]

Observera att indexet i används för att skapa lagringskontots resursnamn.

I nästa exempel distribueras en modul flera gånger.

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
}]

Vektorelement

I följande exempel skapas ett lagringskonto för varje namn som anges i parametern storageNames . Observera att namnegenskapen för varje resursinstans måste vara unik.

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

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

Nästa exempel itererar över en matris för att definiera en egenskap. Det skapar två undernät i ett virtuellt nätverk. Observera att undernätsnamnen måste vara unika.

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@2020-07-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
      }
    }]
  }
}

Matris och index

I följande exempel används både matriselementet och indexvärdet när du definierar lagringskontot.

param storageAccountNamePrefix string

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

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

I nästa exempel används både elementen i en matris och ett index för att mata ut information om de nya resurserna.

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

resource nsg 'Microsoft.Network/networkSecurityGroups@2020-06-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
}]

Ordlisteobjekt

Om du vill iterera över element i ett ordlisteobjekt använder du objektfunktionen som konverterar objektet till en matris. Använd egenskapen value för att hämta egenskaper för objekten. Observera att nsg-resursnamnen måste vara unika.

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

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

Loop med villkor

För resurser och moduler kan du lägga till ett if uttryck med loopsyntaxen för att villkorligt distribuera samlingen.

I följande exempel visas en loop som kombineras med en villkorssats. I det här exemplet tillämpas ett enda villkor på alla instanser av modulen.

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
  }
}]

I nästa exempel visas hur du tillämpar ett villkor som är specifikt för det aktuella elementet i matrisen.

resource parentResources 'Microsoft.Example/examples@2020-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
    }]
  }
}]

Distribuera i batchar

Som standard distribueras Azure-resurser parallellt. När du använder en loop för att skapa flera instanser av en resurstyp distribueras alla dessa instanser samtidigt. Ordningen som de skapas i är inte garanterad. Det finns ingen gräns för antalet resurser som distribueras parallellt, förutom den totala gränsen på 800 resurser i Bicep-filen.

Du kanske inte vill uppdatera alla instanser av en resurstyp samtidigt. När du till exempel uppdaterar en produktionsmiljö kanske du vill flytta uppdateringarna så att endast ett visst antal uppdateras samtidigt. Du kan ange att en delmängd av instanserna ska batchas ihop och distribueras samtidigt. De andra instanserna väntar på att batchen ska slutföras.

Om du vill distribuera instanser av en resurs seriellt lägger du till batchSize-dekoratören. Ange dess värde till antalet instanser som ska distribueras samtidigt. Ett beroende skapas på tidigare instanser i loopen, så det startar inte en batch förrän föregående batch har slutförts.

param location string = resourceGroup().location

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

För sekventiell distribution anger du batchstorleken till 1.

Dekoratören batchSizefinns i sys-namnområdet. Om du behöver skilja den här dekoratören från ett annat objekt med samma namn, förorda dekoratören med sys: @sys.batchSize(2)

Iteration för en underordnad resurs

Du kan inte använda en loop för en kapslad underordnad resurs. Om du vill skapa mer än en instans av en underordnad resurs ändrar du den underordnade resursen till en resurs på den översta nivån.

Anta till exempel att du vanligtvis definierar en filtjänst och filresurs som kapslade resurser för ett lagringskonto.

resource stg 'Microsoft.Storage/storageAccounts@2022-09-01' = {
  name: 'examplestorage'
  location: resourceGroup().location
  kind: 'StorageV2'
  sku: {
    name: 'Standard_LRS'
  }
  resource service 'fileServices' = {
    name: 'default'
    resource share 'shares' = {
      name: 'exampleshare'
    }
  }
}

Om du vill skapa fler än en filresurs flyttar du den utanför lagringskontot. Du definierar relationen med den överordnade resursen via egenskapen parent .

I följande exempel visas hur du skapar ett lagringskonto, en filtjänst och mer än en filresurs:

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

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

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

Referensresurs-/modulsamlingar

FUNKTIONEN ARM-mall references returnerar en matris med objekt som representerar en resurssamlings körningstillstånd. I Bicep finns det ingen funktion för explicita referenser. I stället används symbolisk samlingsanvändning direkt, och under kodgenereringen översätter Bicep den till en ARM-mall som använder funktionen ARM-mallreferenser. För översättningsfunktionen som omvandlar symboliska samlingar till ARM-mallar med hjälp av referensfunktionen är det nödvändigt att ha Bicep CLI version 0.20.X eller senare. I bicepconfig.json filen symbolicNameCodegen ska dessutom inställningen visas och anges till true.

Utdata från de två exemplen i Heltalsindex kan skrivas som:

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

resource storageAcct 'Microsoft.Storage/storageAccounts@2022-09-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)

Den här Bicep-filen överförs till följande ARM JSON-mall som använder references funktionen:

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

Observera i föregående ARM JSON-mall, languageVersion måste anges till 1.10-experimental, och resurselementet är ett objekt i stället för en matris.

Nästa steg

  • Mer information om hur du skapar Bicep-filer finns i filen.