使用Azure部署槽时BICEP配置异常问题排查
问题排查:BICEP部署导致Function App部署槽内容被清空
此前使用BICEP部署Function App一直正常,为降低对用户的影响引入Azure部署槽功能。首次向staging槽部署并交换至生产槽一切正常,但再次部署后,交换时发现staging槽内容为空,无法在新代码出问题时回滚。多次测试确认:每次运行BICEP部署时,Function App的内容会被清空,不符合预期,需排查配置错误。
相关代码片段
BICEP代码
resource sites_azfun_xxxxxxxxxxxxxxx_web 'Microsoft.Web/sites@2022-09-01' = { name: sites_azfun_xxxxxxxxxxxxxxx_name location: location tags: { DebitCode: vDebitCode } kind: 'functionapp' identity: { type: 'SystemAssigned' } properties: { clientAffinityEnabled: false clientCertEnabled: false clientCertMode: 'Optional' containerSize: 1536 dailyMemoryTimeQuota: 0 enabled: true hostNamesDisabled: false hostNameSslStates: [ { name: '${sites_azfun_xxxxxxxxxxxxxxx_name}.azurewebsites.net' sslState: 'Disabled' hostType: 'Standard' } { name: '${sites_azfun_xxxxxxxxxxxxxxx_name}.scm.azurewebsites.net' sslState: 'Disabled' hostType: 'Repository' } ] httpsOnly: true hyperV: false isXenon: false redundancyMode: 'None' reserved: false scmSiteAlsoStopped: false serverFarmId: serverfarms_yyyyyyyyyPlan_name_resource.id } } resource sites_azfun_xxxxxxxxxxxxxxx_web_config 'Microsoft.Web/sites/config@2022-09-01' = { parent: sites_azfun_xxxxxxxxxxxxxxx_web name: 'web' properties: { numberOfWorkers: 1 defaultDocuments: [ 'Default.htm' 'Default.html' 'Default.asp' 'index.htm' 'index.html' 'iisstart.htm' 'default.aspx' 'index.php' ] netFrameworkVersion: 'v7.0' phpVersion: '5.6' requestTracingEnabled: false remoteDebuggingEnabled: false httpLoggingEnabled: false logsDirectorySizeLimit: 35 detailedErrorLoggingEnabled: false publishingUsername: '$${sites_azfun_xxxxxxxxxxxxxxx_name}' scmType: 'None' use32BitWorkerProcess: true webSocketsEnabled: false alwaysOn: bool(always_on) managedPipelineMode: 'Integrated' virtualApplications: [ { virtualPath: '/' physicalPath: 'site\\wwwroot' preloadEnabled: false } ] loadBalancing: 'LeastRequests' experiments: { rampUpRules: [] } autoHealEnabled: true cors: { allowedOrigins: [ 'https://functions.azure.com' 'https://functions-staging.azure.com' 'https://functions-next.azure.com' ] supportCredentials: false } localMySqlEnabled: false ipSecurityRestrictions: [ { ipAddress: '***' action: '***' priority: 1 name: '***' description: '***' } ] scmIpSecurityRestrictions: [ { ipAddress: '***' action: '***' priority: 1 name: '***' description: '***' } ] scmIpSecurityRestrictionsUseMain: false http20Enabled: false minTlsVersion: '1.2' ftpsState: 'Disabled' } } resource sites_azfun_xxxxxxxxxxxxxxx_web_azurewebsites_net 'Microsoft.Web/sites/hostNameBindings@2022-09-01' = { parent: sites_azfun_xxxxxxxxxxxxxxx_web name: '${sites_azfun_xxxxxxxxxxxxxxx_name}.azurewebsites.net' properties: { siteName: sites_azfun_xxxxxxxxxxxxxxx_name hostNameType: 'Verified' } } resource sites_azfun_xxxxxxxxxxxxxxx_staging 'Microsoft.Web/sites/slots@2022-09-01' = { name: stagingslot_azfun_xxxxxxxxxxxxxxx_name parent: sites_azfun_xxxxxxxxxxxxxxx_web location: location kind: 'functionapp' properties: { serverFarmId: serverfarms_yyyyyyyyyyPlan_name_resource.id } } resource sites_azfun_xxxxxxxxxxxxxxx_staging_scm 'Microsoft.Web/sites/slots/basicPublishingCredentialsPolicies@2022-09-01' = { parent: sites_azfun_xxxxxxxxxxxxxxx_staging name: 'scm' properties: { allow: true } } resource sites_azfun_xxxxxxxxxxxxxxx_staging_config 'Microsoft.Web/sites/slots/config@2022-09-01' = { parent: sites_azfun_xxxxxxxxxxxxxxx_staging name: 'web' properties: { numberOfWorkers: 1 defaultDocuments: [ 'Default.htm' 'Default.html' 'Default.asp' 'index.htm' 'index.html' 'iisstart.htm' 'default.aspx' 'index.php' ] netFrameworkVersion: 'v7.0' phpVersion: '5.6' requestTracingEnabled: false remoteDebuggingEnabled: false httpLoggingEnabled: false logsDirectorySizeLimit: 35 detailedErrorLoggingEnabled: false publishingUsername: '$${sites_azfun_xxxxxxxxxxxxxxx_name}__staging' scmType: 'None' use32BitWorkerProcess: true webSocketsEnabled: false alwaysOn: bool(always_on) managedPipelineMode: 'Integrated' virtualApplications: [ { virtualPath: '/' physicalPath: 'site\\wwwroot' preloadEnabled: false } ] loadBalancing: 'LeastRequests' experiments: { rampUpRules: [] } autoHealEnabled: true cors: { allowedOrigins: [ 'https://functions.azure.com' 'https://functions-staging.azure.com' 'https://functions-next.azure.com' ] supportCredentials: false } localMySqlEnabled: false ipSecurityRestrictions: [ { ipAddress: '***' action: '***' priority: 1 name: '***' description: '***' } ] scmIpSecurityRestrictions: [ { ipAddress: '***' action: '***' priority: 1 name: '***' description: '***' } ] scmIpSecurityRestrictionsUseMain: false http20Enabled: false minTlsVersion: '1.2' ftpsState: 'Disabled' } } resource sites_azfun_xxxxxxxxxxxxxxx_staging_azurewebsites_net 'Microsoft.Web/sites/slots/hostNameBindings@2022-09-01' = { parent: sites_azfun_xxxxxxxxxxxxxxx_staging name: '${sites_azfun_xxxxxxxxxxxxxxx_name}-staging.azurewebsites.net' properties: { siteName: 'azfun-xxxxxxxxxxxxxxx-lab(staging)' hostNameType: 'Verified' } }
Azure Pipeline YAML片段
stages: - stage: ${{ parameters.environmentName }} dependsOn: ${{ parameters.dependsOn }} variables: - ${{ parameters.varGroups }} jobs: - deployment: azure_resources displayName: "Creating or updating resources" environment: ${{ parameters.azureDevopsEnvironmentName }} variables: - name: templateFile value: 'main.bicep' - name: parametersFile value: 'main.parameters.json' - ${{ parameters.varGroups }} condition: succeeded() pool: vmImage: windows-latest strategy: runOnce: deploy: steps: - task: replacetokens@5 name: tokens_in_parameterfile displayName: 'Replacing tokens in files' inputs: targetFiles: | ../BuildPipeline/BICEP/$(parametersFile) encoding: 'auto' tokenPattern: 'octopus' writeBOM: true actionOnMissing: 'warn' keepToken: false actionOnNoFiles: 'continue' enableTransforms: false enableRecursion: false useLegacyPattern: false enableTelemetry: false - task: AzureResourceManagerTemplateDeployment@3 name: 'deploy' displayName: 'Deploy resources to resource group' inputs: deploymentName: 'deploy' deploymentScope: 'Resource Group' azureResourceManagerConnection: $(azuredevops_serviceendpoint_azurerm) action: 'Create Or Update Resource Group' resourceGroupName: ${{ parameters.resourceGroupName }}-${{ lower(parameters.environmentName) }} location: ${{ parameters.location }} templateLocation: 'Linked artifact' csmFile: '../BuildPipeline/BICEP/$(templateFile)' csmParametersFile: '../BuildPipeline/BICEP/$(parametersFile)' deploymentMode: 'Incremental' - ${{ if eq(parameters.deploy_xxxxxxxxxxxxxxx, true) }}: - task: AzureFunctionApp@2 name: 'xxxxxxxxxxxxxxx_content' displayName: 'Deploy content for xxxxxxxxxxxxxxx' inputs: ${{ if eq(lower(parameters.environmentName), 'xxxx') }}: appName: azfun-xxxxxxxxxxxxxxx ${{ else }}: appName: azfun-xxxxxxxxxxxxxxx-${{ lower(parameters.environmentName) }} connectedServiceNameARM: '$(azuredevops_serviceendpoint_azurerm)' appType: 'functionApp' package: '../BuildPipeline/xxxxxxxxxxxxxxx/**/*.zip' deployToSlotOrASE: true resourceGroupName: ${{ parameters.resourceGroupName }}-${{ lower(parameters.environmentName) }} slotName: 'staging' deploymentMethod: 'auto' - task: AzureAppServiceManage@0 displayName: 'Swap content for xxxxxxxxxxxxxxx' inputs: azureSubscription: '$(azuredevops_serviceendpoint_azurerm)' ${{ if eq(lower(parameters.environmentName), 'xxxx') }}: WebAppName: azfun-xxxxxxxxxxxxxxx ${{ else }}: WebAppName: azfun-xxxxxxxxxxxxxxx-${{ lower(parameters.environmentName) }} ResourceGroupName: ${{ parameters.resourceGroupName }}-${{ lower(parameters.environmentName) }} SourceSlot: staging SwapWithProduction: true
问题分析与修复方案
1. scmType配置为None导致部署功能禁用
生产槽和staging槽的web配置中,scmType均设置为None,这会禁用所有SCM(源代码管理)相关的部署功能,包括槽部署的内容保留机制。当BICEP重新部署配置时,会直接清空槽内已有的代码内容。
- 修复:移除
scmType配置项,让Azure根据实际部署方式自动维护该值;或改为VSTSRM(适配Azure DevOps部署场景)。
2. BICEP部署覆盖槽的全量配置
使用Incremental模式部署时,若BICEP中定义了槽web配置的全部属性,Azure会强制将现有配置与模板对齐,重置与代码内容关联的设置。
- 修复:
- 仅在BICEP中定义必要的配置项(如
.NET版本、alwaysOn、CORS规则等),删除publishingUsername、scmType等与部署相关的属性。 - 或通过
lifecycle.ignoreChanges指令,让BICEP忽略对内容相关属性的更新:resource sites_azfun_xxxxxxxxxxxxxxx_staging_config 'Microsoft.Web/sites/slots/config@2022-09-01' = { parent: sites_azfun_xxxxxxxxxxxxxxx_staging name: 'web' properties: { netFrameworkVersion: 'v7.0' alwaysOn: bool(always_on) cors: { allowedOrigins: [ 'https://functions.azure.com' 'https://functions-staging.azure.com' 'https://functions-next.azure.com' ] supportCredentials: false } // 其他必要配置... } lifecycle: { ignoreChanges: [ 'properties.scmType' 'properties.publishingUsername' 'properties.virtualApplications' ] } }
- 仅在BICEP中定义必要的配置项(如
3. Staging槽HostNameBinding配置错误
staging槽的HostNameBinding中,siteName硬编码为azfun-xxxxxxxxxxxxxxx-lab(staging),与实际槽名称不匹配,可能导致槽的关联异常,间接影响内容保留。
- 修复:使用变量引用正确的槽名称:
resource sites_azfun_xxxxxxxxxxxxxxx_staging_azurewebsites_net 'Microsoft.Web/sites/slots/hostNameBindings@2022-09-01' = { parent: sites_azfun_xxxxxxxxxxxxxxx_staging name: '${sites_azfun_xxxxxxxxxxxxxxx_name}-staging.azurewebsites.net' properties: { siteName: '${sites_azfun_xxxxxxxxxxxxxxx_name}/${stagingslot_azfun_xxxxxxxxxxxxxxx_name}' hostNameType: 'Verified' } }
4. Pipeline部署顺序的潜在风险
当前Pipeline先执行BICEP部署,再部署代码到staging槽。若后续仅运行BICEP部署(如更新其他资源),会直接清空staging槽已有的代码内容。
- 修复:
- 拆分BICEP部署:将Function App基础资源部署与配置更新分离,仅在必要时更新槽配置。
- 添加检查步骤:在BICEP部署完成后,判断staging槽内容是否为空,若为空则重新触发内容部署。
内容的提问来源于stack exchange,提问作者Per
相关产品推荐
相关产品推荐

