azd-deployment
Deploy containerized frontend + backend applications to Azure Container Apps with remote builds, managed identity, and idempotent infrastructure.
- risk
- unknown
- source
- community
- date added
- 2026-02-27
Azure Developer CLI (azd) Container Apps Deployment
Deploy containerized frontend + backend applications to Azure Container Apps with remote builds, managed identity, and idempotent infrastructure.
Quick Start
# Initialize and deploy azd auth login azd init # Creates azure.yaml and .azure/ folder azd env new <env-name> # Create environment (dev, staging, prod) azd up # Provision infra + build + deploy
Core File Structure
project/ ├── azure.yaml # azd service definitions + hooks ├── infra/ │ ├── main.bicep # Root infrastructure module │ ├── main.parameters.json # Parameter injection from env vars │ └── modules/ │ ├── container-apps-environment.bicep │ └── container-app.bicep ├── .azure/ │ ├── config.json # Default environment pointer │ └── <env-name>/ │ ├── .env # Environment-specific values (azd-managed) │ └── config.json # Environment metadata └── src/ ├── frontend/Dockerfile └── backend/Dockerfile
azure.yaml Configuration
Minimal Configuration
name: azd-deployment services: backend: project: ./src/backend language: python host: containerapp docker: path: ./Dockerfile remoteBuild: true
Full Configuration with Hooks
name: azd-deployment metadata: template: my-project@1.0.0 infra: provider: bicep path: ./infra azure: location: eastus2 services: frontend: project: ./src/frontend language: ts host: containerapp docker: path: ./Dockerfile context: . remoteBuild: true backend: project: ./src/backend language: python host: containerapp docker: path: ./Dockerfile context: . remoteBuild: true hooks: preprovision: shell: sh run: | echo "Before provisioning..." postprovision: shell: sh run: | echo "After provisioning - set up RBAC, etc." postdeploy: shell: sh run: | echo "Frontend: ${SERVICE_FRONTEND_URI}" echo "Backend: ${SERVICE_BACKEND_URI}"
Key azure.yaml Options
| Option | Description |
|---|---|
remoteBuild: true | Build images in Azure Container Registry (recommended) |
context: . | Docker build context relative to project path |
host: containerapp | Deploy to Azure Container Apps |
infra.provider: bicep | Use Bicep for infrastructure |
Environment Variables Flow
Three-Level Configuration
- Local
.env- For local development only .azure/<env>/.env- azd-managed, auto-populated from Bicep outputsmain.parameters.json- Maps env vars to Bicep parameters
Parameter Injection Pattern
// infra/main.parameters.json { "parameters": { "environmentName": { "value": "${AZURE_ENV_NAME}" }, "location": { "value": "${AZURE_LOCATION=eastus2}" }, "azureOpenAiEndpoint": { "value": "${AZURE_OPENAI_ENDPOINT}" } } }
Syntax: ${VAR_NAME} or ${VAR_NAME=default_value}
Setting Environment Variables
# Set for current environment azd env set AZURE_OPENAI_ENDPOINT "https://my-openai.openai.azure.com" azd env set AZURE_SEARCH_ENDPOINT "https://my-search.search.windows.net" # Set during init azd env new prod azd env set AZURE_OPENAI_ENDPOINT "..."
Bicep Output → Environment Variable
// In main.bicep - outputs auto-populate .azure/<env>/.env output SERVICE_FRONTEND_URI string = frontend.outputs.uri output SERVICE_BACKEND_URI string = backend.outputs.uri output BACKEND_PRINCIPAL_ID string = backend.outputs.principalId
Idempotent Deployments
Why azd up is Idempotent
- Bicep is declarative - Resources reconcile to desired state
- Remote builds tag uniquely - Image tags include deployment timestamp
- ACR reuses layers - Only changed layers upload
Preserving Manual Changes
Custom domains added via Portal can be lost on redeploy. Preserve with hooks:
hooks: preprovision: shell: sh run: | # Save custom domains before provision if az containerapp show --name "$FRONTEND_NAME" -g "$RG" &>/dev/null; then az containerapp show --name "$FRONTEND_NAME" -g "$RG" \ --query "properties.configuration.ingress.customDomains" \ -o json > /tmp/domains.json fi postprovision: shell: sh run: | # Verify/restore custom domains if [ -f /tmp/domains.json ]; then echo "Saved domains: $(cat /tmp/domains.json)" fi
Handling Existing Resources
// Reference existing ACR (don't recreate) resource containerRegistry 'Microsoft.ContainerRegistry/registries@2023-07-01' existing = { name: containerRegistryName } // Set customDomains to null to preserve Portal-added domains customDomains: empty(customDomainsParam) ? null : customDomainsParam
Container App Service Discovery
Internal HTTP routing between Container Apps in same environment:
// Backend reference in frontend env vars env: [ { name: 'BACKEND_URL' value: 'http://ca-backend-${resourceToken}' // Internal DNS } ]
Frontend nginx proxies to internal URL:
location /api { proxy_pass $BACKEND_URL; }
Managed Identity & RBAC
Enable System-Assigned Identity
resource containerApp 'Microsoft.App/containerApps@2024-03-01' = { identity: { type: 'SystemAssigned' } } output principalId string = containerApp.identity.principalId
Post-Provision RBAC Assignment
hooks: postprovision: shell: sh run: | PRINCIPAL_ID="${BACKEND_PRINCIPAL_ID}" # Azure OpenAI access az role assignment create \ --assignee-object-id "$PRINCIPAL_ID" \ --assignee-principal-type ServicePrincipal \ --role "Cognitive Services OpenAI User" \ --scope "$OPENAI_RESOURCE_ID" 2>/dev/null || true # Azure AI Search access az role assignment create \ --assignee-object-id "$PRINCIPAL_ID" \ --role "Search Index Data Reader" \ --scope "$SEARCH_RESOURCE_ID" 2>/dev/null || true
Common Commands
# Environment management azd env list # List environments azd env select <name> # Switch environment azd env get-values # Show all env vars azd env set KEY value # Set variable # Deployment azd up # Full provision + deploy azd provision # Infrastructure only azd deploy # Code deployment only azd deploy --service backend # Deploy single service # Debugging azd show # Show project status az containerapp logs show -n <app> -g <rg> --follow # Stream logs
Reference Files
- Bicep patterns: See references/bicep-patterns.md for Container Apps modules
- Troubleshooting: See references/troubleshooting.md for common issues
- azure.yaml schema: See references/azure-yaml-schema.md for full options
Critical Reminders
- Always use
remoteBuild: true- Local builds fail on M1/ARM Macs deploying to AMD64 - Bicep outputs auto-populate .azure/<env>/.env - Don't manually edit
- Use
azd env setfor secrets - Not main.parameters.json defaults - Service tags (
azd-service-name) - Required for azd to find Container Apps || truein hooks - Prevent RBAC "already exists" errors from failing deploy
When to Use
This skill is applicable to execute the workflow or actions described in the overview.