Containerisierung von C#-Anwendungen in Docker: Fortgeschrittenes Niveau

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Einleitung: Warum fortgeschrittenes Niveau?

\n

Die Containerisierung von C#-Anwendungen auf Basis von .NET ist nicht mehr nur ein Trend – sie ist ein Industriestandard. Auf der Anfängerstufe reicht ein einfaches Dockerfile mit FROM mcr.microsoft.com/dotnet/aspnet aus. In einer Produktionsumgebung treten jedoch Aufgaben auf, die ein tieferes Verständnis erfordern: Minimierung der Image-Größe, Sicherheit, Multi-Container-Architektur, effizientes Konfigurationsmanagement und Debugging.

\n

Dieser Artikel richtet sich an Entwickler, die bereits mit den Grundlagen von Docker und C# vertraut sind, aber auf die nächste Stufe wechseln möchten. Wir werden fortgeschrittene Techniken behandeln, mit denen Sie leichte, sichere und einfach skalierbare Images für Ihre .NET-Anwendungen erstellen können.

\n\n

1. Multi-Stage-Build: Die Kunst der leichten Images

\n

Ein klassisches Problem – .NET SDK-Images wiegen über 1,5 GB. Diese in die Produktion zu übernehmen ist sinnlos und gefährlich. Der Multi-Stage-Build löst dieses Problem, indem er die Build-Phase und die Runtime-Phase trennt.

\n\n

Fortgeschrittenes Dockerfile mit Multi-Stage

\n

Anstatt einfach die Binärdateien zu kopieren, verwenden wir offizielle SDK-Images für die Kompilierung und kopieren das Ergebnis dann in ein minimales aspnet-Image.

\n
# Phase 1: Build\nFROM mcr.microsoft.com/dotnet/sdk:8.0 AS build\nWORKDIR /app\n\n# Nur die Projektdateien kopieren (Cache-Optimierung)\nCOPY src/MyApp.csproj .\nRUN dotnet restore\n\n# Restlichen Code kopieren\nCOPY src/ .\nRUN dotnet publish -c Release -o /app/publish\n\n# Phase 2: Runtime\nFROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime\nWORKDIR /app\n\n# Nicht-privilegierten Benutzer hinzufügen\nRUN adduser --disabled-password --gecos '' appuser\nUSER appuser\n\nCOPY --from=build /app/publish .\n\nEXPOSE 8080\nENV ASPNETCORE_URLS=http://+:8080\nENTRYPOINT ["dotnet", "MyApp.dll"]
\n

Was hier wichtig ist:

\n
    \n
  • Layer-Caching: Zuerst wird nur die .csproj-Datei kopiert und dotnet restore ausgeführt. Solange sich die Abhängigkeiten nicht ändern, verwendet Docker den Cache für diesen Layer.
  • \n
  • Nicht-privilegierter Benutzer: appuser – kritisch für die Sicherheit in der Produktion.
  • \n
  • Port 8080: In .NET 8 wird standardmäßig Port 8080 verwendet, was modernen Cloud-Standards entspricht.
  • \n
\n\n

Trick: Getrimmte und AOT-Builds

\n

Für eine noch stärkere Größenreduzierung verwenden Sie Trimming (Entfernen von ungenutztem Code) oder Native AOT. Damit lassen sich Images mit einer Größe von 10-30 MB erstellen.

\n
# Für ReadyToRun (R2R) und Trimming\nRUN dotnet publish -c Release -r linux-x64 --self-contained true \\\n    -p:PublishTrimmed=true \\\n    -p:PublishSingleFile=true \\\n    -o /app/publish
\n

Wichtig: AOT unterliegt Einschränkungen bei Reflection und dynamischem Laden von Assemblies. Stellen Sie vor der Verwendung sicher, dass Ihr Code kompatibel ist.

\n\n

2. Arbeiten mit Konfiguration und Secrets

\n

Das Speichern von Verbindungszeichenfolgen und API-Schlüsseln innerhalb des Images ist ein grober Fehler. Auf fortgeschrittenem Niveau verwenden wir Docker Secrets, Umgebungsvariablen und die Verknüpfung mit appsettings.json.

\n\n

Überschreiben von appsettings über Docker

\n

In .NET gibt es einen integrierten Prioritätsmechanismus für die Konfiguration. Wir können Einstellungen über Umgebungsvariablen übergeben, die automatisch auf Konfigurationsabschnitte abgebildet werden.

\n
// In C#-Code\nvar builder = WebApplication.CreateBuilder(args);\nbuilder.Configuration\n    .AddJsonFile("appsettings.json", optional: false)\n    .AddEnvironmentVariables(); // Überschreibt Werte aus JSON
\n

Container starten:

\n
docker run -d -p 8080:8080 \\\n  -e "ConnectionStrings__DefaultConnection=Server=db;Database=myapp;User Id=sa;Password=MyPass123!" \\\n  -e "Logging__LogLevel__Default=Warning" \\\n                

Blogs

Buchempfehlungen