Bicep 中的迭代循环
本文演示如何使用 for
语法来循环访问集合中的项。 此功能在 v0.3.1 及更高版本中可用。 可以使用循环来定义资源、模块、变量、属性或输出的多个副本。 使用循环可以避免在 Bicep 文件中重复语法,并可以动态设置要在部署期间创建的副本数。 若要完成快速入门,请参阅快速入门:创建多个实例。
若要使用循环创建多个资源或模块,每个实例必须具有唯一的名称属性值。 可以使用数组或集合中的索引值或唯一值来创建名称。
循环语法
循环可以使用以下方式声明:
使用整数索引。 当场景为“我想创建这么多实例”时,此选项适用。range 函数创建整数数组,该数组从起始索引开始并包含指定元素的数量。 在循环中,可以使用整数索引来修改值。 有关详细信息,请参阅整数索引。
[for <index> in range(<startIndex>, <numberOfElements>): { ... }]
使用数组中的项。 当场景为“我想要为数组中的每个元素创建实例”时,此选项适用。在循环中,可以使用当前数组元素值修改值。 有关详细信息,请参阅数组元素。
[for <item> in <collection>: { ... }]
使用字典对象中的项。 当场景为“我想要为对象中的每个项创建实例”时,此选项适用。项函数可将对象转换为数组。 在循环中,可以使用对象中的属性来创建值。 有关详细信息,请参阅 字典对象。
[for <item> in items(<object>): { ... }]
使用整数索引和数组中的项。 当场景为“我想要为数组中每个元素创建实例,但还需要当前索引来创建另一个值”时,此选项适用。有关详细信息,请参阅循环数组和索引。
[for (<item>, <index>) in <collection>: { ... }]
添加条件部署。 当场景为“我想要创建多个实例,但对于每个实例,我希望仅在条件为真时进行部署”时,此选项适用。有关详细信息,请参阅带条件的循环。
[for <item> in <collection>: if(<condition>) { ... }]
循环限制
在 Bicep 中使用循环有以下限制:
- Bicep 循环仅适用于可在部署开始时确定的值。
- 循环迭代不能为负数,也不能超过 800 次迭代。
- 不能循环带有嵌套子资源的资源。 必须将子资源更改为顶级资源。 请参阅子资源的迭代。
- 若要在多个属性级别上循环,请使用 lambda map 函数。
整数索引
有关使用索引的简单示例,请创建一个包含字符串数组的变量。
param itemCount int = 5
var stringArray = [for i in range(0, itemCount): 'item${(i + 1)}']
output arrayResult array = stringArray
输出返回具有以下值的数组:
[
"item1",
"item2",
"item3",
"item4",
"item5"
]
下一个示例将创建 storageCount
参数中指定的存储帐户数。 它将返回每个存储帐户的三个属性。
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
}]
请注意,创建存储帐户资源名称时将使用索引 i
。
下一个示例将多次部署一个模块。
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
}]
数组元素
以下示例为 storageNames
参数中提供的每个名称创建一个存储帐户。 请注意,每个资源实例的名称属性必须独一无二。
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'
}]
下一个示例将循环访问数组以定义属性。 它将在虚拟网络内创建两个子网。 请注意,子网名称必须独一无二。
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
}
}]
}
}
数组和索引
以下示例在定义存储帐户时使用数组元素和索引值。
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'
}]
下一个示例使用数组元素和索引来输出有关新资源的信息。
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
}]
字典对象
要在字典对象中循环访问元素,请使用 items 函数,该函数会将对象转换为数组。 请使用 value
属性获取对象的属性。 请注意,nsg 资源名称必须独一无二。
param nsgValues object = {
nsg1: {
name: 'nsg-chinanorth1'
location: 'chinanorth'
}
nsg2: {
name: 'nsg-east1'
location: 'chinaeast'
}
}
resource nsg 'Microsoft.Network/networkSecurityGroups@2023-11-01' = [for nsg in items(nsgValues): {
name: nsg.value.name
location: nsg.value.location
}]
带条件的循环
对于资源和模块,可以在循环语法中添加 if
表达式,以有条件地部署集合。
以下示例演示了一个结合使用条件语句的循环。 此示例将单个条件应用于模块的所有实例。
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
}
}]
下一个示例演示如何应用特定于数组中当前元素的条件。
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
}]
}
}]
批量部署
默认情况下,将并行部署 Azure 资源。 使用循环创建多个资源类型实例时,将同时部署这些实例。 不会保证它们的创建顺序。 除了 Bicep 文件中的资源总数为 800 这一限制外,并行部署的资源数量没有限制。
你可能不希望同时更新资源类型的所有实例。 例如,在更新生产环境时,可能需要错开更新,使任何一次仅更新一定数量。 可指定同时批处理和部署其中一部分实例。 其他实例等待该批处理完成。
若要串行部署资源的实例,请添加 batchSize 修饰器。 将其值设置为要并发部署的实例数。 在循环中创建先前实例的依赖关系,使其在上一个批处理完成后才启动批处理。
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'
}]
对于顺序部署,请将批大小设置为 1。
batchSize
修饰器位于 sys 命名空间中。 如果你需要将此装饰器与同名的其他项区分开来,请在修饰器前面加上 sys:@sys.batchSize(2)
子资源的迭代
若要创建子资源的多个实例,以下两个 Bicep 文件都将正常工作。
嵌套子资源
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}'
}]
}
}
顶级子资源
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
}]
引用资源/模块集合
ARM 模板 references
函数会返回表示资源集合运行时状态的一组对象。 在 Bicep 中,不存在显式引用函数。 相反,符号集合用法是直接使用的,并且在代码生成期间,Bicep 会将其转换为利用 ARM 模板引用函数的 ARM 模板。 对于使用引用函数将符号集合转换为 ARM 模板的转换功能,必须具有 Bicep CLI 版本 0.20.X 或更高版本。 此外,在 bicepconfig.json
文件中,应显示 symbolicNameCodegen
设置并设置为 true
。
整数索引中两个示例的输出可以编写为:
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)
此 Bicep 文件会转译到以下利用 references
函数的 ARM JSON 模板中:
{
"$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))]"
}
}
}
请注意,在前面的 ARM JSON 模板中,必须将 languageVersion
设置为 1.10-experimental
,并且资源元素是对象而不是数组。
后续步骤
- 若要了解如何创建 Bicep 文件,请参阅文件。