Posted in:

In this post we'll explore how we can use the Azure CLI to deploy an Azure Function App running on the "consumption plan" along with all the associated resources such as a Storage Account and an Application Insights instance.

I'll be using PowerShell as my command prompt, but most of these commands translate very straightforwardly to a Bash shell if you prefer.

Step 1 - Create a Resource Group

As always with the Azure CLI, once we've logged in (with az login) and chosen the correct subscription (with az account set -s "MySub"), we should create a resource group to hold the various resources we're going to create.

$resourceGroup = "AzureFunctionsDemo"
$location = "westeurope"
az group create -n $resourceGroup -l $location

Step 2 - Create a Storage Account

A number of features of Azure Functions work with a Storage Account, so it's a good idea to create a dedicated Storage Account to partner with a function app. Storage Accounts do require unique names as it will form part of their domain name, so I'm using a random number to help pick a suitable name, before creating the storage account using the standard LRS pricing tier.

$rand = Get-Random -Minimum 10000 -Maximum 99999
$storageAccountName = "funcsdemo$rand"

az storage account create `
  -n $storageAccountName `
  -l $location `
  -g $resourceGroup `
  --sku Standard_LRS

Step 3 - Create an Application Insights instance

Azure Functions offers excellent monitoring via Application Insights, so it makes sense to turn this on for all deployments. Unfortunately, the Azure CLI currently does not support creating Application Insights directly, but we can create one with the az resource create command.

$appInsightsName = "funcsmsi$rand"
az resource create `
  -g $resourceGroup -n $appInsightsName `
  --resource-type "Microsoft.Insights/components" `
  --properties '{\"Application_Type\":\"web\"}'

Step 4 - Create a Function App

Normally at this point we'd need to create an App Service Plan, but when we're using the consumption pricing tier there's a shortcut we can use, which is to set the --consumption-plan-location parameter when we create the Function App, and we'll automatically get a consumption App Service Plan created for us (with a name like "WestEuropePlan") in our resource group.

We're going to be using V2 of the Azure Functions Runtime, and so I'll specify that I'm using the dotnet runtime, but you can also set this to node or java.

We're also pointing it at the Application Insights instance we just created with the --app-insights switch.

$functionAppName = "funcs-demo-$rand"

az functionapp create `
  -n $functionAppName `
  --storage-account $storageAccountName `
  --consumption-plan-location $location `
  --app-insights $appInsightsName `
  --runtime dotnet `
  -g $resourceGroup

Step 5 - Deploy our Function App Code

Obviously I'm assuming that we have some functions to deploy to the Function App. If we've created a C# Azure Functions project, we can package it up for release by running a dotnet publish, zipping up the resulting folder, and using az functionapp deployment source config-zip to deploy it.

# publish the code
dotnet publish -c Release
$publishFolder = "FunctionsDemo/bin/Release/netcoreapp2.1/publish"

# create the zip
$publishZip = "publish.zip"
if(Test-path $publishZip) {Remove-item $publishZip}
Add-Type -assembly "system.io.compression.filesystem"
[io.compression.zipfile]::CreateFromDirectory($publishFolder, $publishZip)

# deploy the zipped package
az functionapp deployment source config-zip `
 -g $resourceGroup -n $functionAppName --src $publishZip

Step 6 - Configure Application Settings

Optionally at this point, we may wish to configure some application settings, such as connection strings to other services. These can be configured with the az functionapp config appsettings set command (although watch out for some nasty escaping gotchas if your setting values contain certain characters).

az functionapp config appsettings set -n $functionAppName -g $resourceGroup `
    --settings "MySetting1=Hello" "MySetting2=World"

Step 7 - Configure a Daily Use Quota

Another optional feature you might want to consider setting up is a daily usage quota. One of the great things about the serverless Azure Functions consumption plan is that it offers near-infinite scale to handle huge spikes in load. But that does also leave you open to a "denial of wallet attack" where due to an external DoS attack or a coding mistake, you end up with a huge bill because your function app scaled out to hundreds of instances. The daily quota allows you to set a limit in terms of "Gigabyte seconds" (GB-s), which you might want to set just to be on the safe side when you're experimenting. For a production system, I'd probably rather leave this quota off (or set very high), and configure alerts instead to tell me when my usage is much higher than normal.

Here's the command that sets the daily usage quota to 50000 GB-s:

az functionapp update -g $resourceGroup -n $functionAppName `
    --set dailyMemoryTimeQuota=50000

Summary

The Azure CLI provides us with an easy way to deploy and manage our Azure Function apps. Of course, you can also create an ARM template that contains the same resources, and deploy that with the CLI. Personally I find the CLI great when I'm experimenting and prototyping, and when I've got an application that's a bit more stable and ready for production, I might create an ARM template to allow deploying the whole thing in one go.

Want to learn more about how easy it is to get up and running with Azure Functions? Be sure to check out my Pluralsight courses Azure Functions Fundamentals and Microsoft Azure Developer: Create Serverless Functions

Comments

Comment by Tory Berra

Step 6 how do you set connection strings? https://docs.microsoft.com/... there is no az functionapp config connection-string

Tory Berra
Comment by Mark Heath

I just use app settings for connection strings

Mark Heath
Comment by Máximo Calero

HI Mark, good approach to deploy azure function. Thank you for your article.
I have a question about "az functionapp deployment source config-zip".
Can we avoid to delete the existing azure functions that they are already deployed in the azure function app?

Máximo Calero
Comment by Mark Heath

In Azure Functions, the unit of deployment is a whole Function app. So you should put the whole thing in a single source control repository and always deploy it in one go. That way existing functions will remain when you add a new one.

Mark Heath
Comment by McLovin

All right that's great info. I would integrate the Azure CLI into my TFS Release pipeline as a task. But what I want to do is configure the proxies that Azure function apps support. Can i programmatically setup proxies using the Azure CLI? Is it an app setting?

McLovin
Comment by Mark Heath

Proxies are configured as a proxies.json file that is part of your function app. So you don't configure them from outside with the Azure CLI. They can however reference application settings if you need them to be customizable dependent on environment (e.g. to point to a different domain).

Mark Heath