This guide explains the container-based deployment infrastructure for TrashMob applications.
The TrashMob infrastructure has been enhanced to support containerized deployments using Azure Container Apps. This includes:
- Azure Container Registry (ACR) - Stores Docker images
- Azure Container Apps Environment - Hosting environment for containers
- Azure Container App - Runs the TrashMob web application
- Azure Container App Job - Runs TrashMobJobs on a schedule
Creates an Azure Container Registry to store Docker images.
Parameters:
region- Azure regioncontainerRegistryName- Name of the registry (e.g., acrtmdevwestus2)environment- Environment tag (dev, staging, prod)
Creates the Container Apps Environment with Log Analytics integration.
Parameters:
region- Azure regioncontainerAppsEnvironmentName- Name of the environmentlogAnalyticsWorkspaceName- Existing Log Analytics workspace nameenvironment- Environment tag
Deploys the TrashMob web application as a Container App.
Parameters:
region- Azure regioncontainerAppName- Name of the container appcontainerAppsEnvironmentId- Resource ID of the Container Apps EnvironmentcontainerRegistryName- ACR namecontainerImage- Full image name (e.g., acrtmdevwestus2.azurecr.io/trashmob:latest)keyVaultName- Key Vault name for secretsenvironment- Environment tagminReplicas- Minimum number of replicas (default: 1)maxReplicas- Maximum number of replicas (default: 3)
Features:
- Auto-scaling based on HTTP requests
- System-assigned managed identity
- Key Vault integration for secrets
- Exposes port 8080 with HTTPS
Deploys TrashMobJobs as a scheduled Container App Job.
Parameters:
region- Azure regioncontainerAppJobName- Name of the container app jobcontainerAppsEnvironmentId- Resource ID of the Container Apps EnvironmentcontainerRegistryName- ACR namecontainerImage- Full image namekeyVaultName- Key Vault nameazureMapsName- Azure Maps account namestorageAccountName- Storage account nameenvironment- Environment tagcronExpression- Cron schedule (default: every 6 hours)
Features:
- Scheduled execution via cron
- System-assigned managed identity
- Key Vault integration
- 30-minute timeout per execution
TrashMob Web App (TrashMob/Dockerfile)
Multi-stage Docker build:
- Build stage - Installs Node.js, builds React app, compiles .NET app
- Publish stage - Creates production build
- Runtime stage - Uses minimal ASP.NET runtime image
Exposed Ports: 8080, 8081
TrashMobJobs (TrashMobJobs/Dockerfile)
Multi-stage Docker build for the jobs service.
Builds and deploys the TrashMob web application as a container to the dev environment.
Triggers:
- Push to
mainbranch affecting TrashMob files - Manual workflow dispatch
Environment: dev Resources: ca-tm-dev-westus2, acrtmdevwestus2 Scaling: 1-3 replicas
Steps:
- Checkout code with GitVersion
- Login to Azure using OIDC
- Build and push Docker image to ACR (with version tag and latest)
- Deploy to Container App using bicep template
- Output Container App URL
Builds and deploys TrashMobJobs as a scheduled container job to the dev environment.
Triggers:
- Push to
mainbranch affecting TrashMobJobs files - Manual workflow dispatch
Environment: dev Resources: caj-tm-dev-westus2, acrtmdevwestus2 Schedule: Every 6 hours
Steps:
- Checkout code with GitVersion
- Login to Azure using OIDC
- Build and push Docker image to ACR
- Deploy to Container App Job using bicep template
- Verify job configuration
Builds and deploys the TrashMob web application as a container to the production environment.
Triggers:
- Push to
releasebranch affecting TrashMob files - Manual workflow dispatch
Environment: pr (production) Resources: ca-tm-pr-westus2, acrtmprwestus2 Scaling: 2-10 replicas (higher capacity for production)
Steps:
- Checkout code with GitVersion
- Login to Azure using OIDC
- Build and push Docker image to ACR (with version tag and latest)
- Deploy to Container App using bicep template
- Output Container App URL
Builds and deploys TrashMobJobs as a scheduled container job to the production environment.
Triggers:
- Push to
releasebranch affecting TrashMobJobs files - Manual workflow dispatch
Environment: pr (production) Resources: caj-tm-pr-westus2, acrtmprwestus2 Schedule: Every 6 hours
Steps:
- Checkout code with GitVersion
- Login to Azure using OIDC
- Build and push Docker image to ACR
- Deploy to Container App Job using bicep template
- Verify job configuration
-
Deploy Infrastructure
Run the updated
deployInfra.ps1script:cd Deploy .\deployInfra.ps1 -environment dev -region westus2 -subscriptionId <your-subscription-id> -sqlAdminPassword "<password>" -alwaysOn $False
This will create:
- All existing resources (SQL, Key Vault, Storage, etc.)
- Azure Container Registry
- Azure Container Apps Environment
-
Configure GitHub Secrets
Ensure these secrets are configured in your GitHub repository:
AZURE_CLIENT_ID- Service principal client IDAZURE_TENANT_ID- Azure AD tenant IDAZURE_SUBSCRIPTION_ID- Azure subscription ID
-
Deploy Containers
The GitHub Actions workflows will automatically deploy when you push to main, or you can manually trigger them:
- Go to Actions tab in GitHub
- Select the workflow
- Click "Run workflow"
For the dev environment in westus2 region:
| Resource Type | Dev Environment | Production Environment |
|---|---|---|
| Container Registry | acrtmdevwestus2 |
acrtmprwestus2 |
| Container Apps Environment | cae-tm-dev-westus2 |
cae-tm-pr-westus2 |
| Container App (Web) | ca-tm-dev-westus2 |
ca-tm-pr-westus2 |
| Container App Job | caj-tm-dev-westus2 |
caj-tm-pr-westus2 |
| Resource Group | rg-trashmob-dev-westus2 |
rg-trashmob-pr-westus2 |
| Key Vault | kv-tm-dev-westus2 |
kv-tm-pr-westus2 |
| Log Analytics | log-tm-dev-westus2 |
log-tm-pr-westus2 |
Note: Container Registry names cannot contain hyphens, hence the different naming pattern.
Both containers use these environment variables:
ASPNETCORE_ENVIRONMENT=ProductionVaultUri=https://<keyvault-name>.vault.azure.netStorageAccountUri=https://<storage-account-name>.blob.core.windows.net/ApplicationInsights__ConnectionString- Retrieved from the environment-specific Application Insights resourceASPNETCORE_HTTP_PORTS=8080(Web App only)EnableSwagger=true/false(Web App only, based on environment)InstanceName=as-tm-<env>-<region>(Jobs only)
Azure AD Entra External ID configuration (public values, set based on environment parameter in Bicep):
AzureAdEntra__Instance- Entra login endpoint (e.g., https://trashmobecodev.ciamlogin.com/)AzureAdEntra__ClientId- Backend API client ID for JWT validationAzureAdEntra__FrontendClientId- Frontend SPA client ID for MSALAzureAdEntra__Domain- Entra tenant domain (e.g., TrashMobEcoDev.onmicrosoft.com)AzureAdEntra__TenantId- Entra tenant ID
Secrets are retrieved from Key Vault using managed identity:
AzureMapsKeyTMDBServerConnectionStringStorageAccountKeysendGridApiKey
- Min Replicas: 1
- Max Replicas: 3
- Scaling Rule: HTTP concurrent requests (100 requests per instance)
- Resources per instance: 0.5 CPU, 1GB memory
- Execution: Scheduled (every 6 hours by default)
- Parallelism: 1 (one execution at a time)
- Timeout: 30 minutes
- Retry Limit: 1
- Resources: 0.5 CPU, 1GB memory
Azure Container Apps pricing is based on:
- vCPU-seconds and GiB-seconds consumed
- Number of HTTP requests (web app)
- Number of executions (jobs)
The current configuration uses minimal resources (0.5 CPU, 1GB RAM) which is cost-effective for development environments.
All containers send logs to the Log Analytics workspace configured in the Container Apps Environment.
View logs:
# Web App logs
az containerapp logs show --name ca-tm-dev-westus2 --resource-group rg-trashmob-dev-westus2 --follow
# Job execution history
az containerapp job execution list --name caj-tm-dev-westus2 --resource-group rg-trashmob-dev-westus2- Check container logs in Log Analytics
- Verify Key Vault permissions for managed identity
- Ensure environment variables are correct
- Verify Dockerfile paths are correct
- Check that all project references are included
- Ensure Node.js dependencies can be resolved
- Verify cron expression is correct
- Check job execution history
- Review container logs for errors
The original App Service and Function App deployments remain in the infrastructure. You can:
- Run both in parallel - Test containers while keeping existing deployments
- Gradual migration - Move traffic from App Service to Container App gradually
- Complete switch - Update DNS/routing once containers are validated
To switch traffic, update your DNS or Front Door configuration to point to the Container App FQDN instead of the App Service URL.
- Run
deployInfra.ps1to create the container infrastructure - Trigger the GitHub Actions workflows to build and deploy containers
- Test the Container App URL to verify the web app works
- Monitor the Container App Job executions
- Consider removing App Service/Function App resources once containers are validated
After deploying to production, complete these manual steps:
-
Upload TrashMob.eco Waiver - Log into the production admin portal and upload/create the global TrashMob.eco waiver document in the Waiver Management section. This is required for users to sign waivers before attending events.
-
Verify database migrations ran successfully
-
Test user authentication flow
-
Verify email notifications are working
-
Check Application Insights for any startup errors
-
Review Google Search Console - Visit Google Search Console to check for any remaining site issues (mobile usability, indexing problems, etc.)
-
Check Job Logs for Daily Summary Report - Review the Container App Job logs to verify the daily summary report is still being generated. Run:
az containerapp job execution list --name caj-tm-pr-westus2 --resource-group rg-trashmob-pr-westus2to see recent executions, then check the logs for any errors.