Reputation: 1199
I've got an ARM template (included below) to deploy an Azure Function App. I deploy it with:
az group deployment create --resource-group my-group --template-file my-function-app.json
This works and I can then deploy my functions successfully using the VS Code plugin or Azure Functions Core Tools.
However, if I then re-deploy the ARM template (for example to update an application setting) then I lose my functions and need to re-deploy them again. Is this expected behaviour? It's not what I observe when deploying e.g. a Web App via an ARM template. Is there something specific I can do when deploying an ARM template for a Function App to preserve my deployed functions?
my-function-app.json:
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
...
},
"variables": {
...
},
"resources": [
{
"apiVersion": "2015-08-01",
"type": "Microsoft.Web/sites",
"name": "[variables('collectorFunctionAppName')]",
"location": "[parameters('location')]",
"kind": "functionapp",
"properties": {
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]",
"siteConfig": {
"appSettings": [
{
...
}
]
}
}
}
],
"outputs": {}
}
Upvotes: 17
Views: 3361
Reputation: 2974
Adding more to the right answer linking "WEBSITE_RUN_FROM_PACKAGE" setting with this issue, that helped me to fix my issue, in case somebody is looking further to plug in the gaps:
I run bicep as IaC that creates function app, storage, other resources etc along with APIM, API. No function code deployment yet. Had used WEBSITE_RUN_FROM_PACKAGE='1'
in the function app bicep script.
In the next step, I bundle the code and use function tools func azure functionapp publish $FUNCTION_APP_NAME --worker-runtime=python --build-native-deps
to do a remote deployment. Good so far; can see the function in the function app deployed. This command also updates the WEBSITE_RUN_FROM_PACKAGE
setting to the actual package URL from storage such as 'https://contentparserstgfnsa.blob.core.windows.net/function-releases/20250...'.
Now, add the function operations on APIM API and can now have the function running via APIM. All good
Now run the step 1 again, and you would loose the function ! The reason being you are overwriting the right WEBSTITE_RUN_FROM_PACKAGE
value with '1' again, but this needs to be now using not '1' but the actual & latest package URL for subsequent function app deployments
One solution is to try to lookup for the existing function app and its this environment setting in the bicep scripts and use it in the environment setting, something like this:
// Check if the Function App exists
var functionAppExists = contains(listAccountResources(resourceId('Microsoft.Resources/subscriptions/resourceGroups', subscription().subscriptionId, resourceGroup().name), 'Microsoft.Web/sites').value, { name: functionAppName })
// Get existing WEBSITE_RUN_FROM_PACKAGE or use default of 1
var websiteRunFromPackage = functionAppExists ? list('${resourceId('Microsoft.Web/sites', functionAppName)}/config/appsettings', '2024-04-01').properties.WEBSITE_RUN_FROM_PACKAGE ?? '1' : '1'
Probably being new to bicep/Azure I ran into API versions issue, and for now had a workaround in my bash scripts, to lookup for this value using Azure CLI and feed it into bicep deployment CLI call.
AI generated code
APPLICATION="myapp"
FUNCTION_APP_NAME="myappfuncapp"
FUNCTION_APP_WEBSITE_RUN_FROM_PKG_DEFAULT="1"
# Check if the Function App exists
if az webapp show --name "$FUNCTION_APP_NAME" --resource-group "$RESOURCE_GROUP_NAME" > /dev/null 2>&1; then
# Function App exists, try to get the app setting
APP_SETTING=$(az webapp config appsettings list --name "$FUNCTION_APP_NAME" --resource-group "$RESOURCE_GROUP_NAME" --query "[?name=='WEBSITE_RUN_FROM_PACKAGE'].value | [0]" -o tsv)
# Check if the app setting exists
if [[ -z "$APP_SETTING" ]]; then
# App setting is empty or does not exist, use default value
APP_SETTING="$FUNCTION_APP_WEBSITE_RUN_FROM_PKG_DEFAULT"
echo "Function App exists, but WEBSITE_RUN_FROM_PACKAGE setting is missing or empty. Using default value: $FUNCTION_APP_WEBSITE_RUN_FROM_PKG_DEFAULT"
else
echo "Function App exists, WEBSITE_RUN_FROM_PACKAGE setting found: $APP_SETTING"
fi
else
# Function App does not exist, use default value
APP_SETTING="$FUNCTION_APP_WEBSITE_RUN_FROM_PKG_DEFAULT"
echo "Function App does not exist. Using default value: $FUNCTION_APP_WEBSITE_RUN_FROM_PKG_DEFAULT"
fi
# Now, APP_SETTING contains the desired value (either from the Function App or the default)
echo "Using WEBSITE_RUN_FROM_PACKAGE value: $APP_SETTING"
az deployment group create \
--resource-group $RESOURCE_GROUP_NAME \
--template-file main.bicep \
--query "properties.outputs" \
--output json \
--parameters params.bicepparam \
key1=$VALUE1 \
functionAppPackageURL=$APP_SETTING
Accept and use this parameter functionAppPackageURL value now in setting the WEBSITE_RUN_FROM_PACKAGE
in the bicep script.
Upvotes: 0
Reputation: 841
Are you deploying your function as a package? If so, make sure you set this setting in your template, since it will be removed when you redeploy otherwise:
{ "name": "WEBSITE_RUN_FROM_PACKAGE", "value": "1" }
Upvotes: 26
Reputation: 1716
Yes that should be the expected behavior.
ARM Template is a declarative deployment meaning anytime you deploy it will overwrite anything you have with new template information. The template should always include everything you need.
Upvotes: -1
Reputation: 153
You could try "--mode incremental" parameter although that should be the default when it is not provided.
Upvotes: 0