Containerized Activities in Durable Workflows - Part 2
This is the second part in a series about how we can build a serverless workflow using Azure Durable Functions, but implement some of the activities in that workflow using containers with Azure Container Instances. Today we'll look at creating the necessary infrastructure using the Azure CLI.
Current table of contents:
- Part 1: Introduction - What are we building and why do we need it?
- Part 2 (this post): Creating infrastructure with the Azure CLI
- Part 3: Creating an Event Grid Subscription
- Part 4: Creating Container Instances with the Azure .NET SDK
- Part 5: Creating ACI Instances in a Durable Functions Workflow
We'll create a resource group for the Function App containing:
- A Storage Account for Durable Functions to use as well as a File Share for our containers to use
- An Application Insights instance for monitoring and diagnostics
- A Function App (running on the consumption plan) with a system assigned managed identity
We'll also create another resource group that will be used to host our ACI containers. Then we'll grant contributor access to our managed identity so that our Function App is allowed to create resources in that resource group.
Create Storage Account
As usual, I've chosen to automate this with the Azure CLI in PowerShell. First, we create a resource group for our Storage Account and Function App:
$resourceGroup = "DurableFunctionsAci"
$location = "westeurope"
az group create -n $resourceGroup -l $location
In my demo code, I'm using a random number as part of the Storage Account name, but this means my script isn't idempotent unless I first check whether the Storage Account already exists and use the same random number.
$existingName = az storage account list -g $resourceGroup `
--query "[].name" -o tsv
$prefix = "durablefuncsaci"
if ($existingName) {
$rand = $existingName.SubString($prefix.Length)
}
else
{ $rand = Get-Random -Minimum 10000 -Maximum 99999 }
$storageAccountName = "$prefix$rand"
Now we know the Storage Account name we want to use, we can create it with az storage account create
which is idempotent if the Storage Account already exists. Then we can get the Storage Account key with az storage account keys list
which we need for later.
az storage account create `
-n $storageAccountName `
-l $location `
-g $resourceGroup `
--sku Standard_LRS
$storageAccountKey = az storage account keys list -n $storageAccountName `
--query [0].value -o tsv
Create a File Share
We want a File Share that we can mount to our ACI containers later. So I'll create one with az storage share create
$shareName = "acishare"
az storage share create `
-n $shareName `
--account-key $storageAccountKey `
--account-name $storageAccountName
Create an Application Insights instance
I've blogged before about creating an Application Insights instance with the Azure CLI, but I've since found a slightly less cumbersome way to do it. Here's how to create the App Insights instance.
$appInsightsName = "$prefix$rand"
az resource create `
-g $resourceGroup -n $appInsightsName `
--resource-type "Microsoft.Insights/components" `
--properties '{\"Application_Type\":\"web\"}'
Create a Function App
We also need a Function App to host our Durable Functions workflow, and connect it to the Storage Account and App Insights instance we just created. The az functionapp create
command conveniently has flags that lets us connect everything together and with the --consumption-plan-location
flag we can indicate that we want to use the consumption App Service Plan without explicitly needing to create one first.
$functionAppName = "$prefix$rand"
az functionapp create `
-n $functionAppName `
--storage-account $storageAccountName `
--consumption-plan-location $location `
--app-insights $appInsightsName `
--runtime dotnet `
-g $resourceGroup
Give the Function App a Managed Identity
We need to give our Function App a "system assigned" managed identity, and we can use az functionapp identity assign
to do that, which again is idempotent, returning the existing identity if one has already been created. I also need to get hold of the principal and tenant ids for use later.
az functionapp identity assign -n $functionAppName -g $resourceGroup
$principalId = az functionapp identity show -n $functionAppName `
-g $resourceGroup --query principalId -o tsv
$tenantId = az functionapp identity show -n $functionAppName `
-g $resourceGroup --query tenantId -o tsv
Grant Contributor Rights to the Managed Identity
We want our Function App to have permissions to create new ACI container groups, so we're going to put the managed identity we just created into the "contributor" role for a resource group that will hold all the ACI container groups. Let's create the resource group first:
$aciResourceGroup = "DurableFunctionsAciContainers"
az group create -n $aciResourceGroup -l $location
Now we can assign the contributor role to the managed identity but scope it to only have rights to the resource group we just created.
$subscriptionId = az account show --query "id" -o tsv
az role assignment create --role "Contributor" `
--assignee-object-id $principalId `
--scope "/subscriptions/$subscriptionId/resourceGroups/$aciResourceGroup"
Summary
We've created most of the Azure resources we need for this demo. The only missing thing is the Event Grid subscription, which is a bit more complex to set up so we'll look at that in part 3