Skip to content

03 - Configuration, Secrets, and Dapr

This step configures runtime settings in Azure Container Apps, including environment variables, secrets, KEDA scaling rules, and Dapr sidecar options.

Infrastructure Context

Service: Container Apps (Consumption) | Network: VNet integrated | VNet: ✅

This tutorial assumes a production-ready Container Apps deployment with a custom VNet, ACR with managed identity pull, and private endpoints for backend services.

flowchart TD
    INET[Internet] -->|HTTPS| CA["Container App\nConsumption\nLinux Python 3.11"]

    subgraph VNET["VNet 10.0.0.0/16"]
        subgraph ENV_SUB["Environment Subnet 10.0.0.0/23\nDelegation: Microsoft.App/environments"]
            CAE[Container Apps Environment]
            CA
        end
        subgraph PE_SUB["Private Endpoint Subnet 10.0.2.0/24"]
            PE_ACR[PE: ACR]
            PE_KV[PE: Key Vault]
            PE_ST[PE: Storage]
        end
    end

    PE_ACR --> ACR[Azure Container Registry]
    PE_KV --> KV[Key Vault]
    PE_ST --> ST[Storage Account]

    subgraph DNS[Private DNS Zones]
        DNS_ACR[privatelink.azurecr.io]
        DNS_KV[privatelink.vaultcore.azure.net]
        DNS_ST[privatelink.blob.core.windows.net]
    end

    PE_ACR -.-> DNS_ACR
    PE_KV -.-> DNS_KV
    PE_ST -.-> DNS_ST

    CA -.->|System-Assigned MI| ENTRA[Microsoft Entra ID]
    CAE --> LOG[Log Analytics]
    CA --> AI[Application Insights]

    style CA fill:#107c10,color:#fff
    style VNET fill:#E8F5E9,stroke:#4CAF50
    style DNS fill:#E3F2FD

Configuration Flow

graph TD
    ENV[Env Vars] --> ACA[Container App]
    SEC[Secrets] --> ACA
    DAPR[Dapr] --> ACA
    ACA --> APP[Application]

Prerequisites

Step-by-step

  1. Set standard variables (reuse Bicep outputs from Step 02)
RG="rg-aca-python-demo"
BASE_NAME="pycontainer"
DEPLOYMENT_NAME="main"

APP_NAME=$(az deployment group show \
  --name "$DEPLOYMENT_NAME" \
  --resource-group "$RG" \
  --query "properties.outputs.containerAppName.value" \
  --output tsv)

ENVIRONMENT_NAME=$(az deployment group show \
  --name "$DEPLOYMENT_NAME" \
  --resource-group "$RG" \
  --query "properties.outputs.containerAppEnvName.value" \
  --output tsv)

ACR_NAME=$(az deployment group show \
  --name "$DEPLOYMENT_NAME" \
  --resource-group "$RG" \
  --query "properties.outputs.containerRegistryName.value" \
  --output tsv)

???+ example "Expected output" The commands above set shell variables silently. Verify them with:

   ```bash
   echo "APP_NAME=$APP_NAME"
   echo "ENVIRONMENT_NAME=$ENVIRONMENT_NAME"
   echo "ACR_NAME=$ACR_NAME"
   ```

   ```text
   APP_NAME=<your-app-name>
   ENVIRONMENT_NAME=<your-env-name>
   ACR_NAME=<acr-name>
   ```
  1. Set environment variables
az containerapp update \
  --name "$APP_NAME" \
  --resource-group "$RG" \
   --set-env-vars "LOG_LEVEL=INFO" "FEATURE_FLAG=true"

???+ example "Expected output"

{
  "name": "ca-pycontainer-<unique-suffix>",
  "provisioningState": "Succeeded"
}

  1. Store and reference a secret
az containerapp secret set \
  --name "$APP_NAME" \
  --resource-group "$RG" \
   --secrets "db-password=<secret-value>"

???+ example "Expected output"

Containerapp must be restarted in order for secret changes to take effect.
[
  {
    "name": "appinsights-connection-string"
  },
  {
    "name": "registry-password"
  },
  {
    "name": "db-password"
  }
]

az containerapp update \
  --name "$APP_NAME" \
  --resource-group "$RG" \
  --set-env-vars "DB_PASSWORD=secretref:db-password"

???+ example "Expected output"

{
  "name": "ca-pycontainer-<unique-suffix>",
  "provisioningState": "Succeeded"
}

  1. Configure KEDA HTTP autoscaling
az containerapp update \
  --name "$APP_NAME" \
  --resource-group "$RG" \
  --min-replicas 0 \
  --max-replicas 10 \
  --scale-rule-name "http-scale" \
  --scale-rule-type "http" \
   --scale-rule-http-concurrency 50

???+ example "Expected output"

{
  "name": "ca-pycontainer-<unique-suffix>",
  "provisioningState": "Succeeded"
}

Choosing HTTP concurrency threshold

A lower value (e.g., 50) triggers scale-out more aggressively, suitable for latency-sensitive APIs. A higher value (e.g., 100, used in infra/main.bicep) delays scale-out for cost efficiency. Choose based on your latency SLO and budget. The Bicep template in infra/main.bicep defaults to maxReplicas=3 for cost safety. Override with --parameters maxReplicas=10 when deploying infrastructure.

  1. Configure queue-driven KEDA scaling (example)
az containerapp update \
  --name "$APP_NAME" \
  --resource-group "$RG" \
  --scale-rule-name "queue-scale" \
  --scale-rule-type "azure-servicebus" \
  --scale-rule-metadata "queueName=orders" "namespace=sb-namespace" \
  --scale-rule-auth "connection=servicebus-connection"

???+ example "Expected output"

{
  "name": "<your-app-name>",
  "provisioningState": "Succeeded"
}

Verify pushed repositories in ACR:

az acr repository list \
  --name "$ACR_NAME" \
  --output json

???+ example "Expected output"

["myapp", "myapp-job"]

  1. Enable Dapr sidecar
az containerapp dapr enable \
  --name "$APP_NAME" \
  --resource-group "$RG" \
  --dapr-app-id "$APP_NAME" \
  --dapr-app-port 8000

???+ example "Expected output"

{
  "appId": "ca-pycontainer-<unique-suffix>",
  "appPort": 8000,
  "appProtocol": "http",
  "enableApiLogging": false,
  "enabled": true,
  "httpMaxRequestSize": null,
  "httpReadBufferSize": null,
  "logLevel": "info"
}

Python example: read config safely

import os

LOG_LEVEL = os.environ.get("LOG_LEVEL", "INFO")
FEATURE_FLAG = os.environ.get("FEATURE_FLAG", "false").lower() == "true"
DB_PASSWORD = os.environ.get("DB_PASSWORD", "")

Advanced Topics

  • Use Key Vault + managed identity instead of direct secret values.
  • Tune KEDA thresholds differently for API and background worker apps.
  • Add Dapr pub/sub and state store components for event-driven workflows.

See Also

Sources