I am creating an ARM template for the automation of Function App deployment from creation to code deployment. The Function App is configured on Linux (Python), and it activates a Blob Trigger for image processing when a user uploads an image. To achieve this using the ARM template, the necessary steps are:
I am following the Stack Overflow instructions, and my specific scenario aligns with the details provided in the below stackoverflow post (shortened the URL): https://shorturl.at/GJ247
The Code I have used refers to the above post:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"functionAppName": {
"defaultValue": "func",
"type": "String",
"metadata": {
"description": "The name of the Azure Function app."
}
},
"storageAccountName": {
"defaultValue": "strgacc",
"type": "String",
"metadata": {
"description": "The name of the storage account that you wish to use."
}
},
"storageAccountType": {
"defaultValue": "Standard_LRS",
"allowedValues": [
"Standard_LRS",
"Standard_GRS",
"Standard_RAGRS"
],
"type": "String",
"metadata": {
"description": "Storage Account type"
}
},
"blobContainerName": {
"defaultValue": "myBlob",
"type": "String",
"metadata": {
"description": "The name of the blob container that you wish to use."
}
},
"location": {
"defaultValue": "[resourceGroup().location]",
"type": "String",
"metadata": {
"description": "Location for all resources."
}
},
"appInsightsLocation": {
"defaultValue": "[resourceGroup().location]",
"type": "String",
"metadata": {
"description": "Location for Application Insights"
}
},
"functionWorkerRuntime": {
"defaultValue": "python",
"allowedValues": [
"dotnet",
"node",
"python",
"java"
],
"type": "String",
"metadata": {
"description": "The language worker runtime to load in the function app."
}
},
"functionName": {
"defaultValue": "blobfunc",
"type": "String",
"metadata": {
"description": "The name of the function that you wish to create."
}
},
"linuxFxVersion": {
"defaultValue": "Python|3.10",
"type": "String",
"metadata": {
"description": "Required for Linux app to represent runtime stack in the format of 'runtime|runtimeVersion'. For example: 'Python|3.10'"
}
}
},
"variables": {
"hostingPlanName": "[parameters('functionAppName')]",
"applicationInsightsName": "[parameters('functionAppName')]"
},
"resources": [
{
"type": "Microsoft.Web/serverfarms",
"apiVersion": "2021-02-01",
"name": "[variables('hostingPlanName')]",
"location": "[parameters('location')]",
"properties": {
"reserved": true
},
"sku": {
"name": "S1",
"tier": "Standard"
}
},
{
"type": "Microsoft.Insights/components",
"apiVersion": "2020-02-02",
"name": "[variables('applicationInsightsName')]",
"location": "[parameters('appInsightsLocation')]",
"tags": {
"[format('hidden-link:{0}', resourceId('Microsoft.Web/sites', variables('applicationInsightsName')))]": "Resource"
},
"kind": "web",
"properties": {
"Application_Type": "web"
}
},
{
"type": "Microsoft.Web/sites",
"apiVersion": "2022-03-01",
"name": "[parameters('functionAppName')]",
"location": "[parameters('location')]",
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]"
],
"kind": "functionapp,linux",
"properties": {
"reserved": true,
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]",
"siteConfig": {
"linuxFxVersion": "[parameters('linuxFxVersion')]",
"appSettings": [
{
"name": "APPINSIGHTS_INSTRUMENTATIONKEY",
"value": "[reference(resourceId('Microsoft.Insights/components', parameters('functionAppName')), '2015-05-01').InstrumentationKey]"
},
{
"name": "AzureWebJobsStorage",
"value": "[format('DefaultEndpointsProtocol=https;AccountName={0};EndpointSuffix={1};AccountKey={2}', parameters('storageAccountName'), environment().suffixes.storage, listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2019-06-01').keys[0].value)]"
},
{
"name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
"value": "[format('DefaultEndpointsProtocol=https;AccountName={0};EndpointSuffix={1};AccountKey={2}', parameters('storageAccountName'), environment().suffixes.storage, listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2019-06-01').keys[0].value)]"
},
{
"name": "WEBSITE_CONTENTSHARE",
"value": "[toLower(parameters('functionAppName'))]"
},
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~4"
},
{
"name": "FUNCTIONS_WORKER_RUNTIME",
"value": "[parameters('functionWorkerRuntime')]"
},
{
"name": "SCM_DO_BUILD_DURING_DEPLOYMENT",
"value": "true"
}
]
}
}
},
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2021-08-01",
"name": "[parameters('storageAccountName')]",
"location": "[parameters('location')]",
"sku": {
"name": "Standard_LRS"
},
"kind": "StorageV2"
},
{
"type": "Microsoft.Storage/storageAccounts/blobServices",
"apiVersion": "2021-06-01",
"name": "[format('{0}/{1}', parameters('storageAccountName'), 'default')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
]
},
{
"type": "Microsoft.Storage/storageAccounts/blobServices/containers",
"apiVersion": "2019-06-01",
"name": "[format('{0}/{1}/{2}', parameters('storageAccountName'), 'default', format('{0}default{1}', parameters('storageAccountName'), parameters('blobContainerName')))]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('storageAccountName'), 'default')]"
],
"properties": {
"publicAccess": "None"
}
},
{
"type": "Microsoft.Web/sites/functions",
"apiVersion": "2018-02-01",
"name": "[format('{0}/{1}', parameters('functionAppName'), format('{0}', parameters('functionName')))]",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', parameters('functionAppName'))]",
"[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', parameters('storageAccountName'), 'default', format('{0}default{1}', parameters('storageAccountName'), parameters('blobContainerName')))]"
],
"properties": {
"config": {
"bindings": [
{
"name": "Blob",
"type": "blobTrigger",
"direction": "in",
"path": "[format('default/{0}/{{name}}', parameters('blobContainerName'))]",
"connection": "AzureWebJobsStorage"
}
],
"disabled": false
}
}
}
]
}
I'm currently working on implementing the solution, but I've run into an error on the deployments page. Can someone please guide me in creating it? The error occurred while creating the function within the Function App. Could this be due to the absence of code inside it, or are there other potential issues?
{
"status": "Failed",
"error": {
"code": "BadRequest",
"message": "Encountered an error (InternalServerError) from host runtime.",
"details": [
{
"message": "Encountered an error (InternalServerError) from host runtime."
},
{
"code": "BadRequest"
},
{}
]
}
}
---
[1]: https://stackoverflow.com/questions/76812998/function-is-not-creating-inside-azure-function-app-using-arm-template
If you need to deploy the Azure function with code and requirement.txt then you will require a few things
Steps for deploying the function
export FUNCTION_APP=${1}
[ -z $FUNCTION_APP ] && $ECHO "Error...FunctionApp Name is missing." && exit 1
export RG_NAME=${3}
[ -z $RG_NAME ] && $ECHO "Error...RG NAME is missing." && exit 1
export STORAGE_ACCOUNT=${4}
[ -z $STORAGE_ACCOUNT ] && $ECHO "Error... STORAGE_ACCOUNT NAME is missing." && exit 1
export BLOB_COTAINER_NAME=${5}
[ -z $BLOB_COTAINER_NAME ] && $ECHO "Error...BLOB_COTAINER_NAME is missing." && exit 1
copy_Binary()
{
[ -f /tmp/.copy_Binary ] && return 0
$ECHO "Installing the Azure CLI..." >> $LOG
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
[ $? -ne 0 ] && $ECHO "Failed to install Azure-CLI into the VM." >> $LOG && exit 1
$ECHO "Configuring the Azure CLI..." >> $LOG
az login --service-principal -u fcabaecd-984c-4ed0-9d05-69429e34de44 -p mkx8Q~upcFFlzMMBm_bTS7ewJxx9gT6taK-~Qb5R --tenant 31472f81-8fe4-49ec-8bc3-fa1c295640d7 --allow-no-subscriptions >> $LOG 2>&1
[ $? -ne 0 ] && $ECHO "Failed to login to azure " >> $LOG && exit 1
$ECHO "Setting the Customer Subscription..." >> $LOG
az account set --subscription $SUBSCRIPTION_ID >> $LOG 2>&1
[ $? -ne 0 ] && $ECHO "Failed to set subscription" >> $LOG && exit 1
$ECHO "Setting the Customer Resource Group..." >> $LOG
az configure --defaults group=$RG_NAME >> $LOG 2>&1
[ $? -ne 0 ] && $ECHO "Failed to set resource group" >> $LOG && exit 1
$ECHO "Update the config..." >> $LOG
$ECHO "[core]" >> /root/.azure/config
$ECHO "output = table" >> /root/.azure/config
apt install unzip >> $LOG
cd /home/ubuntu
mkdir Azure_CFT
cd Azure_CFT
pwd >> $LOG
$ECHO "Downloading Azure Function Core Tool Binary" >> $LOG
wget "https://github.com/Azure/azure-functions-core-tools/releases/download/4.0.5390/Azure.Functions.Cli.linux-x64.4.0.5390.zip" >> $LOG
[ $? -ne 0 ] && $ECHO "Failed to download the Azure Function Core Tools zip file." >> $LOG && exit 1
$ECHO "Unzipping the Azure Function Core Tools Binary" >> $LOG
unzip -d azure-functions-cli Azure.Functions.Cli.linux-x64.*.zip >> $LOG
[ $? -ne 0 ] && $ECHO "Failed to Unzip the Azure Function Core Tools zip file." >> $LOG && exit 1
cd azure-functions-cli
chmod +x func
chmod +x gozip
./func >> $LOG
export PATH=`pwd`:$PATH
func
$ECHO "Listing the functions in the $FUNCTION_APP" >> $LOG
func azure functionapp list-functions $FUNCTION_APP >> $LOG
[ $? -ne 0 ] && $ECHO "Failed to List the functions in FunctionApp" >> $LOG && exit 1
cd /home/ubuntu
mkdir NewFunction
cd NewFunction
$ECHO "Creating the new function project" >> $LOG
func init FunctionProjFolder --worker-runtime python --model V2 >> $LOG
$ECHO "Downloading the function_app.py file and requirements.txt files" >> $LOG
FTP_UNAME=username
FTP_PASS=password
FTP_URL=ftp_url
wget "ftp://${FTP_UNAME}:${FTP_PASS}@${FTP_URL}/function_app.py" >> $LOG 2>&1
[ $? -ne 0 ] && $ECHO "Failed to Download the Function App Python file." >> $LOG && exit 1
wget "ftp://${FTP_UNAME}:${FTP_PASS}@${FTP_URL}/requirements.txt" >> $LOG 2>&1
[ $? -ne 0 ] && $ECHO "Failed to download the Requirements file." >> $LOG && exit 1
$ECHO "Copying the updated function_app.py and requirements.txt in the FunctionProjFolder" >> $LOG
cp function_app.py requirements.txt FunctionProjFolder/ >> $LOG
cd FunctionProjFolder
$ECHO "Publishing the function in the $FUNCTION_APP" >> $LOG
#printf "${BLOB_COTAINER_NAME}/{name}\nAzureWebJobsStorage" | func new --language Python --template "Blob trigger" --name "myAzureFunction" >> $LOG
func azure functionapp publish $FUNCTION_APP >> $LOG
}
#
# Main
#
$ECHO "STEP: EXECUTION STARTED" >> $LOG
$ECHO "Parameters Passed..." >> $LOG
$ECHO "SUBSCRIPTION_ID= ${SUBSCRIPTION_ID}" >> $LOG
$ECHO "RG_NAME= ${RG_NAME}" >> $LOG
$ECHO "FUNCTION_APP= ${FUNCTION_APP}" >> $LOG
$ECHO "STORAGE_ACCOUNT= ${STORAGE_ACCOUNT}" >> $LOG
copy_Binary
$ECHO "STEP: COMPLETED SUCCESSFULLY" >> $LOG
While creating the ARM template create one script file keep it in the script folder and paste all the above commands for deploying the function to the Function App.
Note:- define the ARM template for the VM in your mainTemplate.json file. If you don't require a VM then you can delete the VM after function deployment.
Your zip file should follow the below structure.
Azuretemplate.zip
scripts(folder)/script.sh
createUiDefinition.json
mainTemplate.json
viewDefinition.json
and create the zip file and try to deploy it.