Documentation
how-to/deploy.md
How to Deploy Dynaplex
This guide covers deploying Dynaplex applications using .NET Aspire to various environments.
Deployment Options
- Azure Container Apps (Recommended) - Managed containers with Aspire support
- Docker Compose - Self-hosted containers
- Kubernetes - Advanced orchestration
- Azure App Service - Traditional PaaS
Azure Container Apps (Recommended)
.NET Aspire has first-class support for Azure Container Apps.
Prerequisites
# Install Azure CLI
brew install azure-cli # macOS
# or download from https://aka.ms/installazurecliwindows
# Install Aspire workload
dotnet workload install aspire
# Login to Azure
az login
Deploy with Aspire
# Navigate to AppHost project
cd projects/bbu-rfid/src/Acsis.Dynaplex.Projects.BbuRfid/
# Deploy to Azure
azd init
azd up
# Follow prompts to:
# 1. Choose subscription
# 2. Select region
# 3. Name your deployment
Aspire automatically:
- Creates Azure Container Apps for each service
- Provisions PostgreSQL databases
- Configures service-to-service communication
- Sets up Application Insights
- Configures health checks
Access Your Deployment
# Get deployment URL
azd env get-values
# View logs
az containerapp logs show --name core-data --resource-group <your-rg>
# Monitor in Azure Portal
open https://portal.azure.com
Docker Deployment
Build Docker Images
Each service can be containerized:
Dockerfile for a component service:
# engines/core-data/Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /src
# Copy project files
COPY ["engines/core-data/src/Acsis.Dynaplex.Engines.CoreData/", "engines/core-data/src/Acsis.Dynaplex.Engines.CoreData/"]
COPY ["engines/core-data/src/Acsis.Dynaplex.Engines.CoreData.Abstractions/", "engines/core-data/src/Acsis.Dynaplex.Engines.CoreData.Abstractions/"]
COPY ["Directory.Build.props", "./"]
# Restore and build
RUN dotnet restore "engines/core-data/src/Acsis.Dynaplex.Engines.CoreData/Acsis.Dynaplex.Engines.CoreData.csproj"
RUN dotnet build "engines/core-data/src/Acsis.Dynaplex.Engines.CoreData/Acsis.Dynaplex.Engines.CoreData.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "engines/core-data/src/Acsis.Dynaplex.Engines.CoreData/Acsis.Dynaplex.Engines.CoreData.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Acsis.Dynaplex.Engines.CoreData.dll"]
Docker Compose
docker-compose.yml:
version: '3.8'
services:
postgres:
image: postgres:16
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: acsis
volumes:
- postgres-data:/var/lib/postgresql/data
ports:
- "5432:5432"
core-data:
build:
context: .
dockerfile: engines/core-data/Dockerfile
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ConnectionStrings__DefaultConnection=Host=postgres;Database=acsis;Username=postgres;Password=${POSTGRES_PASSWORD}
ports:
- "40443:443"
depends_on:
- postgres
identity:
build:
context: .
dockerfile: engines/identity/Dockerfile
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ConnectionStrings__DefaultConnection=Host=postgres;Database=acsis;Username=postgres;Password=${POSTGRES_PASSWORD}
- CoreDataApiUrl=https://core-data
ports:
- "41443:443"
depends_on:
- core-data
volumes:
postgres-data:
Deploy:
# Build images
docker-compose build
# Start services
docker-compose up -d
# View logs
docker-compose logs -f
# Stop services
docker-compose down
Kubernetes Deployment
Generate Kubernetes Manifests
Aspire can generate K8s manifests:
# Install Aspire manifest tool
dotnet tool install -g aspirate
# Generate manifests
cd projects/bbu-rfid/src/Acsis.Dynaplex.Projects.BbuRfid/
aspirate generate
Deploy to Kubernetes
# Apply manifests
kubectl apply -f aspir8-output/
# Check deployment
kubectl get pods
kubectl get services
# View logs
kubectl logs -f deployment/core-data
# Port forward to access locally
kubectl port-forward service/core-data 40443:443
CI/CD Pipelines
GitHub Actions
.github/workflows/deploy.yml:
name: Deploy to Azure
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'
- name: Install Aspire workload
run: dotnet workload install aspire
- name: Azure Login
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: Deploy to Azure
run: |
cd projects/bbu-rfid/src/Acsis.Dynaplex.Projects.BbuRfid/
azd deploy --no-prompt
env:
AZURE_ENV_NAME: ${{ secrets.AZURE_ENV_NAME }}
AZURE_LOCATION: ${{ secrets.AZURE_LOCATION }}
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
Azure DevOps
azure-pipelines.yml:
trigger:
branches:
include:
- main
pool:
vmImage: 'ubuntu-latest'
steps:
- task: UseDotNet@2
inputs:
packageType: 'sdk'
version: '9.0.x'
- script: dotnet workload install aspire
displayName: 'Install Aspire workload'
- task: AzureCLI@2
inputs:
azureSubscription: 'your-service-connection'
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
cd projects/bbu-rfid/src/Acsis.Dynaplex.Projects.BbuRfid/
azd deploy --no-prompt
Environment Configuration
Development
// appsettings.Development.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"ConnectionStrings": {
"DefaultConnection": "Host=localhost;Database=acsis;Username=postgres;Password=dev"
}
}
Production
// appsettings.Production.json
{
"Logging": {
"LogLevel": {
"Default": "Warning",
"Microsoft.AspNetCore": "Error"
}
},
"ConnectionStrings": {
"DefaultConnection": "${CONNECTIONSTRING}" // Injected by Azure
}
}
Secrets Management
Azure Key Vault:
# Create Key Vault
az keyvault create --name acsis-kv --resource-group acsis-rg
# Add secrets
az keyvault secret set --vault-name acsis-kv --name "ConnectionString" --value "your-connection-string"
# Grant access to managed identity
az keyvault set-policy --name acsis-kv \
--object-id <managed-identity-id> \
--secret-permissions get list
In code:
// Program.cs
builder.Configuration.AddAzureKeyVault(
new Uri($"https://{builder.Configuration["KeyVaultName"]}.vault.azure.net/"),
new DefaultAzureCredential());
Monitoring & Observability
Application Insights
Aspire automatically configures Application Insights:
// Already configured by Aspire ServiceDefaults
builder.AddServiceDefaults();
View Telemetry
# View in Azure Portal
open https://portal.azure.com
# Navigate to: Application Insights > your-app > Logs
# Query example
requests
| where timestamp > ago(1h)
| summarize count() by name
| order by count_ desc
Health Checks
# Check service health
curl https://your-app.azurecontainerapps.io/health
# View in Aspire Dashboard
curl https://your-app.azurecontainerapps.io/health/ready
Scaling
Azure Container Apps
# Scale manually
az containerapp update \
--name core-data \
--resource-group acsis-rg \
--min-replicas 2 \
--max-replicas 10
# Auto-scale based on HTTP requests
az containerapp update \
--name core-data \
--resource-group acsis-rg \
--scale-rule-name http-scale \
--scale-rule-http-concurrency 50
Kubernetes
# Scale deployment
kubectl scale deployment core-data --replicas=3
# Auto-scale
kubectl autoscale deployment core-data \
--min=2 --max=10 \
--cpu-percent=70
Rollback
Azure Container Apps
# List revisions
az containerapp revision list \
--name core-data \
--resource-group acsis-rg
# Activate previous revision
az containerapp revision activate \
--name core-data \
--resource-group acsis-rg \
--revision <previous-revision-name>
Kubernetes
# Rollback deployment
kubectl rollout undo deployment/core-data
# Check rollout status
kubectl rollout status deployment/core-data
Troubleshooting
View Logs
Azure Container Apps:
az containerapp logs show \
--name core-data \
--resource-group acsis-rg \
--follow
Docker:
docker logs -f core-data
Kubernetes:
kubectl logs -f deployment/core-data
Common Issues
Service can't reach database:
- Check connection strings
- Verify database exists
- Check network security rules
Service returns 503:
- Check health endpoint:
/health - Verify dependencies are running
- Check Application Insights for errors
High memory usage:
- Review telemetry in Application Insights
- Check for memory leaks
- Scale horizontally
Best Practices
✅ Use Aspire for Azure Container Apps deployment
✅ Enable health checks on all services
✅ Use managed identities for Azure resources
✅ Store secrets in Azure Key Vault
✅ Enable Application Insights for all services
✅ Use horizontal scaling for high availability
✅ Test deployments in staging environment first
✅ Implement rollback strategy
✅ Monitor costs in Azure Portal
Next Steps
- Operations guide - Running in production
- Monitoring guide - Observability
- Troubleshooting - Common issues