Pętle iteracyjne w Bicep
W tym artykule pokazano, jak używać for
składni do iterowania elementów w kolekcji. Ta funkcja jest obsługiwana od wersji 0.3.1 do nowszej. Pętle umożliwiają definiowanie wielu kopii zasobu, modułu, zmiennej, właściwości lub danych wyjściowych. Użyj pętli, aby uniknąć powtarzania składni w pliku Bicep i dynamicznie ustawiać liczbę kopii do utworzenia podczas wdrażania. Aby zapoznać się z przewodnikiem Szybki start, zobacz Szybki start: tworzenie wielu wystąpień.
Aby używać pętli do tworzenia wielu zasobów lub modułów, każde wystąpienie musi mieć unikatową wartość właściwości name. Aby utworzyć nazwy, możesz użyć wartości indeksu lub unikatowych wartości w tablicach lub kolekcjach.
Zasoby szkoleniowe
Jeśli wolisz dowiedzieć się więcej na temat pętli za pomocą wskazówek krok po kroku, zobacz Tworzenie elastycznych szablonów Bicep przy użyciu warunków i pętli.
Składnia pętli
Pętle mogą być deklarowane przez:
Za pomocą indeksu liczb całkowitych. Ta opcja działa, gdy twój scenariusz to: "Chcę utworzyć to wiele wystąpień". Funkcja zakresu tworzy tablicę liczb całkowitych rozpoczynających się od indeksu początkowego i zawiera liczbę określonych elementów. W pętli można użyć indeksu liczby całkowitej, aby zmodyfikować wartości. Aby uzyskać więcej informacji, zobacz Indeks liczb całkowitych.
[for <index> in range(<startIndex>, <numberOfElements>): { ... }]
Używanie elementów w tablicy. Ta opcja działa, gdy scenariusz to: "Chcę utworzyć wystąpienie dla każdego elementu w tablicy". W pętli można użyć wartości bieżącego elementu tablicy, aby zmodyfikować wartości. Aby uzyskać więcej informacji, zobacz Elementy tablicy.
[for <item> in <collection>: { ... }]
Używanie elementów w obiekcie słownika. Ta opcja działa, gdy w twoim scenariuszu jest: "Chcę utworzyć wystąpienie dla każdego elementu w obiekcie". Funkcja items konwertuje obiekt na tablicę. W ramach pętli można użyć właściwości z obiektu do utworzenia wartości. Aby uzyskać więcej informacji, zobacz Obiekt słownika.
[for <item> in items(<object>): { ... }]
Używanie indeksu całkowitego i elementów w tablicy. Ta opcja działa, gdy twój scenariusz to: "Chcę utworzyć wystąpienie dla każdego elementu w tablicy, ale potrzebuję również bieżącego indeksu, aby utworzyć inną wartość". Aby uzyskać więcej informacji, zobacz Tablica pętli i indeks.
[for (<item>, <index>) in <collection>: { ... }]
Dodawanie wdrożenia warunkowego. Ta opcja działa, gdy w twoim scenariuszu jest: "Chcę utworzyć wiele wystąpień, ale dla każdego wystąpienia chcę wdrożyć tylko wtedy, gdy warunek ma wartość true". Aby uzyskać więcej informacji, zobacz Pętla z warunkiem.
[for <item> in <collection>: if(<condition>) { ... }]
Limity pętli
Używanie pętli w Bicep ma następujące ograniczenia:
- Pętle Bicep działają tylko z wartościami, które można określić na początku wdrożenia.
- Iteracje pętli nie mogą być liczbą ujemną ani przekraczać 800 iteracji.
- Nie można pętli zasobu z zagnieżdżonym zasobami podrzędnymi. Zmień zasoby podrzędne na zasoby najwyższego poziomu. Zobacz Iteracja zasobu podrzędnego.
- Aby przeprowadzić pętlę na wielu poziomach właściwości, użyj funkcji mapy lambda.
Indeks liczby całkowitej
Aby uzyskać prosty przykład użycia indeksu, utwórz zmienną zawierającą tablicę ciągów.
param itemCount int = 5
var stringArray = [for i in range(0, itemCount): 'item${(i + 1)}']
output arrayResult array = stringArray
Dane wyjściowe zwracają tablicę z następującymi wartościami:
[
"item1",
"item2",
"item3",
"item4",
"item5"
]
W następnym przykładzie zostanie utworzona liczba kont magazynu określonych w parametrze storageCount
. Zwraca trzy właściwości dla każdego konta magazynu.
param location string = resourceGroup().location
param storageCount int = 2
resource storageAcct 'Microsoft.Storage/storageAccounts@2023-05-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
}]
Zwróć uwagę, że indeks i
jest używany podczas tworzenia nazwy zasobu konta magazynu.
W następnym przykładzie jest wdrażany moduł wiele razy.
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
}]
Elementy tablicy
Poniższy przykład tworzy jedno konto magazynu dla każdej nazwy podanej w parametrze storageNames
. Zanotuj właściwość name dla każdego wystąpienia zasobu musi być unikatowa.
param location string = resourceGroup().location
param storageNames array = [
'contoso'
'fabrikam'
'coho'
]
resource storageAcct 'Microsoft.Storage/storageAccounts@2023-05-01' = [for name in storageNames: {
name: '${name}${uniqueString(resourceGroup().id)}'
location: location
sku: {
name: 'Standard_LRS'
}
kind: 'Storage'
}]
W następnym przykładzie iteruje tablicę w celu zdefiniowania właściwości. Tworzy dwie podsieci w sieci wirtualnej. Należy pamiętać, że nazwy podsieci muszą być unikatowe.
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@2023-11-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
}
}]
}
}
Tablica i indeks
W poniższym przykładzie użyto zarówno elementu tablicy, jak i wartości indeksu podczas definiowania konta magazynu.
param storageAccountNamePrefix string
var storageConfigurations = [
{
suffix: 'local'
sku: 'Standard_LRS'
}
{
suffix: 'geo'
sku: 'Standard_GRS'
}
]
resource storageAccountResources 'Microsoft.Storage/storageAccounts@2023-05-01' = [for (config, i) in storageConfigurations: {
name: '${storageAccountNamePrefix}${config.suffix}${i}'
location: resourceGroup().location
sku: {
name: config.sku
}
kind: 'StorageV2'
}]
W następnym przykładzie użyto zarówno elementów tablicy, jak i indeksu, aby uzyskać informacje o nowych zasobach.
param location string = resourceGroup().location
param orgNames array = [
'Contoso'
'Fabrikam'
'Coho'
]
resource nsg 'Microsoft.Network/networkSecurityGroups@2023-11-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
}]
Obiekt słownika
Aby iterować elementy w obiekcie słownika, użyj funkcji items, która konwertuje obiekt na tablicę. value
Użyj właściwości , aby uzyskać właściwości obiektów. Pamiętaj, że nazwy zasobów sieciowej grupy zabezpieczeń muszą być unikatowe.
param nsgValues object = {
nsg1: {
name: 'nsg-westus1'
location: 'westus'
}
nsg2: {
name: 'nsg-east1'
location: 'eastus'
}
}
resource nsg 'Microsoft.Network/networkSecurityGroups@2023-11-01' = [for nsg in items(nsgValues): {
name: nsg.value.name
location: nsg.value.location
}]
Pętla z warunkiem
W przypadku zasobów i modułów można dodać if
wyrażenie ze składnią pętli w celu warunkowego wdrożenia kolekcji.
W poniższym przykładzie przedstawiono pętlę połączoną z instrukcją condition. W tym przykładzie pojedynczy warunek jest stosowany do wszystkich wystąpień modułu.
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
}
}]
W następnym przykładzie pokazano, jak zastosować warunek specyficzny dla bieżącego elementu w tablicy.
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
}]
}
}]
Wdrażanie w partiach
Domyślnie zasoby platformy Azure są wdrażane równolegle. Gdy używasz pętli do tworzenia wielu wystąpień typu zasobu, wszystkie te wystąpienia są wdrażane w tym samym czasie. Kolejność ich tworzenia nie jest gwarantowana. Nie ma żadnego limitu liczby zasobów wdrożonych równolegle, poza całkowitym limitem 800 zasobów w pliku Bicep.
Możesz nie chcieć zaktualizować wszystkich wystąpień typu zasobu w tym samym czasie. Na przykład podczas aktualizowania środowiska produkcyjnego może być konieczne rozłożenie aktualizacji tak, aby tylko określona liczba została zaktualizowana w dowolnym momencie. Można określić, że podzbiór wystąpień jest wsadowy i wdrażany w tym samym czasie. Inne wystąpienia czekają na ukończenie tej partii.
Aby szeregowo wdrożyć wystąpienia zasobu, dodaj dekorator batchSize. Ustaw jej wartość na liczbę wystąpień, które mają być wdrażane współbieżnie. Zależność jest tworzona na wcześniejszych wystąpieniach w pętli, więc nie uruchamia jednej partii, dopóki poprzednia partia nie zostanie ukończona.
param location string = resourceGroup().location
@batchSize(2)
resource storageAcct 'Microsoft.Storage/storageAccounts@2023-05-01' = [for i in range(0, 4): {
name: '${i}storage${uniqueString(resourceGroup().id)}'
location: location
sku: {
name: 'Standard_LRS'
}
kind: 'Storage'
}]
W przypadku wdrożenia sekwencyjnego ustaw rozmiar partii na 1.
Dekorator batchSize
znajduje się w przestrzeni nazw systemu. Jeśli chcesz odróżnić ten dekorator od innego elementu o tej samej nazwie, należy poprzeć dekorator za pomocą systemu: @sys.batchSize(2)
Iteracja zasobu podrzędnego
Aby utworzyć więcej niż jedno wystąpienie zasobu podrzędnego, oba następujące pliki Bicep będą działać.
Zagnieżdżone zasoby podrzędne
param location string = resourceGroup().location
resource stg 'Microsoft.Storage/storageAccounts@2023-05-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}'
}]
}
}
Zasoby podrzędne najwyższego poziomu
resource stg 'Microsoft.Storage/storageAccounts@2023-05-01' = {
name: 'examplestorage'
location: resourceGroup().location
kind: 'StorageV2'
sku: {
name: 'Standard_LRS'
}
}
resource service 'Microsoft.Storage/storageAccounts/fileServices@2023-05-01' = {
name: 'default'
parent: stg
}
resource share 'Microsoft.Storage/storageAccounts/fileServices/shares@2023-05-01' = [for i in range(0, 3): {
name: 'exampleshare${i}'
parent: service
}]
Odwołania do kolekcji zasobów/modułów
Funkcja szablonu references
usługi ARM zwraca tablicę obiektów reprezentujących stany środowiska uruchomieniowego kolekcji zasobów. W Bicep nie ma jawnej funkcji odwołań. Zamiast tego użycie kolekcji symbolicznej jest stosowane bezpośrednio, a podczas generowania kodu Bicep tłumaczy go na szablon usługi ARM, który korzysta z funkcji odwołań do szablonu usługi ARM. Aby funkcja tłumaczenia przekształcała kolekcje symboliczne w szablony usługi ARM przy użyciu funkcji references, konieczne jest posiadanie interfejsu wiersza polecenia Bicep w wersji 0.20.X lub nowszej. Ponadto w bicepconfig.json
pliku symbolicNameCodegen
należy przedstawić ustawienie i ustawić wartość true
.
Dane wyjściowe dwóch przykładów w indeksie liczba całkowita można zapisać jako:
param location string = resourceGroup().location
param storageCount int = 2
resource storageAcct 'Microsoft.Storage/storageAccounts@2023-05-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)
Ten plik Bicep jest transpilowany do następującego szablonu JSON usługi ARM, który korzysta z references
funkcji:
{
"$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))]"
}
}
}
Uwaga w poprzednim szablonie languageVersion
JSON usługi ARM musi być ustawiona na 1.10-experimental
, a element zasobu jest obiektem zamiast tablicy.
Następne kroki
- Aby dowiedzieć się więcej o tworzeniu plików Bicep, zobacz plik.