Tutorial: Deploy a background processing application with Azure Container Apps

Using Azure Container Apps allows you to deploy applications without requiring the exposure of public endpoints. By using Container Apps scale rules, the application can scale out and in based on the Azure Storage queue length. When there are no messages on the queue, the container app scales in to zero.

You learn how to:

  • Create a Container Apps environment to deploy your container apps
  • Create an Azure Storage Queue to send messages to the container app
  • Deploy your background processing application as a container app
  • Verify that the queue messages are processed by the container app

Setup

To begin, sign in to Azure. Run the following command, and follow the prompts to complete the authentication process.

az login

Next, install the Azure Container Apps extension for the CLI.

az extension add --name containerapp --upgrade

Now that the current extension or module is installed, register the Microsoft.App namespace.

Note

Azure Container Apps resources have migrated from the Microsoft.Web namespace to the Microsoft.App namespace. Refer to Namespace migration from Microsoft.Web to Microsoft.App in March 2022 for more details.

az provider register --namespace Microsoft.App

Register the Microsoft.OperationalInsights provider for the Azure Monitor Log Analytics workspace if you have not used it before.

az provider register --namespace Microsoft.OperationalInsights

Next, set the following environment variables:

RESOURCE_GROUP="my-container-apps"
LOCATION="canadacentral"
CONTAINERAPPS_ENVIRONMENT="my-environment"

With these variables defined, you can create a resource group to organize the services related to your new container app.

az group create \
  --name $RESOURCE_GROUP \
  --location $LOCATION

With the CLI upgraded and a new resource group available, you can create a Container Apps environment and deploy your container app.

Create an environment

An environment in Azure Container Apps creates a secure boundary around a group of container apps. Container Apps deployed to the same environment are deployed in the same virtual network and write logs to the same Log Analytics workspace.


Individual container apps are deployed to an Azure Container Apps environment. To create the environment, run the following command:

az containerapp env create \
  --name $CONTAINERAPPS_ENVIRONMENT \
  --resource-group $RESOURCE_GROUP \
  --location "$LOCATION"

Set up a storage queue

Begin by defining a name for the storage account. Storage account names must be unique within Azure and be from 3 to 24 characters in length containing numbers and lowercase letters only.

STORAGE_ACCOUNT_NAME="<STORAGE_ACCOUNT_NAME>"

Create an Azure Storage account.

az storage account create \
  --name $STORAGE_ACCOUNT_NAME \
  --resource-group $RESOURCE_GROUP \
  --location "$LOCATION" \
  --sku Standard_RAGRS \
  --kind StorageV2

Next, get the connection string for the queue.

QUEUE_CONNECTION_STRING=`az storage account show-connection-string -g $RESOURCE_GROUP --name $STORAGE_ACCOUNT_NAME --query connectionString --out json | tr -d '"'`

Now you can create the message queue.

az storage queue create \
  --name "myqueue" \
  --account-name $STORAGE_ACCOUNT_NAME \
  --connection-string $QUEUE_CONNECTION_STRING

Finally, you can send a message to the queue.

az storage message put \
  --content "Hello Queue Reader App" \
  --queue-name "myqueue" \
  --connection-string $QUEUE_CONNECTION_STRING

Deploy the background application

Create a file named queue.json and paste the following configuration code into the file.

{
    "$schema": "https://schema.management.azure.com/schemas/2019-08-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "location": {
            "defaultValue": "canadacentral",
            "type": "String"
        },
        "environment_name": {
            "type": "String"
        },
        "queueconnection": {
            "type": "secureString"
        }
    },
    "variables": {},
    "resources": [
    {
        "name": "queuereader",
        "type": "Microsoft.App/containerApps",
        "apiVersion": "2022-03-01",
        "kind": "containerapp",
        "location": "[parameters('location')]",
        "properties": {
            "managedEnvironmentId": "[resourceId('Microsoft.App/managedEnvironments', parameters('environment_name'))]",
            "configuration": {
                "activeRevisionsMode": "single",
                "secrets": [
                {
                    "name": "queueconnection",
                    "value": "[parameters('queueconnection')]"
                }]
            },
            "template": {
                "containers": [
                    {
                        "image": "mcr.microsoft.com/azuredocs/containerapps-queuereader",
                        "name": "queuereader",
                        "env": [
                            {
                                "name": "QueueName",
                                "value": "myqueue"
                            },
                            {
                                "name": "QueueConnectionString",
                                "secretRef": "queueconnection"
                            }
                        ]
                    }
                ],
                "scale": {
                    "minReplicas": 1,
                    "maxReplicas": 10,
                    "rules": [
                        {
                            "name": "myqueuerule",
                            "azureQueue": {
                                "queueName": "myqueue",
                                "queueLength": 100,
                                "auth": [
                                    {
                                        "secretRef": "queueconnection",
                                        "triggerParameter": "connection"
                                    }
                                ]
                            }
                        }
                    ]
                }
            }
        }
    }]
}

Now you can create and deploy your container app.

az deployment group create --resource-group "$RESOURCE_GROUP" \
  --template-file ./queue.json \
  --parameters \
    environment_name="$CONTAINERAPPS_ENVIRONMENT" \
    queueconnection="$QUEUE_CONNECTION_STRING" \
    location="$LOCATION"

This command deploys the demo application from the public container image called mcr.microsoft.com/azuredocs/containerapps-queuereader and sets secrets and environments variables used by the application.

The application scales out to 10 replicas based on the queue length as defined in the scale section of the ARM template.

Verify the result

The container app runs as a background process. As messages arrive from the Azure Storage Queue, the application creates log entries in Log analytics. You must wait a few minutes for the analytics to arrive for the first time before you're able to query the logged data.

Run the following command to see logged messages. This command requires the Log analytics extension, so accept the prompt to install extension when requested.

LOG_ANALYTICS_WORKSPACE_CLIENT_ID=`az containerapp env show --name $CONTAINERAPPS_ENVIRONMENT --resource-group $RESOURCE_GROUP --query properties.appLogsConfiguration.logAnalyticsConfiguration.customerId --out tsv`

az monitor log-analytics query \
  --workspace $LOG_ANALYTICS_WORKSPACE_CLIENT_ID \
  --analytics-query "ContainerAppConsoleLogs_CL | where ContainerAppName_s == 'queuereader' and Log_s contains 'Message ID' | project Time=TimeGenerated, AppName=ContainerAppName_s, Revision=RevisionName_s, Container=ContainerName_s, Message=Log_s | take 5" \
  --out table

Tip

Having issues? Let us know on GitHub by opening an issue in the Azure Container Apps repo.

Clean up resources

Once you're done, run the following command to delete the resource group that contains your Container Apps resources.

Caution

The following command deletes the specified resource group and all resources contained within it. If resources outside the scope of this tutorial exist in the specified resource group, they will also be deleted.

az group delete \
  --resource-group $RESOURCE_GROUP