You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

咨询: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:

  1. 首先修改appServicePlan.bicep,添加输出属性:
output id string = asp.id
output aspPlan string = parameters('aspPlan')
  1. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 01:24:50