Skip to main content

Best Practices für die Containerisierung von .NET-Anwendungen

Artikel von

Marcelo Oliveira

hero container aps

31. August 2022

0 Min. Lesezeit

Die Containerisierung mit Docker hat sich zu einem wichtigen Trend in der Webentwicklung entwickelt, den viele .NET-Entwickler übernommen haben. Es gibt viele überzeugende Gründe für Entwickler und DevOps-Engineers, .NET-Anwendungen zu containerisieren – auch bei der Arbeit mit den älteren Versionen des .NET Framework 4.x. Wenn wir jedoch nicht wissen, wie wir Container richtig einsetzen, profitieren wir nur wenig davon.

In diesem Artikel behandeln wir Best Practices für die Containerisierung von .NET-Anwendungen – auch für Anwendungen mit dem .NET Framework 4.x. Außerdem geht es darum, kleine Images zu verwenden und Images zu scannen, um Sicherheitsrisiken zu verringern und unnötige Komponenten aus unseren Containern zu entfernen.

Voraussetzungen

Bevor Sie beginnen, benötigen Sie Folgendes:

Ziehen Sie die Containerisierung Ihrer .NET-Apps in Betracht (auch mit .NET Framework 4.x)

Mit .NET Core 1.0 wurden Web-Apps plattformübergreifend, portabel und Open Source. Dadurch konnten Entwickler sie auf Docker portieren und die Vorteile der Containerisierung voll ausschöpfen.

Neuere .NET-Versionen unter Linux erhalten zwar die meiste Aufmerksamkeit, doch Windows-Container unterstützen auch die älteren, ausschließlich für Windows verfügbaren .NET-Versionen, auf die unzählige Unternehmensanwendungen angewiesen sind. Außerdem sind nicht alle Unternehmen, die Web-Apps mit dem .NET Framework warten, bereit, sie auf neuere Versionen zu portieren. Deshalb ist es sinnvoll, unsere .NET Framework 4.x-Anwendungen zu containerisieren.

Die folgenden Schritte zeigen, wie Sie eine containerisierte ASP.NET-Web-Forms-Anwendung in Visual Studio 2022 erstellen und ausführen.

Starten Sie zunächst Docker Desktop auf Ihrem Entwicklungscomputer:

Windows-Suchergebnisse für „docker desktop“ mit Docker Desktop als App mit der besten Übereinstimmung.

Wählen Sie im Fenster Erste Schritte von Visual Studio die Option Neues Projekt erstellen aus.

Visual-Studio-Startbildschirm mit rot hervorgehobener Option „Neues Projekt erstellen“.

Geben Sie „Web Forms“ in das Textfeld Nach Vorlagen suchen ein und wählen Sie ASP.NET-Webanwendung (.NET Framework) aus.

Suchergebnisse für „Web Forms“ in Visual Studio. Angezeigt wird die Projektvorlage „ASP.NET Web Application“ mit den Tags C#, Windows, Cloud und Web.

Geben Sie einen Namen für Ihre neue Anwendung ein (zum Beispiel WebFormsApp), legen Sie den Speicherort auf dem Datenträger fest, wählen Sie .NET Framework 4.8 aus und klicken Sie auf Erstellen.

Visual-Studio-Dialogfeld zur Konfiguration eines neuen ASP.NET-Webanwendungsprojekts namens WebFormsApp mit .NET Framework 4.8

Wählen Sie anschließend den Typ Web Forms aus.

Bildschirm zum Erstellen einer neuen ASP.NET-Webanwendung mit den Projektvorlagen „Leer“ und „Web Forms“ und ihren Beschreibungen

Vergewissern Sie sich, dass die Optionen Web Forms und Docker-Unterstützung ausgewählt sind, und klicken Sie dann auf Erstellen.

Dialog zur Projekterstellung mit Optionen für Ordner und Core-Referenz, erweiterten Einstellungen, einem deaktivierten Feld für das Testprojekt sowie den Schaltflächen „Zurück“ und „Erstellen“.

Warten Sie, bis Visual Studio das Projekt erstellt hat. So sieht die Projektstruktur in Visual Studio aus:

Visual Studio Solution Explorer mit der Projektstruktur der WebFormsApp, einschließlich ASP.NET-Dateien, Ordnern und Konfigurationsdateien.

Öffnen Sie nun Docker Desktop. Sie werden sehen, dass der Container WebFormsApp auf Port 61469 ausgeführt wird:

Container-Ansicht in Docker Desktop mit dem laufenden WebFormsApp-Container auf Port 61469

Öffnen Sie die Registerkarte Images, um das Image WebFormsApp zu sehen, aus dem der Container WebFormsApp ausgeführt wird.

Docker-Desktop-Ansicht „Images on disk“ mit zwei lokalen Images mit insgesamt 8,64 GB, darunter webformsapp mit dem Tag dev.

Drücken Sie abschließend Ctrl+F5, um Ihr Docker-Image zu erstellen und lokal auszuführen. Sobald das Container-Image erstellt wurde und in einem Docker-Container läuft, öffnet Visual Studio die Web-App in Ihrem Standardbrowser.

Browserfenster mit der Startseite einer ASP.NET-Anwendung: Navigation, Einführungstext und Bereiche zu den Themen Erste Schritte, Bibliotheken und Webhosting.

Kehren Sie nun zu Visual Studio zurück und klicken Sie auf die Datei Dockerfile:

Visual Studio Solution Explorer mit einem WebFormsApp-Projekt, in dem die Dockerfile hervorgehoben ist.

Dadurch wird die Dockerfile geöffnet, mit der Ihr Projekt für die Ausführung in einem Container konfiguriert wird.

Visual Studio-Editor mit einer Dockerfile für eine ASP.NET-Anwendung, einschließlich eines .NET-Framework-Basisimages, eines Source-Arguments, eines Arbeitsverzeichnisses und eines Publish-

Die Anweisung FROM startet eine neue Build-Phase und legt das Basis-Image für die folgenden Anweisungen fest. In diesem Fall ist das Image aspnet:4.8-windowsservercore-ltsc2019, das Docker aus dem Image-Repository von Microsoft herunterlädt.

Natürlich wurde Ihr Web-Forms-Projekt wahrscheinlich nicht von Anfang an mit Docker-Unterstützung erstellt. Um genau diese Situation nachzustellen, erstellen Sie ein neues ASP.NET-Web-Forms-Projekt, diesmal jedoch ohne Docker-Unterstützung:

Visual Studio Solution Explorer mit einer WebFormsApp-Lösung und den Projektdateien von WebFormsAppNoDocker, darunter ASPX-Seiten und Konfigurationsdateien.

Fügen wir dem neuen Projekt nun eine Dockerfile hinzu. Klicken Sie mit der rechten Maustaste auf den Projektnamen, wählen Sie das Menü Hinzufügen und dann das Untermenü Docker-Unterstützung aus:

Visual Studio Solution Explorer mit geöffnetem Menü „Hinzufügen“, in dem „Docker-Unterstützung“ für ein Webprojekt ausgewählt ist

Visual Studio erstellt die Dockerfile des Projekts daraufhin automatisch.

Visual Studio-Projektmappen-Explorer mit dem Projekt WebFormsAppNoDocker, in dem die Dockerfile ausgewählt ist

Beachten Sie, dass Visual Studio das Image und den Quellcodepfad, aus denen der Container erstellt wird, bereits ausgewählt hat.

Visual Studio-Editor mit einer Dockerfile, die ein ASP.NET-Framework-Basisimage, WORKDIR /inetpub/wwwroot und den Befehl COPY für die Build-Ausgabe zeigt

Ihr Projekt verfügt nun über die Unterstützung und Vorteile, die mit der Containerisierung durch Docker einhergehen – darunter Portabilität, Agilität, schnellere Bereitstellung, höhere Sicherheit und einfachere Verwaltung.

Halten Sie Container-Images so klein wie möglich

Sowohl Linux- als auch Windows-Container bieten schlanke Basis-Images, die nur die Apps und Dienste enthalten, die für den Betrieb Ihrer Anwendung erforderlich sind. Ein kleines Image mit möglichst wenigen Abhängigkeiten verringert die Anzahl der über diese Abhängigkeiten eingebrachten Schwachstellen und damit die Angriffsfläche.

Sehen wir uns einige Basis-Images an, die .NET-Entwickler für kleine Container in Betracht ziehen können. Wenn Sie noch ASP.NET Framework 4.x verwenden, das unter Linux nicht unterstützt wird, sind Windows-Container Ihre einzige Option. Microsoft empfiehlt als schlanke Basis-Images Windows Server Core und Nano Server.

Windows Server Core ist ein minimales, befehlszeilenbasiertes Betriebssystem zum Ausführen von Windows-Serverrollen und Anwendungen, die keine standardmäßige grafische Windows-Benutzeroberfläche benötigen. Nano Server ist ein Betriebssystem, das für Private Clouds und Rechenzentren optimiert ist. Nano Server bietet keine lokale Anmeldefunktion, ist kleiner und startet deutlich schneller neu als Server Core.

Für .NET Core und .NET 5+ sollten SDK-Images nur für den Build und Runtime-Images für Produktionsbereitstellungen im Rahmen eines mehrstufigen Builds verwendet werden. Zu den geeigneten schlanken Basis-Images gehören Debian bullseye-slim-amd64 und Alpine Linux.

Wir können Basis-Images noch weiter verkleinern, indem wir Images für die .NET-Runtime-Abhängigkeiten verwenden und unsere .NET-Anwendung im eigenständigen Modus erstellen. So laden wir nur die Abhängigkeiten herunter, die unsere App benötigt – und nichts darüber hinaus.

Üben wir nun, eine .NET-6-Webanwendung mit schlanken Images zu erstellen. Öffnen Sie Visual Studio 2022, klicken Sie auf Neues Projekt erstellen und wählen Sie den Typ ASP.NET Core-Web-App aus.

Visual Studio-Projektmappen-Explorer mit einem WebApp-Projekt und Connected Services, Dependencies, Properties, wwwroot, Pages, appsettings.json, Dockerfile und C#

Geben Sie dem Projekt einen Namen, zum Beispiel WebApp.

Der Bildschirm „Neues Projekt konfigurieren“ in Visual Studio mit Projektname, Speicherort und Projektmappenname einer ASP.NET-Core-Web-App sowie der Option für das Verzeichnis.

Klicken Sie auf Weiter und wählen Sie die folgenden Optionen aus:

  • .NET 6.0 Framework

  • Authentifizierungstyp: Keine

  • Für HTTPS konfigurieren: Aktiviert

  • Docker aktivieren: Aktiviert

  • Docker-Betriebssystem: Linux

Zusätzliche Informationseinstellungen für eine ASP.NET Core-Web-App mit .NET 6.0, ohne Authentifizierung, mit aktiviertem HTTPS und Docker sowie ausgewähltem Linux.

Klicken Sie auf Erstellen und sehen Sie sich das neue Projekt in Visual Studio an.

Vorlage für die Suche nach einer ASP.NET Core-Web-App mit Filtern für C#, alle Plattformen und Web.

Drücken Sie nun F5, um die Web-App in Ihrem lokalen Docker-Container auszuführen.

Startseite einer Web-App mit der Überschrift „Willkommen“, einem Link zum Erstellen von Web-Apps mit ASP.NET Core und Navigationslinks zu „Startseite“ und „Datenschutz“.

Führen Sie nun den Befehl docker images aus, um eine Liste der Docker-Images auf Ihrem System abzurufen:

> docker images

Der Befehl gibt ungefähr Folgendes aus:

REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
webapp       dev       e3b51b1eef08   4 hours ago   208MB

Beachten Sie, dass die App in einem Linux-Container ausgeführt wird und das webapp-Image oben 208 MB groß ist.

Verkleinern wir als Nächstes das Container-Image unserer Web-App.

Beenden Sie die App in Visual Studio und öffnen Sie die Datei Dockerfile. Im folgenden Abschnitt wird Docker angewiesen, die Images dotnet/aspnet:6.0 und dotnet/sdk:6.0 aus der Microsoft Container Registry (mcr) herunterzuladen und als Basis-Images für Ihren App-Container zu verwenden:

FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["WebApp/WebApp.csproj", "WebApp/"]
RUN dotnet restore "WebApp/WebApp.csproj"
COPY . .
WORKDIR "/src/WebApp"
RUN dotnet build "WebApp.csproj" -c Release -o /app/build

Drücken Sie anschließend F5, um die Anwendung erneut auszuführen. Sobald die Web-App läuft, führen Sie den Befehl docker images aus, um eine Liste der Docker-Images auf Ihrem System abzurufen:

> docker images

Ihre Image-Liste sieht etwa so aus:

REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
webapp       dev       778bcd52f366   4 hours ago   100MB
<none>       <none>    e3b51b1eef08   4 hours ago   208MB

Beachten Sie, dass das webapp-Image neu erstellt wurde und nun 100 MB groß ist (108 MB kleiner als das ursprüngliche Image).

Images auf Schwachstellen scannen

Die Codebasis regelmäßig zu aktualisieren, ist an sich schon eine Best Practice. Zu den offensichtlichen Vorteilen zählen der Zugriff auf neue Funktionen, Fehlerkorrekturen, eine bessere Benutzeroberfläche und eine höhere Leistung. Sicherheitsupdates sind jedoch genauso wichtig.

Das Betriebssystem oder die Bibliotheken im Basis-Image können ungepatchte Schwachstellen enthalten. Auch Skripte, Code und Apps, die dem Basis-Image hinzugefügt werden, können Schwachstellen aufweisen, die wir nicht versehentlich in der Produktionsumgebung bereitstellen möchten.

Das Scannen von Containern auf Schwachstellen ist unverzichtbar, um potenzielle Sicherheitsrisiken zu bewerten und geeignete Maßnahmen zu ergreifen. In diesem Beispiel wählen wir ein veraltetes .NET-Image aus: mcr.microsoft.com/dotnet/core/aspnet:2.2.

dotnet new webapp -n "AspNet2.2" -f "netcoreapp2.2"

Öffnen Sie das Projekt in Visual Studio und fügen Sie dem neuen Projekt eine Dockerfile hinzu. Klicken Sie mit der rechten Maustaste auf den Projektnamen, wählen Sie das Menü Hinzufügen und klicken Sie dann auf das Untermenü Docker-Unterstützung.

Öffnen Sie nun die Datei Dockerfile und ersetzen Sie ihren Inhalt durch den folgenden Code:

#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/core/sdk:2.2.105 AS build
WORKDIR /src
COPY ["AspNet2.2.csproj", "."]
RUN dotnet restore "./AspNet2.2.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "AspNet2.2.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "AspNet2.2.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "AspNet2.2.dll"]

Als Nächstes erfahren Sie, wie Sie Image-Scans einsetzen, um herauszufinden, wie anfällig unser Container ist. Führen Sie zunächst den CLI-Befehl docker images aus, um Ihre aktuellen lokalen Images aufzulisten:

docker images

REPOSITORY       TAG       IMAGE ID       CREATED              SIZE
aspnet22         latest    223b485f4516   About a minute ago   265MB

Führen Sie anschließend den Befehl snyk auth aus, um sich für die Snyk CLI zu authentifizieren:

> snyk auth

Sobald Ihr Konto authentifiziert ist, können Sie die Snyk CLI verwenden. Führen wir den Befehl snyk container test <repository>:<tag> aus, um das lokal erstellte Image zu testen, das in unserem lokalen Docker-Daemon verfügbar ist:

> snyk container test aspnet22:latest
PowerShell-Terminal mit einer Liste von Sicherheitslücken mit hohem Schweregrad in den Paketen zlib, systemd und shadow/passwd

Der Befehl snyk container test erstellt eine Liste der im Image installierten Komponenten, sendet diese Liste an den Snyk-Service und gibt eine Liste der Schwachstellen in unserem Image zurück.

Der Image-Scan hat insgesamt 193 Schwachstellen gefunden:

Terminalbericht für docker-image|aspnet22 mit 193 Schwachstellen, darunter 10 kritische, im Microsoft-.NET-Basis-Image.

Führen Sie den Befehl snyk container monitor <repository>:<tag> aus, um das Image zu überwachen:

> snyk container monitor aspnet22:latest
Terminalausgabe mit Snyk-Monitoring für das Docker-Image aspnet22:latest und einem Link zum Projektverlauf.

Der Befehl snyk container monitor erstellt eine Liste der im Image installierten Komponenten, sendet diese Liste an den Snyk-Service und gibt einen Link zum Snyk-Service unter http://app.snyk.io/org/{YOUR-ACCOUNT}/ zurück, wo Sie die Ergebnisse sehen können:

Tabelle mit dem Titel „Empfehlungen für das Upgrade des Basis-Images“, die aktuelle und alternative .NET-Basis-Images nach Sicherheitslücken und Schweregrad vergleicht.

Die 3 wichtigsten Tipps zur Containerisierung

Wir haben viele überzeugende Gründe gesehen, warum Entwickler und DevOps-Engineers .NET-Anwendungen containerisieren sollten. Container sind jedoch keine magische Lösung für alle Probleme. Wir müssen weiterhin einige Best Practices umsetzen, die Klarheit über Container schaffen und zeigen, wie wir das Beste aus ihnen herausholen.

Entgegen dem weit verbreiteten Irrglauben, dass Container nur für .NET-Core-Apps gedacht sind, haben wir gesehen, dass Container auch .NET Framework 4.x-Anwendungen Vorteile bieten.

Bei der Größe von Container-Images gilt: Je kleiner, desto besser. Wie wir gesehen haben, sind einige Basis-Images klein genug, um nur das zu enthalten, was unsere App zum Ausführen benötigt. So wird auch die Angriffsfläche des Containers verkleinert.

Abschließend haben wir gesehen, wie sich Sicherheitsrisiken durch das Scannen von Container-Images und deren Aktualisierung verringern lassen. Die Befehle Snyk container test und Snyk container monitor sind wertvolle Tools, mit denen wir unsere .NET-Container auf Schwachstellen scannen und kontinuierlich überwachen können. Bei richtiger Anwendung kann die Containerisierung unseren Apps unabhängig von ihrem Alter zusätzliche Sicherheit und Flexibilität bieten.

Container-Sicherheit mit Fokus auf Entwickler

Snyk findet und behebt automatisch Schwachstellen in Container-Images und Kubernetes-Workloads.