I am making a deploy using BICEP and it has been working fine. Though now I need to make use of deployment slots as deployment disturbs our users.
I read the documentation and got it working, at least what I thought. I make a deploy to the staging slot, making a swap and everything works. First time I expect the staging slot to be empty after the deploy but not as I deploy another time. As I do a swap I expect the old production code to be the staging code but it is not. Staging is empty, which is bad as I can’t switch back in case something went wrong with the new code.
After lots of reruns of my deploy I have noticed that the functionapp is emptied of its content as the BICEP is run, not what I expect from what I have read should happen with my configuration.
Is there a misconfiguration somewhere I just can’t see? Something goes wrong BEFORE deploying the content to the Azure Function.
My BICEP (or part of it)
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'
}
}
My azure pipeline, in yml (or part of it)
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
2
Answers
As Kevin Lu pointed out, I had to add the appsettings WEBSITE_RUN_FROM_PACKAGE: '1'.
We can refer to this doc: Run your functions from a package file in Azure
When you deploy function app code using AzureFunctionApp@2, this app setting will automatically add into function app.
When redeploying your bicep file, this setting is removed and the function app host does not know where to find the code.
In this case, the functionapp could show as empty of its content
We can add the appsetting: WEBSITE_RUN_FROM_PACKAGE: ‘1’ to the bicep file to solve the issue.