Deploy
Digest deploys to Azure Container Apps with one command. Aspire generates the infrastructure (Bicep), builds the containers, pushes them to the registry and deploys them.
One-time setup
Sign in to the Azure CLI on the tenant and subscription to deploy to:
az login --tenant <tenant id>Pin the target in AppHost user secrets:
aspire secret set "Azure:SubscriptionId" "<subscription id>" aspire secret set "Azure:TenantId" "<tenant id>" aspire secret set "Azure:Location" "<region, for example centralus>" aspire secret set "Azure:ResourceGroup" "rg-aspire-digest" aspire secret set "Azure:CredentialSource" "AzureCli"Register the resource providers once per subscription:
Microsoft.App,Microsoft.ContainerRegistry,Microsoft.ContainerInstance,Microsoft.KeyVault,Microsoft.ManagedIdentity,Microsoft.OperationalInsights,Microsoft.ServiceBus,Microsoft.Sql,Microsoft.Storage.
Deploy
aspire deploy runs the AppHost in the Production environment, which does not read user secrets. Pass them as environment variables instead. From the repository root in PowerShell:
$secrets = (dotnet user-secrets list --json --project src/Digest.AppHost | Where-Object { $_ -notmatch '^//' }) -join "`n" | ConvertFrom-Json
foreach ($p in $secrets.PSObject.Properties | Where-Object Name -match '^(Parameters|Azure):') {
[Environment]::SetEnvironmentVariable($p.Name.Replace(':', '__'), [string]$p.Value, 'Process')
}
aspire deploy
The web app applies database migrations when it starts.
On the first deploy the summarizer can fail to read Key Vault while its new role assignment takes effect. Run aspire deploy again a few minutes later.
What gets created
| Resource | Tier |
|---|---|
| Container Apps environment, with the Aspire dashboard | Consumption |
Container apps web and summarizer (Functions on Container Apps) |
Consumption, scale to zero |
| Container Registry | Basic |
| Azure SQL Database | Free offer, pauses after an hour idle |
Service Bus namespace with the links queue |
Basic |
| Storage account (Functions host) | Standard LRS |
| Key Vault holding the secrets, read by each app's managed identity | Standard |
| Log Analytics workspace | Pay-as-you-go |
Apps reach SQL, Service Bus, Storage and Key Vault with managed identities. No connection-string secrets are deployed.
The first request after a quiet spell takes up to a minute while the database resumes and the web app starts.
Deployment profiles
Set DeploymentProfile before deploying:
| Profile | Web | Summarizer |
|---|---|---|
minimal (default) |
0 to 1 replica, 0.25 vCPU, 0.5 GiB | 0 to 1 replica, 0.5 vCPU, 1 GiB |
scalable |
1 to 5 replicas, HTTP scale rule at 50 concurrent requests | 0 to 10 replicas on queue length |
DeploymentProfile=scalable aspire deploy
$env:DeploymentProfile = "scalable"; aspire deploy
The dashboard shows each app's replicas as one instance, so with scalable it does not tell them apart.
Real scale also needs more Azure SQL vCores, Service Bus Standard, and Redis for a shared cache and rate limits across replicas.
Custom domain
Add two DNS records, without a proxy:
- a CNAME from the host to the web app's Container Apps address
- a TXT record
asuid.<host>with the environment'scustomDomainConfiguration.customDomainVerificationId
Bind the host and create a free managed certificate:
az containerapp hostname add --hostname <host> -g rg-aspire-digest -n web az containerapp hostname bind --hostname <host> -g rg-aspire-digest -n web --environment <environment> --validation-method CNAMESave the host and certificate name so every deploy keeps the binding:
aspire secret set "Parameters:custom-domain" "<host>" aspire secret set "Parameters:certificate-name" "<managed certificate name>"
Teardown
aspire destroy
It lists the Azure resources, asks for confirmation and deletes the resource group. Key Vault keeps a soft-deleted copy for 90 days at no cost.