How to Deploy Azure Function With Azure DevOp

This article will explain how to automate azure function application deployment with azure DevOps using ARM templates
This article will explain how to automate azure function application deployment with azure DevOps using ARM templates

Hey, What's up, Welcome back to another very exiting tutorial by Ciemasen. Today we are going to be take a look at How to deploy azure function app using azure DevOps. Hope you enjoyed the previous article on How to create Azure Function Application. If you missed the previous article, we suggest you to have a look on that first.

Overview

In this article we will explain how to deploy azure function app using azure DevOps. we will be configure azure CICD to automate deployment using azure DevOps.

Azure Function app ARM template

As mentioned earlier we will be deploying azure function app using azure devops pipelines. So before deploying we need to create the function app in azure first. In order to create new azure function we can log in to the azure portal and create web app as explained in our previous article on How to create Azure Function Application. Since we already explained how to create function in azure portal, in this article we will be using azure ARM template to automate app service creation.

Lets create following azure resource as part of the ARM template

  • Azure app service plan
  • Azure function

Create azure app service plan in ARM template

In order to deploy azure web application first we need to have a app service plan created. So we are using Microsoft.Web/serverfarms template to add app service plan resource.

 
{
  "type": "Microsoft.Web/serverfarms",
  "apiVersion": "2020-06-01",
  "name": "[variables('appServicePlanName')]",
  "location": "[parameters('location')]",
  "sku": {
	"name": "[parameters('sku')]"
  }
}

Create azure function in ARM template

Now we have the app service plan created and next we are using Microsoft.Web/sites template to add website resource.

{
  "apiVersion": "2019-08-01",
  "type": "Microsoft.Web/sites",
  "name": "[variables('functionAppName')]",
  "location": "[parameters('location')]",
  "kind": "functionapp",
  "dependsOn": [
	"[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]"
  ],
  "properties": {
	"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]",
	"siteConfig": {
	  "appSettings": [
		{
		  "name": "AzureWebJobsStorage",
		  "value": "[parameters('storageAccountConnectionString')]"
		},
		{
		  "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
		  "value": "[parameters('storageAccountConnectionString')]"
		},
		{
		  "name": "WEBSITE_CONTENTSHARE",
		  "value": "[toLower(variables('functionAppName'))]"
		},
		{
		  "name": "FUNCTIONS_EXTENSION_VERSION",
		  "value": "~4"
		},
		{
		  "name": "FUNCTIONS_WORKER_RUNTIME",
		  "value": "[variables('functionWorkerRuntime')]"
		}
	  ]
	}
  }
}

here is the complete ARM template we are using for this article

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "appName": {
      "type": "string",
      "defaultValue": "[concat('fnapp', uniqueString(resourceGroup().id))]",
      "metadata": {
        "description": "The name of the function app that you wish to create."
      }
    },
    "storageAccountConnectionString": {
      "type": "string",
      "metadata": {
        "description": "The name of the SQL connection string"
      }
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "Location for all resources."
      }
    }
  },
  "variables": {
    "functionAppName": "[parameters('appName')]",
    "hostingPlanName": "[parameters('appName')]",
    "functionWorkerRuntime": "dotnet"
  },
  "resources": [
    {
      "type": "Microsoft.Web/serverfarms",
      "apiVersion": "2019-08-01",
      "name": "[variables('hostingPlanName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "Y1",
        "tier": "Dynamic"
      },
      "properties": {
        "name": "[variables('hostingPlanName')]",
        "computeMode": "Dynamic"
      }
    },
    {
      "apiVersion": "2019-08-01",
      "type": "Microsoft.Web/sites",
      "name": "[variables('functionAppName')]",
      "location": "[parameters('location')]",
      "identity": {
        "type": "SystemAssigned"
      },
      "kind": "functionapp",
      "dependsOn": [
        "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]"
      ],
      "properties": {
        "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]",
        "siteConfig": {
          "appSettings": [
            {
              "name": "AzureWebJobsStorage",
              "value": "[parameters('storageAccountConnectionString')]"
            },
            {
              "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
              "value": "[parameters('storageAccountConnectionString')]"
            },
            {
              "name": "WEBSITE_CONTENTSHARE",
              "value": "[toLower(variables('functionAppName'))]"
            },
            {
              "name": "FUNCTIONS_EXTENSION_VERSION",
              "value": "~4"
            },
            {
              "name": "WEBSITE_NODE_DEFAULT_VERSION",
              "value": "~16"
            },
            {
              "name": "FUNCTIONS_WORKER_RUNTIME",
              "value": "[variables('functionWorkerRuntime')]"
            }
          ]
        }
      }
    }
  ]
}

You need to store the ARM template as part of the repository. We will be creating new folder called Templates and store the ARM template inside that.

Upload ARM template as azure devops build artifact

Now we have the completed ARM template with our repo and we need to upload it to azure devops build artifact in order to access it in release pipeline. Let's add following section to azure-pipelines.yml.


- task: PublishBuildArtifacts@1
  displayName: 'Publish ARM: drop'
  inputs:
    PathtoPublish: $(System.DefaultWorkingDirectory)/Templates
    ArtifactName: drop

ARM template deployment

  1. Add a task in agent jobs section
  2. Select ARM template deployment task
  3. Now you can select the service connection as the Azure Resource Manager connection
  4. Select subscription, resource group and location accordingly
  5. Select action as Create or update resource group
  6. Keep Template location as Linked artifact
  7. Select the path to ARM template from build artifacts
  8. Set respective parameters in Override template parameters section. These parameters we defined in ARM template already. Here we setting the values for those parameters.

Function app deployment

  1. Add a task in agent jobs section
  2. Select Azure Functions task
  3. Select the subscription which we selected for ARM template deployment task as well.
  4. Provide a name for function which we set in ARM template deployment task as well. This is the name we used to create the function app in ARM template.
  5. Select the deployment package from build artifacts.

Save the release pipeline and now we are ready for a deployment. How to configure Azure DevOps CICD article explained how to configure automatic deployment trigger. You can deploy the stage you created and that will create function app and deploy the function app code in to that automatically.

Now we have the function app deployed into azure.

Hope you enjoy the tutorial and see you soon in another very exiting tutorial