docker-containers
Multi-container .NET applications with Docker Compose, container orchestration, and development environments
Works with
---
name: docker-containers
description: Multi-container .NET applications with Docker Compose, container orchestration, and development environments
license: MIT
---
# Multi-Container .NET Applications
## Multi-Stage Dockerfile (.NET 10)
```dockerfile
# Build stage
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
# Copy solution and project files for layer caching
COPY *.sln .
COPY Directory.Build.props Directory.Packages.props ./
COPY src/MyApp.Web/MyApp.Web.csproj src/MyApp.Web/
COPY src/MyApp.Api/MyApp.Api.csproj src/MyApp.Api/
COPY src/MyApp.Domain/MyApp.Domain.csproj src/MyApp.Domain/
COPY src/MyApp.Infrastructure/MyApp.Infrastructure.csproj src/MyApp.Infrastructure/
RUN dotnet restore
# Copy source and publish
COPY . .
RUN dotnet publish src/MyApp.Web/MyApp.Web.csproj -c Release -o /app/publish --no-restore
# Runtime stage (minimal image)
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime
WORKDIR /app
EXPOSE 8080
ENV ASPNETCORE_URLS=http://+:8080
ENV DOTNET_RUNNING_IN_CONTAINER=true
# Non-root user for security
USER $APP_UID
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "MyApp.Web.dll"]
```
## Docker Compose (Development)
```yaml
services:
# Blazor Web App
webapp:
build:
context: .
dockerfile: src/MyApp.Web/Dockerfile
ports:
- "5000:8080"
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ConnectionStrings__Default=Host=postgres;Database=myapp;Username=postgres;Password=devpass
- ConnectionStrings__Redis=redis:6379
- RabbitMQ__Host=rabbitmq
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
volumes:
- ~/.aspnet/https:/https:ro # Dev HTTPS certs
networks:
- backend
# API Service
api:
build:
context: .
dockerfile: src/MyApp.Api/Dockerfile
ports:
- "5001:8080"
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ConnectionStrings__Default=Host=postgres;Database=myapp;Username=postgres;Password=devpass
- ConnectionStrings__Redis=redis:6379
depends_on:
postgres:
condition: service_healthy
networks:
- backend
# Worker Service
worker:
build:
context: .
dockerfile: src/MyApp.Worker/Dockerfile
environment:
- ConnectionStrings__Default=Host=postgres;Database=myapp;Username=postgres;Password=devpass
- RabbitMQ__Host=rabbitmq
depends_on:
postgres:
condition: service_healthy
rabbitmq:
condition: service_healthy
networks:
- backend
# PostgreSQL
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: postgres
POSTGRES_PASSWORD: devpass
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
networks:
- backend
# Redis
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
networks:
- backend
# RabbitMQ
rabbitmq:
image: rabbitmq:3-management-alpine
ports:
- "5672:5672" # AMQP
- "15672:15672" # Management UI
environment:
RABBITMQ_DEFAULT_USER: guest
RABBITMQ_DEFAULT_PASS: guest
healthcheck:
test: ["CMD", "rabbitmq-diagnostics", "check_port_connectivity"]
interval: 10s
timeout: 5s
retries: 5
networks:
- backend
# SQL Server (alternative to PostgreSQL)
# sqlserver:
# image: mcr.microsoft.com/mssql/server:2022-latest
# environment:
# ACCEPT_EULA: "Y"
# MSSQL_SA_PASSWORD: "YourStrong!Password"
# ports:
# - "1433:1433"
volumes:
postgres_data:
redis_data:
networks:
backend:
driver: bridge
```
## Integration Event Bus (RabbitMQ)
```csharp
// Integration event (crosses service boundaries)
public sealed record OrderPaymentSucceededIntegrationEvent(
int OrderId, DateTime PaymentDate) : IntegrationEvent;
// Event bus interface
public interface IEventBus
{
Task PublishAsync<T>(T @event, CancellationToken ct = default) where T : IntegrationEvent;
void Subscribe<T, THandler>() where T : IntegrationEvent where THandler : IIntegrationEventHandler<T>;
}
// Integration event handler
public sealed class OrderPaymentSucceededHandler(
IOrderRepository orderRepo,
ILogger<OrderPaymentSucceededHandler> logger)
: IIntegrationEventHandler<OrderPaymentSucceededIntegrationEvent>
{
public async Task Handle(OrderPaymentSucceededIntegrationEvent @event, CancellationToken ct)
{
logger.LogInformation("Payment succeeded for order {OrderId}", @event.OrderId);
var order = await orderRepo.GetAsync(@event.OrderId, ct);
order?.SetPaidStatus();
await orderRepo.UnitOfWork.SaveEntitiesAsync(ct);
}
}
```
## API Gateway Pattern
```csharp
// Using YARP (Yet Another Reverse Proxy) - Microsoft's recommended gateway
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddReverseProxy()
.LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
var app = builder.Build();
app.MapReverseProxy();
app.Run();
```
```json
// appsettings.json for YARP
{
"ReverseProxy": {
"Routes": {
"catalog-route": {
"ClusterId": "catalog-cluster",
"Match": { "Path": "/api/catalog/{**catch-all}" }
},
"ordering-route": {
"ClusterId": "ordering-cluster",
"Match": { "Path": "/api/orders/{**catch-all}" }
}
},
"Clusters": {
"catalog-cluster": {
"Destinations": {
"destination1": { "Address": "http://catalog-api:8080/" }
}
},
"ordering-cluster": {
"Destinations": {
"destination1": { "Address": "http://ordering-api:8080/" }
}
}
}
}
}
```
## .NET Docker Images
| Image | Use for | Size |
|-------|---------|------|
| `mcr.microsoft.com/dotnet/sdk:10.0` | Build stage only | ~800MB |
| `mcr.microsoft.com/dotnet/aspnet:10.0` | Web apps, APIs | ~220MB |
| `mcr.microsoft.com/dotnet/runtime:10.0` | Console/worker apps | ~190MB |
| `mcr.microsoft.com/dotnet/runtime-deps:10.0` | Self-contained AOT | ~110MB |
## Best Practices
- Use multi-stage builds (build with SDK, run with aspnet/runtime)
- Copy .csproj files first for Docker layer caching on restore
- Use health checks in docker-compose for dependency ordering
- Run as non-root user in production containers
- Use `.dockerignore` to exclude bin/, obj/, .git/
- Pin image versions (never use `:latest` alone in production)
- Use named volumes for persistent data
## Reference
- Multi-container apps: https://learn.microsoft.com/en-us/dotnet/architecture/microservices/multi-container-microservice-net-applications/
- Docker Compose: https://learn.microsoft.com/en-us/dotnet/architecture/microservices/multi-container-microservice-net-applications/multi-container-applications-docker-compose
- Official Docker images: https://learn.microsoft.com/en-us/dotnet/architecture/microservices/net-core-net-framework-containers/official-net-docker-images
- RabbitMQ event bus: https://learn.microsoft.com/en-us/dotnet/architecture/microservices/multi-container-microservice-net-applications/rabbitmq-event-bus-development-test-environment
- API gateways: https://learn.microsoft.com/en-us/dotnet/architecture/microservices/multi-container-microservice-net-applications/implement-api-gateways-with-ocelotMore DevOps & Infrastructure skills
azure-ai
microsoft/azure-skills
Use for Azure AI: Search, Speech, OpenAI, Document Intelligence. Helps with search, vector/hybrid search, speech-to-text, text-to-speech, transcription, OCR. WHEN: AI Search, query search, vector search, hybrid search, semantic search, speech-to-text, text-to-speech, transcribe, OCR, convert text to speech.
appinsights-instrumentation
microsoft/azure-skills
Guidance for instrumenting webapps with Azure Application Insights. Provides telemetry patterns, SDK setup, and configuration references. WHEN: how to instrument app, App Insights SDK, telemetry patterns, what is App Insights, Application Insights guidance, instrumentation examples, APM best practices.
azure-storage
microsoft/azure-skills
Azure Storage Services including Blob Storage, File Shares, Queue Storage, Table Storage, and Data Lake. Answers questions about storage access tiers (hot, cool, cold, archive), when to use each tier, and tier comparison. Provides object storage, SMB file shares, async messaging, NoSQL key-value, and big data analytics. Includes lifecycle management. USE FOR: blob storage, file shares, queue storage, table storage, data lake, upload files, download blobs, storage accounts, access tiers, storage tiers, hot cool cold archive, storage tier comparison, when to use storage tiers, lifecycle management, Azure Storage concepts. DO NOT USE FOR: SQL databases, Cosmos DB (use azure-prepare), messaging with Event Hubs or Service Bus (use azure-messaging).

