Docker und C#: Containerisierung von Anwendungen auf fortgeschrittenem Niveau
Die Containerisierung von .NET-Anwendungen mit Docker ist zum Industriestandard geworden. Wenn die grundlegenden Fähigkeiten im Umgang mit Containern bereits erlernt wurden, ist es an der Zeit, auf ein fortgeschrittenes Niveau zu wechseln. In diesem Artikel betrachten wir komplexe Szenarien: Multi-Stage-Build, Erstellung von leichtgewichtigen Produktions-Images, Organisation von Microservices mit Docker Compose, Implementierung von Health Checks und effektive Konfigurationsverwaltung. Alle Beispiele sind aktuell für .NET 8 und die neuesten Docker-Versionen.
1. Multi-Stage-Build für .NET
Ein klassisches Problem sind riesige Images, die SDK und Build-Tools enthalten. Die Lösung ist der Multi-Stage-Build, bei dem das finale Image nur die Laufzeitumgebung und die kompilierten Binärdateien enthält.
Betrachten wir ein fortgeschrittenes Dockerfile für eine ASP.NET Core Web API:
# Stufe 1: Wiederherstellung der AbhängigkeitenFROM mcr.microsoft.com/dotnet/sdk:8.0 AS restoreWORKDIR /srcCOPY ["MyApp.Api/MyApp.Api.csproj", "MyApp.Api/"]COPY ["MyApp.Core/MyApp.Core.csproj", "MyApp.Core/"]RUN dotnet restore "MyApp.Api/MyApp.Api.csproj"
# Stufe 2: Build und VeröffentlichungFROM restore AS buildCOPY . .WORKDIR "/src/MyApp.Api"RUN dotnet publish -c Release -o /app/publish
# Stufe 3: Finales Image (nur Laufzeit)FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS finalWORKDIR /appEXPOSE 8080ENV ASPNETCORE_URLS=http://+:8080COPY --from=build /app/publish .ENTRYPOINT ["dotnet", "MyApp.Api.dll"]Wichtige Optimierungen:
- Trennung von restore und build: Das Caching der Abhängigkeitsebene beschleunigt wiederholte Builds.
- Zielplattform: Verwenden Sie
--no-restorein der publish-Phase, wenn restore bereits durchgeführt wurde. - Minimierung der Ebenen: Fassen Sie
RUN-Befehle wo möglich mit&&zusammen. - Verwendung von
--chmod: Für korrekte Zugriffsrechte in Linux-Containern.
2. Docker Compose für Microservices in C#
Docker Compose ist unverzichtbar bei der Arbeit mit mehreren .NET-Diensten. Ein fortgeschrittenes Szenario umfasst die Konfiguration von Netzwerk, Abhängigkeiten und Umgebungsvariablen.
Beispiel einer docker-compose.yml für eine Microservice-Architektur mit API Gateway, Bestelldienst und RabbitMQ:
version: '3.8'
services: rabbitmq: image: rabbitmq:3-management-alpine ports: - "5672:5672" - "15672:15672" healthcheck: test: ["CMD", "rabbitmq-diagnostics", "check_port_connectivity"] interval: 30s timeout: 10s retries: 5
orders-api: build: context: . dockerfile: src/Orders.Api/Dockerfile ports: - "5001:8080" environment: - ASPNETCORE_ENVIRONMENT=Production - ConnectionStrings__DefaultConnection=Server=db;Database=OrdersDb;User=sa;Password=Your_password123; - RabbitMQ__Host=rabbitmq depends_on: rabbitmq: condition: service_healthy db: condition: service_started restart: unless-stopped
api-gateway: build: context: . dockerfile: src/ApiGateway/Dockerfile ports: - "80:8080" depends_on: - orders-api environment: - ASPNETCORE_ENVIRONMENT=Production - Services__Orders=http://orders-api:8080Fortgeschrittene Techniken:
- Healthcheck in Compose: Verwenden Sie
condition: service_healthyfür strikte Abhängigkeiten. - Profile: Aktivieren/deaktivieren Sie Dienste für verschiedene Entwicklungsumgebungen.
- Integrierte Volumes für Logs:
volumes:zum Speichern von Logs außerhalb des Containers. - Umgebungsvariablen über .env-Datei: Speichern Sie sensible