咨询:Azure Bicep中无需索引关联Function App与App Service Plan的方法
问题描述
我正在尝试创建多个采用不同计划(如Consumption、Flex Consumption)的Function App,已通过数组向App Service Plan和Function App传递参数。但在部署资源时,Bicep无法正确映射对应的App Service Plan,尝试一对一索引方式也无效。现咨询是否存在其他方法,可在Function App中引用对应App Service Plan的资源ID。
我已对Function App模块进行拆分,使其能够根据传入的不同计划参数完成创建,当前使用Azure Verified Module开发资源,相关代码如下:
main.bicep
module appServicePlan './Modules/AppServicePlan/appServicePlan.bicep' = [ for fa in functionApps.appServicePlans: { name: 'appserviceplan-${fa.key}' params: { name: '${fa.key}-asp' kind: fa.kind location: location skuName: fa.skuName skuCapacity: fa.skuCapacity zoneRedundant: fa.zoneRedundant elasticScaleEnabled: fa.elasticScaleEnabled perSiteScaling: fa.perSiteScaling targetWorkerCount: fa.targetWorkerCount targetWorkerSize: fa.targetWorkerSize maximumElasticWorkerCount: fa.maximumElasticWorkerCount reserved: fa.reserved diagnosticSettings: fa.diagnosticSettings aspPlan: fa.aspPlan } } ] module functionAppModule './Modules/FunctionApp/functionApp.bicep' = [ for (fa, i) in functionApps.functionApps: { name: 'funappsdeploye-${fa.key}-${uniqueString(resourceGroup().id, fa.key)}' params: { name: '${fa.key}' deploymentName: 'functionapps-${fa.key}-${uniqueString(resourceGroup().id, fa.key)}' kind: fa.kind functionAppType: fa.functionAppType serverFarmResourceId: // configs: [ // { // // applicationInsightResourceId : // name : fa.configs[i].name // properties : fa.configs[i].properties // // storageAccountResourceId // storageAccountUseIdentityAuthentication : fa.configs[i].storageAccountUseIdentityAuthentication // } // ] outboundVnetRouting : fa.outboundVnetRouting diagnosticSettings: fa.diagnosticSettings publicNetworkAccess: fa.publicNetworkAccess location: location managedIdentities: fa.managedIdentities siteConfig: fa.siteConfig // virtualNetworkSubnetResourceId: fa.subnetDelegation == 'Microsoft.App/serverFarms' // ? functionAppsServerFarmsSubnetId // : functionAppEnvironmentsSubnetId // privateEndpoints: empty(privateEndpointSubnetId) // ? [] // : [ // { // name: '${namingModule.outputs.names.functionApp.name}-${fa.key}-pe' // service: 'sites' // subnetResourceId: privateEndpointSubnetId // privateDnsZoneGroup: { // privateDnsZoneGroupConfigs: [ // { // privateDnsZoneResourceId: resourceId( // resourceGroup().name, // 'Microsoft.Network/privateDnsZones', // 'privatelink.azurewebsites.net' // ) // } // ] // } // } // ] functionAppConfig: { deployment: { storage: { type: 'blobcontainer' value: 'https://${storageAccount.outputs.name}.blob.core.windows.net/${fa.fnappStorageAccount.storageBlobContainerName}' authentication: { type: 'systemassignedidentity' } } } scaleAndConcurrency: { maximumInstanceCount: 100 instanceMemoryMB: 2048 } runtime: { name: 'dotnet-isolated' version: '8.0' } } tags: tags } dependsOn: [ appServicePlan ] } }
parameter.json
{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "functionApps": { "value": { "appServicePlans": [ { "key": "admindashboard2", "kind": "functionapp", "skuName": "Y1", "skuCapacity": 0, "zoneRedundant": false, "elasticScaleEnabled": false, "perSiteScaling": false, "targetWorkerCount": 0, "targetWorkerSize": 0, "maximumElasticWorkerCount": 0, "reserved": true, "diagnosticSettings": [], "aspPlan": "Consumption" }, { "key": "admindashboard1", "kind": "functionapp", "skuName": "FC1", "skuCapacity": 0, "zoneRedundant": false, "elasticScaleEnabled": false, "perSiteScaling": false, "targetWorkerCount": 0, "targetWorkerSize": 0, "maximumElasticWorkerCount": 0, "reserved": true, "diagnosticSettings": [], "aspPlan": "FlexConsumption" } ], "functionApps": [ { "key": "admindashboard01", "kind": "functionapp,linux", "subnetDelegation": "Microsoft.App/environments", "functionAppType": "FlexConsumption", "location": "eastus", "httpsOnly": true, "fnappStorageAccount": { "storageAccountIndex": 0, "storageBlobContainerName": "admindashboard" }, "configs": [ { "name": "appsettings", "properties": { "APPLICATIONINSIGHTS_AUTHENTICATION_STRING": "Authorization=AAD", "AzureWebJobsServiceBus": "", "AzureFunctionsWebHost__hostid": "admindashboard-dev", "kvEnv": "", "AzureWebJobsStorage__accountName": "" }, "storageAccountUseIdentityAuthentication": true } ], "diagnosticSettings": [], "publicNetworkAccess": "Enabled", "managedIdentities": { "systemAssigned": true }, "outboundVnetRouting": { "allTraffic": true, "contentShareTraffic": true, "imagePullTraffic": true }, "siteConfig": { "healthCheckPath": "/", "use32BitWorkerProcess": false, "http20Enabled": true, "minTlsVersion": "1.2", "scmSiteConfig": { "useScmSecurity": false, "ftpsState": "Disabled" }, "ipSecurityRestrictionsDefaultAction": "Allow", "ipSecurityRestrictions": [], "scmIpSecurityRestrictionsDefaultAction": "Allow", "scmIpSecurityRestrictionsUseMain": true, "scmIpSecurityRestrictions": [ { "ipAddress": "any", "action": "deny", "priority": 2147483647, "name": "Deny all", "description": "Deny all access" } ] } }, { "key": "admindashboard02", "kind": "functionapp,linux", "subnetDelegation": "Microsoft.App/environments", "functionAppType": "Consumption", "location": "eastus", "httpsOnly": true, "fnappStorageAccount": { "storageAccountIndex": 0, "storageBlobContainerName": "admindashboard" }, "configs": [ { "name": "appsettings", "properties": { "APPLICATIONINSIGHTS_AUTHENTICATION_STRING": "Authorization=AAD", "AzureWebJobsServiceBus": "", "AzureFunctionsWebHost__hostid": "admindashboard-dev", "kvEnv": "", "AzureWebJobsStorage__accountName": "" }, "storageAccountUseIdentityAuthentication": true } ], "diagnosticSettings": [], "publicNetworkAccess": "Enabled", "managedIdentities": { "systemAssigned": true }, "outboundVnetRouting": { "allTraffic": true, "contentShareTraffic": true, "imagePullTraffic": true }, "siteConfig": { "healthCheckPath": "/", "use32BitWorkerProcess": false, "http20Enabled": true, "minTlsVersion": "1.2", "scmSiteConfig": { "useScmSecurity": false, "ftpsState": "Disabled" }, "ipSecurityRestrictionsDefaultAction": "Allow", "ipSecurityRestrictions": [], "scmIpSecurityRestrictionsDefaultAction": "Allow", "scmIpSecurityRestrictionsUseMain": true, "scmIpSecurityRestrictions": [ { "ipAddress": "any", "action": "deny", "priority": 2147483647, "name": "Deny all", "description": "Deny all access" } ] } } ] } } } }
解决方法
核心是通过明确标识建立Function App与App Service Plan的映射关系,替代不可靠的索引匹配,以下是两种可行方案:
方案1:通过计划类型匹配
利用filter+first函数,根据Function App的functionAppType字段匹配对应的App Service Plan:
- 首先修改
appServicePlan.bicep,添加输出属性:
output id string = asp.id output aspPlan string = parameters('aspPlan')
- 在main.bicep的Function App模块中,将
serverFarmResourceId替换为:
serverFarmResourceId: first(filter(appServicePlan, asp => asp.outputs.aspPlan == fa.functionAppType)).outputs.id
该逻辑会筛选出与当前Function App计划类型一致的App Service Plan,并获取其资源ID。
方案2:参数结构中直接关联Key
修改parameter.json,给每个Function App添加对应App Service Plan的aspKey字段,直接建立关联:
"functionApps": [ { "key": "admindashboard01", "aspKey": "admindashboard1", // 关联FlexConsumption类型的ASP // 其他属性... }, { "key": "admindashboard02", "aspKey": "admindashboard2", // 关联Consumption类型的ASP // 其他属性... } ]
然后在main.bicep中通过Key匹配:
serverFarmResourceId: first(filter(appServicePlan, asp => asp.name == 'appserviceplan-${fa.aspKey}')).outputs.id
这种方式更直观,避免类型重复导致的匹配错误。
额外验证(可选)
可以添加断言语句,提前验证匹配结果的唯一性,避免部署失败:
assert matchedAspCount = length(filter(appServicePlan, asp => asp.outputs.aspPlan == fa.functionAppType)) == 1
内容的提问来源于stack exchange,提问作者Omkar
相关产品推荐
相关产品推荐

