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

使用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'
          ]
        }
      }
      

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 23:09:51