Azure Functions are an integral part of serverless applications, and they are required to build a robust integration platform in the cloud. As discussed in previous chapters, we can code small executables or log running durable functions in Azure Functions and use them within Logic Apps, API Management, or Microsoft Flow using webhooks or HTTP bindings.
Azure Functions also supports many other input and output binding types to connect with multiple platforms. We can also create a custom binding, which can be used to build a serverless integration platform in Azure.
There are various options available to perform continuous integration and deployment for functions, such as running them from a ZIP file, using PowerShell, and setting up a DevOps pipeline directly from the Azure portal. In this section, we will cover automated deployment for Azure Functions using an ARM definition with a compiled assembly through the DevOps pipeline (https://docs.microsoft.com/en-us/azure/azure-functions/deployment-zip-push).
To understand the process, follow these steps:
- Create an Azure Functions project along with associated class libraries to store models and methods with the related dependency injection.
- Define an ARM template for the function app container to hold function app resource definitions such as the Storage account, application keys, application insights, and the pricing plan:
- In the function app ARM template definition, add the required Functions dependency resources, such as the Storage account, Application Insight account, and the hosting plan (server farms). Here is the definition of Application Insights for the function app:
{
"apiVersion": "2015-05-01",
"name": "[parameters('appInsightsName')]",
"type": "microsoft.insights/components",
"location": "[parameters('appInsightsLocation')]",
"tags": {
"[concat('hidden-link:', resourceGroup().id, '/providers/Microsoft.Web/sites/', parameters('appInsightsName'))]": "Resource"
},
"properties": {
"ApplicationId": "[parameters('appInsightsName')]"
}
}
- The Storage account is required by the functions app to store the logs' and functions' state information for durable functions. It is good practice to include a Storage account with a proper naming convention within the function's ARM definition template:
{
"type": "Microsoft.Storage/storageAccounts",
"name": "[variables('storageAccountName')]",
"apiVersion": "2016-01-01",
"location": "[resourceGroup().location]",
"kind": "Storage",
"sku": {
"name": "Standard_LRS"
},
"dependsOn": []
}
- The last dependency resource for the function app is the compute model (App plan for Function App), as this function app uses the consumption plan to run its Functions. We have defined the ARM resource for the app plan:
{
"type": "Microsoft.Web/serverfarms",
"apiVersion": "2016-03-01",
"name": "[variables('hostingPlanName')]",
"location": "[resourceGroup().location]",
"properties": {
"name": "[variables('hostingPlanName')]",
"computeMode": "Dynamic",
"sku": "Dynamic"
}
}
- Now, as we have all the required dependency resources listed for the function app, the next step is to add the ARM definition for the function app with the required dependencies for storage, Application Insights, and the hosting plan:
{
"apiVersion": "2016-08-01",
"type": "Microsoft.Web/sites",
"name": "[variables('functionAppName')]",
"location": "[resourceGroup().location]",
"kind": "functionapp",
"scale": null,
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]",
"[resourceId('microsoft.insights/components/', parameters('appInsightsName'))]"
],
"properties": {
"name": "[variables('functionAppName')]",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]",
"clientAffinityEnabled": false,
"siteConfig": {
"appSettings": [
{
"name": "AzureWebJobsDashboard",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountid'),'2015-05-01-preview').key1)]"
},
{
"name": "AzureWebJobsStorage",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountid'),'2015-05-01-preview').key1)]"
},
{
"name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountid'),'2015-05-01-preview').key1)]"
},
{
"name": "WEBSITE_CONTENTSHARE",
"value": "[toLower(variables('functionAppName'))]"
},
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~1"
},
{
"name": "WEBSITE_NODE_DEFAULT_VERSION",
"value": "6.5.0"
},
{
"name": "APPINSIGHTS_INSTRUMENTATIONKEY",
"value": "[reference(resourceId('microsoft.insights/components/', parameters('appInsightsName')), '2015-05-01').InstrumentationKey]"
}
]
}
}
- The basic parameter list for our function app is as follows:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"environment": {
"value": "dev"
},
"appInsightsName": {
"value": "devfuncappinsights01"
},
"appName": {
"value": "func-integration-dev"
},
"functionStorageName": {
"value": "devsabausefun01"
},
"functionApplicationPlanName": {
"value": "fc-ause-integration-dev"
},
"appInsightsLocation": {
"value": "westus2"
}
}
}