CloudBrum
CloudBrum · Cloud decision-support platform
Azure App modernization

Azure Container AppsLast reviewedReading time~12 minLevelBeginner to advanced

Microsoft Azure · App modernization · Serverless containers

Containers that scale with the load, down to zero, with no cluster to run. Container Apps runs your images on infrastructure Microsoft manages, puts HTTPS in front of them, scales on HTTP traffic, queues or a schedule, and keeps every deployment as a revision you can split traffic between. The plan decides the bill. The Consumption profile charges by the second while your app runs and can rest at zero, while dedicated profiles reserve whole machines. Pick one on purpose, and check what a minimum replica count does to the idle cost.

On this page (17 sections)

    Mind map: Azure Container Apps at a glance

    Azure Container Apps mind map Azure Container Apps at a glance: Environment: Shared boundary, Virtual network, Log destination; Apps and revisions: Revisions, Traffic splitting, Single or multiple mode; Scaling: HTTP concurrency, KEDA event rules, Scale to zero; Compute plans: Consumption, Dedicated, GPU profiles; Networking: External ingress, Internal ingress, Custom domains; Identity: Managed identity, Registry identity, Key Vault secrets; Jobs and sidecars: Manual and cron jobs, Event-driven jobs, Dapr, init containers; Pricing: Active and idle rates, Free monthly grant, Dedicated nodes. Azure Container Apps at a glance Serverless containers on Azure: the main building blocks and decisions CloudBrum Cloud decision-support platform CloudBrum Shared boundary Virtual network Log destination Environment Revisions Traffic splitting Single or multiple mode Apps and revisions HTTP concurrency KEDA event rules Scale to zero Scaling Consumption Dedicated GPU profiles Compute plans External ingress Internal ingress Custom domains Networking Managed identity Registry identity Key Vault secrets Identity Manual and cron jobs Event-driven jobs Dapr, init containers Jobs and sidecars Active and idle rates Free monthly grant Dedicated nodes Pricing Container Apps17-point analysis CloudBrum· 17-point cloud service analysis cloudbrum.com
    CloudBrum Container Apps at a glance · 17-point analysis Environment Shared boundary Virtual network Log destination Apps and revisions Revisions Traffic splitting Single or multiple mode Scaling HTTP concurrency KEDA event rules Scale to zero Compute plans Consumption Dedicated GPU profiles Networking External ingress Internal ingress Custom domains Identity Managed identity Registry identity Key Vault secrets Jobs and sidecars Manual and cron jobs Event-driven jobs Dapr, init containers Pricing Active and idle rates Free monthly grant Dedicated nodes CloudBrum · cloudbrum.com

    Free to share. The downloaded image includes the CloudBrum link.

    Key features (summary)

    • Containers without a clusterYou deploy an image with a few settings: CPU, memory, port and scale limits. Microsoft runs the machines and the Kubernetes layer behind them, and you never see a node or an ingress controller.
    • Revisions and traffic splittingEvery change to the app’s template creates an immutable revision. In multiple-revision mode you can send 10% of traffic to the new one, watch it, and then move the rest, or roll back by moving the weight.
    • Scaling down to zeroApps scale on HTTP concurrency, TCP connections or any KEDA scaler, such as a queue length. A Consumption app with zero minimum replicas costs nothing for compute while idle, at the price of a short cold start.
    • Consumption and Dedicated plansThe Consumption profile is pay-per-use and serverless. A Dedicated profile reserves machines of a chosen size, with GPU options, and suits steady load or large replicas.
    • JobsA container can run as a job instead of a service: started by hand, on a cron schedule or by an event, and billed only while it runs. It’s a good home for nightly reports and queue workers.
    • Identity and secretsA managed identity pulls images from Azure Container Registry and reaches Azure services without keys. Secrets can be stored in the app or referenced from Key Vault.
    • NetworkingIngress can be public or internal. An environment can sit in your virtual network, with its own subnet, so apps reach private databases and are reachable only from inside.
    • Dapr and sidecarsTurn on Dapr for service-to-service calls, state and pub/sub, and add init and sidecar containers when an app needs a helper next to it.

    Basic concepts

    Environment
    The secure boundary around a group of apps and jobs. They share a virtual network, a log destination and an internal DNS.
    Container app
    One deployable unit, defined by its containers, ingress, scale rules and identity.
    Revision
    An immutable snapshot of an app’s template. Changes to containers or scale rules create a new revision, and settings such as ingress weights don’t.
    Replica
    One running instance of a revision. Scale rules decide how many replicas exist.
    Revision mode
    Single mode keeps one active revision and replaces it on each change. Multiple mode keeps several, so you can split traffic.
    Ingress
    The HTTPS or TCP front door of an app, with a target port, external or internal visibility, and optional IP restrictions.
    Scale rule
    A condition that adds or removes replicas: HTTP concurrency, TCP connections, CPU, memory or a custom KEDA scaler.
    KEDA
    Kubernetes event-driven autoscaling. Container Apps uses it so apps can scale on Azure Service Bus, Storage queues, Kafka lag and similar sources.
    Workload profile
    The kind of compute that an app or job runs on: Consumption, Dedicated (with several machine sizes) or, in preview, Flex.
    Consumption profile
    The serverless profile. It bills by the second for the resources your replicas use, and has a free monthly grant.
    Dedicated profile
    A set of reserved machines. You pay for each running instance, plus a plan management fee, whether replicas use them fully or not.
    Container Apps job
    A container that runs to completion, started manually, by a schedule or by an event.
    Managed identity
    An Entra identity for the app, used to pull images, read Key Vault secrets and call Azure services without stored credentials.
    Dapr
    An open-source runtime for building blocks like service invocation, state stores and pub/sub, available as a sidecar through an app setting.

    How to create & configure it

    Create a container app with the Azure CLI

    1. Pick the region and the planChoose a region near your users (Central India or South India). Start on the Consumption profile unless the workload is steady and large, since it can scale to zero and carries a free monthly grant.
    2. Plan the networkIf apps need private resources, create a subnet for the environment, delegate it to Microsoft.App/environments, and decide whether the environment should have only internal addresses. A subnet can’t be swapped later without rebuilding.
    3. Create the log destination and the environmentCreate a Log Analytics workspace, or choose another destination, then az containerapp env create. The environment is where apps share networking and logs.
    4. Create the identity and the registry accessMake a user-assigned managed identity for the app, give it AcrPull on your registry and the minimum role on the storage account, and use it as the registry identity so no password is stored.
    5. Create the appRun az containerapp create with the image, target port, ingress, CPU and memory, a minimum and maximum replica count and an HTTP scale rule. Pick multiple-revision mode if you plan to split traffic.
    6. Test scale and cold startSend load and watch replicas rise, then stop and watch them fall. If the minimum is zero, time the first request after a quiet period, and decide whether users can live with it.
    7. Roll out a change graduallyDeploy a new revision with a suffix, give it 10% of the traffic, check logs and errors, then move the weight across.
    8. Add a job for scheduled workCreate a job from the same image with a cron expression for nightly work, and give it its own replica timeout and retry limit.
    9. Add the domain and the alertsBind a custom domain with a managed certificate, send logs to Log Analytics, and alert on restarts, failed revisions and replica counts hitting the maximum.

    Tip: az containerapp up builds and deploys from source or an image in one command, which is fine for a first try. For anything shared, write the environment and the app as Bicep or Terraform (see the code references), so a revision is a reviewed change.

    Common issues after configuration

    SymptomLikely causeWhat to check / fix
    A revision stays in Provisioning or ends FailedThe container can’t start or can’t pull the image, or the app listens on a different port from the ingress target portRead az containerapp logs show and the system logs. Match the target port with the port the process listens on, and check the registry identity can pull.
    UNAUTHORIZED or manifest unknown when pulling from the registryThe registry identity has no AcrPull, or the tag doesn’t existGrant AcrPull to the identity the app uses as its registry identity, wait for the role to propagate, and check the tag with az acr repository show-tags.
    The app URL returns 404 or never answersIngress is off, set to internal while you test from outside, or points to the wrong portCheck az containerapp ingress show, switch visibility if needed and confirm the target port.
    Requests fail with a 504 after about four minutesThe platform’s ingress has a request timeout, and long requests exceed itKeep requests short, return a status URL for slow work and move the work to a job or a queue worker.
    The first request after a quiet period takes several secondsThe app scaled to zero, and a replica must startSet a minimum of one replica for latency-sensitive apps, shrink the image and do lazy start-up work.
    The app never scales to zeroA minimum replica count is set, a TCP or custom scaler keeps one replica busy, or a probe keeps traffic flowingSet min-replicas to 0, check the scale rules and look for health checks or monitors that hit the app all day.
    A KEDA scale rule doesn’t reactThe metadata or the authentication secret is wrong, or the identity can’t read the queueCheck the rule’s metadata against the scaler docs, test the secret, and look at the system logs for scaler errors.
    Traffic splitting settings are rejected or ignoredThe app is in single-revision mode, or the weights don’t add to 100Switch to multiple mode, name the revisions, and set weights that sum to 100.
    A Key Vault secret reference failsThe app’s identity can’t read the secret, or the Key Vault network rules block the environmentGive the identity the Key Vault Secrets User role, and allow the environment’s subnet in the vault firewall.
    Environment creation fails with a subnet errorThe subnet is too small, not delegated, or overlaps the platform’s reserved rangesUse a subnet of at least the size the docs ask for (a /27 for workload profile environments), delegate it to Microsoft.App/environments, and choose a platform CIDR that doesn’t overlap yours.
    The bill shows compute charges while there is no trafficReplicas at a minimum count bill idle-rate compute, and Dedicated nodes bill while they runLower the minimum replicas, or move bursty apps to the Consumption profile. Keep dedicated profiles only for load that fills them.

    Use cases: when and where to use it

    Good fit

    • HTTP APIs and web back ends that have spiky or unpredictable traffic
    • Event-driven workers that read from queues or topics and should scale to zero when empty
    • Microservices that need revisions and gradual rollouts without running Kubernetes
    • Scheduled and one-off batch work through jobs
    • Teams that want containers on Azure with Dapr, managed identity and private networking
    • Migrating from App Service or from a self-run cluster to something with less to look after

    Consider something else

    • Full control of Kubernetes objects, operators and custom networking → Azure Kubernetes Service
    • Event-driven code with no container → Azure Functions
    • A classic web app with built-in runtimes and deployment slots → Azure App Service
    • A single short-lived container with no scaling → Azure Container Instances
    • The same job on other clouds → compare Cloud Run and AWS App Runner, which is closed to new customers

    Pros: why consider it?

    Why teams choose it

    • No cluster to run, and no Kubernetes knowledge needed for most apps
    • Scale to zero with a free monthly grant on the Consumption profile
    • Revisions and traffic splitting built in
    • KEDA scalers for queues and events
    • Jobs for scheduled and one-off work
    • Managed identity, Key Vault references and virtual network integration

    Trade-offs to weigh

    • A request timeout of about four minutes
    • Less control than Kubernetes: no custom operators, daemonsets or arbitrary cluster add-ons
    • Cold starts when apps scale to zero
    • Dedicated profiles bill for whole nodes, and the cost model takes some care
    • Environment networking choices are hard to change later
    • Features such as Flex profiles are still in preview

    Common threats, vulnerabilities & risks

    RiskSeverityWhy it mattersMitigation
    A public ingress with no authenticationHighAnyone can call the API, and scanners find new endpoints quickly.Turn on built-in authentication or validate tokens in the app, restrict source IP ranges, or use internal ingress behind Front Door or API Management.
    Secrets as plain environment variablesHighThey show in the app definition and leak into logs and screenshots.Use secrets with Key Vault references, mounted through the managed identity.
    Registry admin credentials in useMediumShared passwords don’t expire and can’t be traced to one app.Disable the admin user and use a managed identity with AcrPull.
    A dedicated profile that sits mostly emptyMediumYou pay for the whole node while it runs.Choose Consumption for bursty apps, and size dedicated profiles from measurements.
    Minimum replicas set to high values everywhereMediumIdle-rate compute bills around the clock.Use zero where cold starts are fine, and one for apps that must answer quickly.
    Untested scale rulesMediumA wrong threshold causes either runaway scaling or an overloaded queue.Load test, cap max-replicas, and alert when it’s reached.
    Network design done after creationMediumChanging the environment’s subnet or visibility means building a new environment.Decide on the virtual network and internal or external access first.
    Unreviewed revisions in productionLow–MedA bad image reaches users at once in single-revision mode.Use multiple-revision mode with a small weight for new revisions, and review in a pipeline.
    Logs and Dapr traffic growing quietlyLow–MedVerbose logging and many sidecar calls add Log Analytics cost.Set log levels, sample, and set a daily cap on the workspace.

    Performance optimisation

    • Set CPU and memory from measurements. On Consumption they’re billed by use, so over-allocating costs money and under-allocating costs restarts.
    • Use a minimum of one replica for latency-sensitive endpoints, and zero for background and internal ones.
    • Choose the HTTP concurrency for the scale rule by load testing. Lower numbers scale earlier, higher numbers pack more requests per replica.
    • Keep the image small and the start-up fast. Scale-out time is dominated by the image pull and the process start.
    • Use startup, liveness and readiness probes so traffic only reaches replicas that are ready.
    • Put the app and its database in the same region, and use private endpoints for data stores.
    • Use event-based scale rules for workers instead of polling in a loop, so replicas appear when messages arrive.
    • Cache static and repeatable responses at the edge with Front Door or a CDN.

    Reduce monthly cost

    FinOps is the habit of managing cloud spend together with engineering. These are the FinOps checks that matter most for Azure Container Apps.

    • Use the Consumption profile for bursty workloads, and make use of the monthly free grant of vCPU-seconds, GiB-seconds and requests.
    • Set minimum replicas to zero wherever a cold start is acceptable. Replicas at the minimum bill an idle rate rather than nothing.
    • Keep Dedicated profiles for steady, large loads that fill the node, and check their utilisation monthly.
    • Right-size CPU and memory per replica. On Consumption you pay for what you allocate while the replica runs.
    • Cap max replicas so a bug or an attack can’t scale the bill without limit.
    • Run scheduled work as jobs, which cost nothing between executions.
    • Control Log Analytics ingestion with log levels and a daily cap, since logs can cost more than small apps.
    • Buy savings plans or reservations for Dedicated profiles that run all the time.
    • Delete old revisions' replicas by deactivating revisions you no longer need.
    • Tag environments and apps, and set a budget alert in Cost Management.

    The grants and the way compute is billed come from Microsoft's billing page as we read it in October 2026. The per-second rates, the Dedicated plan management fee and the preview Flex profile change, so check the live pricing page (see Pricing).

    Security optimisation

    • Use a managed identity for the registry, Key Vault and Azure data services, and disable the registry’s admin user.
    • Store secrets in Key Vault and reference them from the app, instead of typing values into the app definition.
    • Turn on built-in authentication with Microsoft Entra ID for apps that serve people, and validate tokens for service-to-service calls.
    • Prefer internal ingress with Front Door or API Management in front, and restrict source IP ranges where an app must be public.
    • Place the environment in a virtual network and use private endpoints for databases and storage.
    • Enable mutual TLS and peer-to-peer encryption inside the environment where your rules require it.
    • Run containers as a non-root user, keep images small and scan them in the registry, and deploy by digest or fixed tag.
    • Use Microsoft Defender for Cloud recommendations for container registries and the environment.
    • Send system and console logs to Log Analytics, and alert on failed revisions and unusual restart counts.
    • Limit who can create and change apps with Azure RBAC, and use policy to require tags and approved registries.

    Governance & compliance

    Guardrails

    • Tagging policies for environments, apps and jobs (owner, environment, cost centre)
    • An Azure Policy that denies container apps with public ingress or without managed identity in production subscriptions
    • A shared Bicep or Terraform module for environments, with virtual network, logging and identity already set
    • An approved list of registries and base images, with a retirement date for each

    Continuous checks (Azure Policy and Defender for Cloud)

    • “Container Apps environment should use network injection”
    • “Container Apps should disable external network access”
    • “Managed identity should be enabled for Container Apps”
    • “Container Apps should only be accessible over HTTPS”
    • “Container Apps should configure authentication”

    The Azure Activity Log records who created, changed or deleted environments and apps, Azure Policy applies and reports on the rules above, Defender for Cloud gives recommendations, and the Service Trust Portal holds compliance material. Microsoft runs the platform, the nodes and the Kubernetes layer behind Container Apps, and you own the images, the app code, identities, secrets, network settings and the scale rules.

    Reduce carbon footprint

    • Scale to zero where you can, so idle apps use no compute at all.
    • Right-size CPU and memory, since oversized replicas use more energy for the same work.
    • Use jobs for scheduled work instead of an always-on worker.
    • Keep images small to cut the data moved on every scale-out.
    • Cache at the edge, so fewer requests reach your replicas.
    • Choose a region with a cleaner grid for workloads that aren’t tied to a place, as far as data rules allow.
    • The Azure Emissions Impact Dashboard estimates the footprint of a subscription. Check what it includes for Container Apps before you quote a figure.

    Pricing

    Purchase options

    Consumption profile Per second of use

    You pay for vCPU and memory while replicas run, at a lower idle rate when a replica is up but not handling requests, plus a small charge per million requests above the free allowance.

    Free monthly grant Per subscription

    Microsoft’s billing page lists the first 180,000 vCPU-seconds, 360,000 GiB-seconds and 2 million requests each month as free for the Consumption plan.

    Dedicated profiles Per node-second, plus a management fee

    You pay for the reserved instances of the chosen size while they run, whether replicas use them fully or not, and a plan management fee applies.

    Everything around it Varies

    Log Analytics ingestion, Container Registry, data transfer out, public IPs and load balancers in a virtual network environment, and Defender for Cloud plans.

    What you actually pay for

    • vCPU and memory per second for the replicas that run, at active or idle rates
    • Requests above the free monthly allowance
    • Reserved nodes and a management fee on Dedicated profiles
    • Log ingestion, the container registry and data transfer out
    • Anything else you attach, such as Front Door, Defender plans or a NAT gateway

    Rates differ by region and change over time, so confirm them. See the official Azure Container Apps pricing page, the Azure pricing calculator and Microsoft's page on billing in Azure Container Apps for how active and idle usage are counted.

    Important code references

    The orders-api service again, this time in a Container Apps environment on a virtual network: a user-assigned identity that pulls from the registry and writes receipts to Blob Storage, an HTTP scale rule, multiple revisions with a 10% canary, and a nightly job from the same image. The Azure CLI tab builds it and Terraform builds the environment and the app. The Python tab moves traffic between revisions with the management SDK, and the C# tab reports on each revision. Replace the names, subscription, registry and storage account with your own. Replicas at the minimum count bill from the moment they start, so delete the test environment when you’re done.

    # Placeholders: replace names, the registry, the storage account and the subnet with your own.
    RG=rg-orders-apps
    LOC=centralindia
    ENV=cae-orders
    ACR=acrordersexample
    STORAGE=storordersexample
    SUBNET_ID=$(az network vnet subnet show --resource-group rg-orders --vnet-name vnet-orders --name snet-apps --query id -o tsv)
    
    az group create --name $RG --location $LOC
    az monitor log-analytics workspace create --resource-group $RG --workspace-name log-orders --location $LOC
    LOG_ID=$(az monitor log-analytics workspace show --resource-group $RG --workspace-name log-orders --query customerId -o tsv)
    LOG_KEY=$(az monitor log-analytics workspace get-shared-keys --resource-group $RG --workspace-name log-orders --query primarySharedKey -o tsv)
    
    # The environment sits in a delegated subnet (Microsoft.App/environments) and only has internal addresses.
    az containerapp env create --name $ENV --resource-group $RG --location $LOC --enable-workload-profiles \
      --infrastructure-subnet-resource-id "$SUBNET_ID" --internal-only true \
      --logs-destination log-analytics --logs-workspace-id "$LOG_ID" --logs-workspace-key "$LOG_KEY"
    
    # One identity for the app: pulls images, writes receipts. No passwords anywhere.
    az identity create --resource-group $RG --name id-orders-api
    IDENTITY_ID=$(az identity show --resource-group $RG --name id-orders-api --query id -o tsv)
    PRINCIPAL_ID=$(az identity show --resource-group $RG --name id-orders-api --query principalId -o tsv)
    az role assignment create --assignee-object-id $PRINCIPAL_ID --assignee-principal-type ServicePrincipal \
      --role AcrPull --scope $(az acr show --name $ACR --query id -o tsv)
    az role assignment create --assignee-object-id $PRINCIPAL_ID --assignee-principal-type ServicePrincipal \
      --role "Storage Blob Data Contributor" --scope $(az storage account show --name $STORAGE --query id -o tsv)
    
    # The app: scales from one to ten replicas, one new replica per 50 concurrent requests.
    az containerapp create --name orders-api --resource-group $RG --environment $ENV \
      --image $ACR.azurecr.io/orders-api:1.4.2 --target-port 8080 --ingress external \
      --cpu 0.5 --memory 1Gi --min-replicas 1 --max-replicas 10 \
      --scale-rule-name http-load --scale-rule-type http --scale-rule-http-concurrency 50 \
      --user-assigned "$IDENTITY_ID" --registry-server $ACR.azurecr.io --registry-identity "$IDENTITY_ID" \
      --env-vars RECEIPT_ACCOUNT_URL=https://$STORAGE.blob.core.windows.net AZURE_CLIENT_ID=$(az identity show --ids "$IDENTITY_ID" --query clientId -o tsv) \
      --revisions-mode multiple --revision-suffix v142
    
    # Canary: deploy the next version with no traffic first, then send it 10 percent.
    az containerapp update --name orders-api --resource-group $RG --image $ACR.azurecr.io/orders-api:1.5.0 --revision-suffix v150
    az containerapp ingress traffic set --name orders-api --resource-group $RG --revision-weight orders-api--v142=90 orders-api--v150=10
    az containerapp revision list --name orders-api --resource-group $RG --output table
    
    # Nightly work from the same image: a cron job that costs nothing between runs.
    az containerapp job create --name orders-nightly --resource-group $RG --environment $ENV \
      --trigger-type Schedule --cron-expression "30 20 * * *" --replica-timeout 1800 --replica-retry-limit 2 \
      --image $ACR.azurecr.io/orders-api:1.4.2 --cpu 0.5 --memory 1Gi --args=--task=reconcile \
      --mi-user-assigned "$IDENTITY_ID" --registry-server $ACR.azurecr.io --registry-identity "$IDENTITY_ID"
    # Placeholders: pass in your own resource group, subnet, registry and storage account.
    variable "resource_group_name" {
      type    = string
      default = "rg-orders-apps"
    }
    
    variable "location" {
      type    = string
      default = "centralindia"
    }
    
    variable "infrastructure_subnet_id" {
      type = string
    }
    
    variable "registry_server" {
      type    = string
      default = "acrordersexample.azurecr.io"
    }
    
    variable "registry_id" {
      type = string
    }
    
    variable "storage_account_id" {
      type = string
    }
    
    resource "azurerm_log_analytics_workspace" "orders" {
      name                = "log-orders"
      location            = var.location
      resource_group_name = var.resource_group_name
      sku                 = "PerGB2018"
      retention_in_days   = 30
    }
    
    resource "azurerm_container_app_environment" "orders" {
      name                           = "cae-orders"
      location                       = var.location
      resource_group_name            = var.resource_group_name
      log_analytics_workspace_id     = azurerm_log_analytics_workspace.orders.id
      infrastructure_subnet_id       = var.infrastructure_subnet_id
      internal_load_balancer_enabled = true
    
      workload_profile {
        name                  = "Consumption"
        workload_profile_type = "Consumption"
      }
    }
    
    resource "azurerm_user_assigned_identity" "orders_api" {
      name                = "id-orders-api"
      location            = var.location
      resource_group_name = var.resource_group_name
    }
    
    resource "azurerm_role_assignment" "acr_pull" {
      scope                = var.registry_id
      role_definition_name = "AcrPull"
      principal_id         = azurerm_user_assigned_identity.orders_api.principal_id
    }
    
    resource "azurerm_role_assignment" "blob_writer" {
      scope                = var.storage_account_id
      role_definition_name = "Storage Blob Data Contributor"
      principal_id         = azurerm_user_assigned_identity.orders_api.principal_id
    }
    
    resource "azurerm_container_app" "orders_api" {
      name                         = "orders-api"
      resource_group_name          = var.resource_group_name
      container_app_environment_id = azurerm_container_app_environment.orders.id
      revision_mode                = "Multiple"
      workload_profile_name        = "Consumption"
    
      identity {
        type         = "UserAssigned"
        identity_ids = [azurerm_user_assigned_identity.orders_api.id]
      }
    
      registry {
        server   = var.registry_server
        identity = azurerm_user_assigned_identity.orders_api.id
      }
    
      ingress {
        external_enabled = true
        target_port      = 8080
    
        traffic_weight {
          latest_revision = true
          percentage      = 100
        }
      }
    
      template {
        min_replicas = 1
        max_replicas = 10
    
        http_scale_rule {
          name                = "http-load"
          concurrent_requests = "50"
        }
    
        container {
          name   = "api"
          image  = "${var.registry_server}/orders-api:1.4.2"
          cpu    = 0.5
          memory = "1Gi"
    
          env {
            name  = "AZURE_CLIENT_ID"
            value = azurerm_user_assigned_identity.orders_api.client_id
          }
        }
      }
    
      depends_on = [azurerm_role_assignment.acr_pull]
    }
    
    resource "azurerm_container_app_job" "nightly" {
      name                         = "orders-nightly"
      location                     = var.location
      resource_group_name          = var.resource_group_name
      container_app_environment_id = azurerm_container_app_environment.orders.id
      replica_timeout_in_seconds   = 1800
      replica_retry_limit          = 2
    
      identity {
        type         = "UserAssigned"
        identity_ids = [azurerm_user_assigned_identity.orders_api.id]
      }
    
      registry {
        server   = var.registry_server
        identity = azurerm_user_assigned_identity.orders_api.id
      }
    
      schedule_trigger_config {
        cron_expression = "30 20 * * *"
      }
    
      template {
        container {
          name   = "reconcile"
          image  = "${var.registry_server}/orders-api:1.4.2"
          args   = ["--task=reconcile"]
          cpu    = 0.5
          memory = "1Gi"
        }
      }
    }
    # Moves traffic between two revisions of a container app with the management SDK
    # (pip install azure-identity azure-mgmt-appcontainers). Usage: canary.py <subscription> <group> <app> <percent>
    import sys
    
    from azure.identity import DefaultAzureCredential
    from azure.mgmt.appcontainers import ContainerAppsAPIClient
    from azure.mgmt.appcontainers.models import TrafficWeight
    
    
    def shift(client, group, name, percent):
        app = client.container_apps.get(group, name)
        if app.configuration.active_revisions_mode != "Multiple":
            raise SystemExit("The app is in single-revision mode. Traffic splitting needs multiple mode.")
    
        live = [r for r in client.container_apps_revisions.list_revisions(group, name)
                if r.active and r.provisioning_state == "Provisioned"]
        live.sort(key=lambda r: r.created_time)
        if len(live) < 2:
            raise SystemExit("Need two healthy active revisions, found %d." % len(live))
    
        old, new = live[-2].name, live[-1].name
        app.configuration.ingress.traffic = [
            TrafficWeight(revision_name=old, weight=100 - percent),
            TrafficWeight(revision_name=new, weight=percent),
        ]
        client.container_apps.begin_create_or_update(group, name, app).result()
        return old, new
    
    
    if __name__ == "__main__":
        subscription, group, app_name, pct = sys.argv[1], sys.argv[2], sys.argv[3], int(sys.argv[4])
        if not 0 <= pct <= 100:
            raise SystemExit("percent must be between 0 and 100")
        api = ContainerAppsAPIClient(DefaultAzureCredential(), subscription)
        old, new = shift(api, group, app_name, pct)
        print("%s gets %d%%, %s gets %d%%" % (old, 100 - pct, new, pct))
    // dotnet add package Azure.ResourceManager.AppContainers
    // dotnet add package Azure.Identity
    // Lists the revisions of a container app and flags any that get traffic but have no running replica.
    using Azure.Identity;
    using Azure.ResourceManager;
    using Azure.ResourceManager.AppContainers;
    
    if (args.Length < 3) { Console.Error.WriteLine("Usage: revisions <subscription> <group> <app>"); return 2; }
    
    var arm = new ArmClient(new DefaultAzureCredential());
    var appId = ContainerAppResource.CreateResourceIdentifier(args[0], args[1], args[2]);
    ContainerAppResource app = arm.GetContainerAppResource(appId);
    
    int bad = 0;
    await foreach (ContainerAppRevisionResource rev in app.GetContainerAppRevisions().GetAllAsync())
    {
        var d = rev.Data;
        bool servesTraffic = (d.TrafficWeight ?? 0) > 0;
        bool noReplicas = (d.Replicas ?? 0) == 0;
        string flag = servesTraffic && noReplicas ? "  <-- gets traffic but has no replica" : "";
        if (flag.Length > 0) bad++;
        Console.WriteLine($"{d.Name,-28} active={d.IsActive,-5} traffic={d.TrafficWeight ?? 0,3}% replicas={d.Replicas ?? 0,2} health={d.HealthState}{flag}");
    }
    return bad == 0 ? 0 : 1;

    Best videos to explore

    Short walkthrough videos for this service are being prepared. They will appear here and load only when you press play. Until then, follow CloudBrum on YouTube for new videos.

    Introduction to Azure Container AppsVideo coming soon · Beginner
    Scale rules and scale to zero in Container AppsVideo coming soon · Intermediate
    Revisions and traffic splittingVideo coming soon · Intermediate
    Container Apps networking and workload profilesVideo coming soon · Advanced

    Interview questions

    BasicWhat is Azure Container Apps?

    It’s Microsoft’s serverless platform for running containers. You give it an image and some settings, and it runs the replicas, provides HTTPS ingress and scales them on traffic or events, including down to zero. There’s no cluster for you to manage.

    BasicWhat is a revision?

    A revision is an immutable snapshot of an app’s template: its containers, scale rules and similar settings. Each change to the template creates a new revision. In multiple-revision mode several can be active, and you split traffic between them by weight.

    BasicCan Container Apps scale to zero, and what does that cost?

    Yes. On the Consumption profile an app with a minimum of zero replicas bills no compute while idle, and the first request after a quiet period waits for a replica to start. Replicas kept at a minimum count bill a lower idle rate instead.

    IntermediateHow do you choose between the Consumption and Dedicated workload profiles?

    Choose Consumption for bursty, small or event-driven workloads, since it bills per second of use and has a free monthly grant. Choose Dedicated for steady or large loads, GPU needs or when you want reserved capacity, remembering that you pay for the whole node while it runs and a plan management fee applies.

    IntermediateHow does an app pull from Azure Container Registry without a password?

    Give the app a managed identity, grant that identity AcrPull on the registry, and configure the app’s registry with the identity instead of credentials. Then disable the registry’s admin user.

    IntermediateWhat is the difference between a container app and a job?

    An app runs continuously, has ingress and scales on traffic or events. A job runs to completion and stops. It can be started manually, on a cron schedule or by an event, it has no ingress, and it bills only while it runs.

    AdvancedHow would you roll out a new version of an API with a gradual canary?

    Use multiple-revision mode, deploy the new image with a revision suffix, and set traffic weights, for example 90% to the stable revision and 10% to the new one. Watch error rates, latency and logs, raise the weight in steps, then deactivate the old revision. Rollback is a weight change.

    AdvancedHow do KEDA scale rules differ from HTTP scale rules?

    HTTP rules scale on concurrent requests per replica and suit APIs. KEDA scalers watch an external source such as a Service Bus queue, Storage queue or Kafka topic and scale replicas on its length or lag, including to zero. They need metadata and authentication, usually through secrets or a managed identity.

    AdvancedHow would you make an internal-only Container Apps setup reachable from the internet in a controlled way?

    Keep the environment internal, in a delegated subnet of your virtual network, and put Azure Front Door or API Management (or Application Gateway) in front, with a private link or internal address to the environment. Add WAF rules and authentication at that layer, and restrict the app’s ingress to it.

    AdvancedWhere would you pick Azure Kubernetes Service over Container Apps?

    When you need Kubernetes itself: custom operators, daemonsets, specific CNI or network policy needs, admission control, fine control of nodes and upgrades, or an existing fleet and tooling. Container Apps suits teams that want containers, scaling and revisions without owning any of that.

    Similar or alternative services on other clouds

    CapabilityAWSAzureGoogle Cloud
    ServiceAWS App Runner (closed to new customers), or ECS Express ModeAzure Container AppsCloud Run
    Scale to zeroNo: App Runner keeps one provisioned instanceYes, on the Consumption profileYes, by default
    Scaling signalsConcurrent requestsHTTP, TCP, CPU, memory and KEDA event scalersConcurrent requests and CPU, plus min and max instances
    RolloutsWhole-service deploymentsRevisions with traffic weightsRevisions with traffic splitting and tags
    JobsNot in App RunnerManual, cron and event jobsCloud Run jobs
    Network integrationVPC connector (outgoing), private endpoint (incoming)Virtual network environment, internal ingressDirect VPC egress, internal ingress
    Identity for pulling and calling servicesAccess role and instance roleManaged identityService account
    Free allowanceNone for App Runner180,000 vCPU-seconds, 360,000 GiB-seconds and 2 million requests a month2 million requests and a vCPU and memory allowance a month

    If you need Kubernetes itself, look at Azure Kubernetes Service. For event-driven code with no container, use Azure Functions. A single batch container with no scaling fits Azure Container Instances, and a classic web app fits App Service. Images normally come from Azure Container Registry and files from Azure Blob Storage.

    Did you find this article helpful?

    Your answer helps us improve this page for the next reader.

    Sources and further reading

    CloudBrum wrote this page in its own words, using the provider’s public documentation listed below as the reference. Features, limits, names and prices change, so confirm anything that matters on the provider’s own pages before you decide.