Containerisieren einer .NET-App mit dem Befehl „dotnet publish“

Container haben viele Features und Vorteile, z. B. eine unveränderliche Infrastruktur, eine portable Architektur und die Skalierbarkeit. Das Image kann zum Erstellen von Containern für Ihre lokale Entwicklungsumgebung, eine private Cloud oder eine öffentliche Cloud verwendet werden. In diesem Tutorial erfahren Sie, wie Sie eine .NET-Anwendung mithilfe des Befehls dotnet publish containerisieren.

Voraussetzungen

Die folgenden Komponenten müssen installiert sein:

Zusätzlich zu diesen Voraussetzungen ist es empfehlenswert, mit Workerdiensten in .NET vertraut zu sein.

Erstellen einer .NET-App

Sie benötigen eine .NET-App zum Containerisieren. Beginnen Sie daher mit dem Erstellen einer neuen App anhand einer Vorlage. Öffnen Sie Ihr Terminal, erstellen Sie einen Arbeitsordner (sample-directory), falls noch nicht geschehen, und ändern Sie die Verzeichnisse so, dass Sie sich darin befinden. Führen Sie im Arbeitsordner den folgenden Befehl aus, um ein neues Projekt im Unterverzeichnis Worker zu erstellen:

dotnet new worker -o Worker -n DotNet.ContainerImage

Ihre Ordnerstruktur sollte wie folgt aussehen:

📁 sample-directory
    └──📂 Worker
        ├──appsettings.Development.json
        ├──appsettings.json
        ├──DotNet.ContainerImage.csproj
        ├──Program.cs
        ├──Worker.cs
        └──📂 obj
            ├── DotNet.ContainerImage.csproj.nuget.dgspec.json
            ├── DotNet.ContainerImage.csproj.nuget.g.props
            ├── DotNet.ContainerImage.csproj.nuget.g.targets
            ├── project.assets.json
            └── project.nuget.cache

Mit dem Befehl dotnet new erstellen Sie einen neuen Ordner mit dem Namen Worker und generieren einen Workerdienst, bei dessen Ausführung jede Sekunde eine Nachricht protokolliert wird. Ändern Sie in Ihrer Terminalsitzung die Verzeichnisse, und navigieren Sie zum Ordner Worker. Verwenden Sie den dotnet run-Befehl, um die App zu starten.

dotnet run
Building...
info: DotNet.ContainerImage.Worker[0]
      Worker running at: 10/18/2022 08:56:00 -05:00
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: .\Worker
info: DotNet.ContainerImage.Worker[0]
      Worker running at: 10/18/2022 08:56:01 -05:00
info: DotNet.ContainerImage.Worker[0]
      Worker running at: 10/18/2022 08:56:02 -05:00
info: DotNet.ContainerImage.Worker[0]
      Worker running at: 10/18/2022 08:56:03 -05:00
info: Microsoft.Hosting.Lifetime[0]
      Application is shutting down...
Attempting to cancel the build...

Die Workervorlage wird unbegrenzt in einer Schleife ausgeführt. Verwenden Sie zum Beenden den Befehl STRG+C, um diese anzuhalten.

Hinzufügen des NuGet-Pakets

Das NuGet-Paket Microsoft.NET.Build.Containers ist derzeit erforderlich, um ein Webprojekt als Container zu veröffentlichen. Zum Hinzufügen des NuGet-Pakets Microsoft.NET.Build.Containers zur Workervorlage führen Sie den folgenden Befehl dotnet add package aus:

dotnet add package Microsoft.NET.Build.Containers

Tipp

Wenn Sie eine Webanwendung erstellen und das .NET SDK 7.0.300 oder höher verwenden, ist das Paket nicht erforderlich – die Funktionen sind bereits im SDK enthalten.

Festlegen des Namens des Containerimages

Beim Veröffentlichen einer App als Container stehen verschiedene Konfigurationsoptionen zur Verfügung.

Standardmäßig ist der Name des Containerimages der AssemblyName des Projekts. Wenn dieser Name als Containerimagename ungültig ist, können Sie ihn überschreiben, indem Sie einen ContainerRepository wie in der folgenden Projektdatei angeben:

<Project Sdk="Microsoft.NET.Sdk.Worker">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <UserSecretsId>dotnet-DotNet.ContainerImage-2e40c179-a00b-4cc9-9785-54266210b7eb</UserSecretsId>
    <ContainerRepository>dotnet-worker-image</ContainerRepository>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
  </ItemGroup>
</Project>

Weitere Informationen finden Sie unter ContainerRepository.

Standardmäßig ist der Name des Containerimages der AssemblyName des Projekts. Wenn dieser Name als Containerimagename ungültig ist, können Sie ihn überschreiben, indem Sie einen ContainerImageName (veraltet) oder das bevorzugte ContainerRepository wie in der folgenden Projektdatei angeben:

<Project Sdk="Microsoft.NET.Sdk.Worker">

  <PropertyGroup>
    <TargetFramework>net7.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <UserSecretsId>dotnet-DotNet.ContainerImage-2e40c179-a00b-4cc9-9785-54266210b7eb</UserSecretsId>
    <ContainerImageName>dotnet-worker-image</ContainerImageName>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
    <PackageReference Include="Microsoft.NET.Build.Containers" Version="7.0.401" />
  </ItemGroup>
</Project>

Weitere Informationen finden Sie unter ContainerImageName.

Veröffentlichen einer .NET-App

Veröffentlichen Sie die .NET-App als Container mit dem folgenden dotnet publish-Befehl:

dotnet publish --os linux --arch x64 /t:PublishContainer -c Release

Mit dem vorherigen .NET CLI-Befehl wird die App als Container veröffentlicht:

  • Für Linux als Betriebssystem (--os linux).
  • Angeben einer x64-Architektur (--arch x64).
  • Verwenden der Releasekonfiguration (-c Release).

Wichtig

Um den Container lokal zu erstellen, muss der Docker-Daemon ausgeführt werden. Wenn dieser nicht ausgeführt wird, sobald Sie versuchen, die App als Container zu veröffentlichen, tritt ein Fehler ähnlich dem folgenden auf:

..\build\Microsoft.NET.Build.Containers.targets(66,9): error MSB4018:
   The "CreateNewImage" task failed unexpectedly. [..\Worker\DotNet.ContainerImage.csproj]

Tipp

Je nach Typ der App, die Sie containerisieren, können die Befehlszeilenschalter (Optionen) variieren. Das Argument /t:PublishContainer ist beispielsweise nur für Nicht-Web-.NET-Apps erforderlich, wie die Vorlagen console und worker. Ersetzen Sie bei Webvorlagen das Argument /t:PublishContainer durch -p:PublishProfile=DefaultContainer. Weitere Informationen finden Sie unter .NET SDK-Containerbuilds, Issue 141.

Der Befehl erzeugt eine Ausgabe ähnlich der Beispielausgabe:

Determining projects to restore...
  All projects are up-to-date for restore.
  DotNet.ContainerImage -> .\Worker\bin\Release\net8.0\linux-x64\DotNet.ContainerImage.dll
  DotNet.ContainerImage -> .\Worker\bin\Release\net8.0\linux-x64\publish\
  Building image 'dotnet-worker-image' with tags latest on top of base image mcr.microsoft.com/dotnet/aspnet:8.0
  Pushed container 'dotnet-worker-image:latest' to Docker daemon
Determining projects to restore...
  All projects are up-to-date for restore.
  DotNet.ContainerImage -> .\Worker\bin\Release\net7.0\linux-x64\DotNet.ContainerImage.dll
  DotNet.ContainerImage -> .\Worker\bin\Release\net7.0\linux-x64\publish\
  Building image 'dotnet-worker-image' with tags 1.0.0 on top of base image mcr.microsoft.com/dotnet/aspnet:7.0
  Pushed container 'dotnet-worker-image:1.0.0' to Docker daemon

Dieser Befehl kompiliert Ihre Worker-App in den Ordner publish und pusht den Container in Ihre lokale Docker-Registrierung.

Konfigurieren eines Containerimages

Sie können über MSBuild-Eigenschaften viele Aspekte des generierten Containers steuern. Wenn Sie einen Befehl in einer Dockerfile verwenden können, um eine Konfiguration festzulegen, ist dies in der Regel auch über MSBuild möglich.

Hinweis

Die einzigen Ausnahmen sind RUN-Befehle. Aufgrund der Art und Weise, wie Container angelegt sind, können diese nicht emuliert werden. Wenn Sie diese Funktionalität benötigen, müssen Sie Ihre Containerimages mithilfe einer Dockerfile erstellen.

ContainerArchiveOutputPath

Ab .NET 8 können Sie einen Container direkt als Tar.gz-Archiv erstellen. Diese Funktion ist nützlich, wenn Ihr Workflow nicht einfach ist und erfordert, dass Sie beispielsweise ein Scantool über Ihre Bilder ausführen, bevor Sie diese pushen. Nachdem das Archiv erstellt wurde, können Sie es verschieben, scannen oder in eine lokale Docker-Toolkette laden.

Um sie in einem Archiv zu veröffentlichen, fügen Sie die ContainerArchiveOutputPath Eigenschaft zu Ihrem dotnet publish-Befehl hinzu, z. B.:

dotnet publish \
  -p PublishProfile=DefaultContainer \
  -p ContainerArchiveOutputPath=./images/sdk-container-demo.tar.gz

Sie können entweder einen Ordnernamen oder einen Pfad mit einem bestimmten Dateinamen angeben. Wenn Sie den Ordnernamen angeben, lautet der für die Imagearchivdatei generierte Dateiname $(ContainerRepository).tar.gz. Diese Archive können mehrere Tags enthalten, nur wenn eine einzelne Datei für alle ContainerImageTags erstellt wird.

Namenskonvention für Containerimages

Containerimages folgen einer bestimmten Namenskonvention. Der Name des Images besteht aus mehreren Teilen, der Registrierung, dem Port (optional), dem Repository und Tag und Familie (optional).

REGISTRY[:PORT]/REPOSITORY[:TAG[-FAMILY]]

Betrachten Sie beispielsweise den vollqualifizierten Imagenamen mcr.microsoft.com/dotnet/runtime:8.0-alpine:

  • mcr.microsoft.com ist die Registrierung (in diesem Fall die Microsoft-Containerregistrierung).
  • dotnet/runtime ist das Repository (einige betrachten dies jedoch als user/repository).
  • 8.0-alpine ist das Tag und die Familie (die Familie ist ein optionaler Bezeichner, der bei der Zuordnung des Betriebssystempakets hilft).

Einige in den folgenden Abschnitten beschriebene Eigenschaften entsprechen den verwaltenden Bestandteilen des generierten Imagenamens. Beachten Sie die folgende Tabelle, die die Beziehung zwischen dem Imagenamen und den Buildeigenschaften zuordnet:

Bestandteil des Imagenamens MSBuild-Eigenschaft Beispielwerte
REGISTRY[:PORT] ContainerRegistry mcr.microsoft.com:443
PORT ContainerPort :443
REPOSITORY ContainerRepository dotnet/runtime
TAG ContainerImageTag 8.0
FAMILY ContainerFamily -alpine
Bestandteil des Imagenamens MSBuild-Eigenschaft Beispielwerte
REGISTRY[:PORT] ContainerRegistry mcr.microsoft.com:443
PORT ContainerPort :443
REPOSITORY ContainerImageName dotnet/runtime
TAG ContainerImageTag 8.0

In den folgenden Abschnitten werden die verschiedenen Eigenschaften beschrieben, die zum Steuern des generierten Containerimages verwendet werden können.

ContainerBaseImage

Die Eigenschaft „Containerbasisimage“ steuert das Image, das als Basis für Ihr Image dient. Standardmäßig werden die folgenden Werte basierend auf den Eigenschaften Ihres Projekts abgeleitet:

  • Wenn Ihr Projekt eigenständig ist, wird das mcr.microsoft.com/dotnet/runtime-deps-Image als Basisimage verwendet.
  • Wenn Ihr Projekt ein ASP.NET Core-Projekt ist, wird das mcr.microsoft.com/dotnet/aspnet-Image als Basisimage verwendet.
  • Andernfalls wird das mcr.microsoft.com/dotnet/runtime-Image als Basisimage verwendet.

Das Tag des Images wird als numerische Komponente des ausgewählten TargetFramework abgeleitet. Beispielsweise führt ein Projekt für net6.0 zum 6.0-Tag des abgeleiteten Basisimages, und ein net7.0-linux-Projekt verwendet das 7.0-Tag usw.

Wenn Sie hier einen Wert festlegen, müssen Sie den vollständig qualifizierten Namen des Images festlegen, das Sie als Basis verwenden möchten, einschließlich aller von Ihnen gewünschten Tags:

<PropertyGroup>
    <ContainerBaseImage>mcr.microsoft.com/dotnet/runtime:8.0</ContainerBaseImage>
</PropertyGroup>
<PropertyGroup>
    <ContainerBaseImage>mcr.microsoft.com/dotnet/runtime:7.0</ContainerBaseImage>
</PropertyGroup>

ContainerFamily

Ab .NET 8 können Sie die MSBuild-Eigenschaft ContainerFamily verwenden, um eine andere Familie von Microsoft-Containerimages als Basisimage für Ihre App auszuwählen. Wenn dieser Wert festgelegt ist, wird er am Ende des ausgewählten TFM-spezifischen Tags angefügt, wobei das angegebene Tag geändert wird. Um beispielsweise die Alpine Linux-Varianten der .NET-Basisimages zu verwenden, können Sie ContainerFamily auf alpine festlegen:

<PropertyGroup>
    <ContainerFamily>alpine</ContainerFamily>
</PropertyGroup>

Die vorherige Projektkonfiguration führt zum endgültigen Tag 8.0-alpine für eine .NET 8-App.

Dieses Feld ist ein Freiformfeld und kann häufig verwendet werden, um verschiedene Betriebssystemdistributionen, Standardpaketkonfigurationen oder andere Änderungsflavors für ein Basisimage auszuwählen. Dieses Feld wird ignoriert, wenn ContainerBaseImage festgelegt ist. Weitere Informationen finden Sie unter .NET-Containerimages.

ContainerRuntimeIdentifier

Die Eigenschaft „ContainerRuntimeIdentifier“ steuert das Betriebssystem und die Architektur, die von Ihrem Container verwendet werden, wenn ContainerBaseImage mehr als eine Plattform unterstützt. Beispielsweise unterstützt das Image mcr.microsoft.com/dotnet/runtime derzeit die Images linux-x64, linux-arm, linux-arm64 und win10-x64 hinter demselben Tag. Daher muss dem Tool mitgeteilt werden, welche dieser Versionen Sie verwenden möchten. Standardmäßig wird diese Option auf den RuntimeIdentifier-Wert festgelegt, den Sie beim Veröffentlichen des Containers ausgewählt haben. Diese Eigenschaft muss selten explizit festgelegt werden. Verwenden Sie stattdessen die Option -r für den Befehl dotnet publish. Wenn das von Ihnen ausgewählte Image den von Ihnen ausgewählten RuntimeIdentifier-Wert nicht unterstützt, wird eine Fehlermeldung mit den RuntimeIdentifiers-Werten angezeigt, die vom Image unterstützt werden.

Sie können die Eigenschaft ContainerBaseImage immer auf einen vollqualifizierten Imagenamen festlegen, einschließlich des Tags, um diese Eigenschaft überhaupt nicht verwenden zu müssen.

<PropertyGroup>
    <ContainerRuntimeIdentifier>linux-arm64</ContainerRuntimeIdentifier>
</PropertyGroup>

Weitere Informationen zu den von .NET unterstützten Runtime-IDs finden Sie im RID-Katalog.

ContainerRegistry

Die Eigenschaft „Containerregistrierung“ steuert die Zielregistrierung und damit den Speicherort, in den das neu erstellte Image gepusht wird. Standardmäßig wird an den lokalen Docker-Daemon gepusht, Sie können aber auch eine Remoteregistrierung angeben. Wenn Sie eine Remoteregistrierung verwenden, die eine Authentifizierung erfordert, authentifizieren Sie sich mithilfe der bekannten docker login-Mechanismen. Weitere Informationen finden Sie unter Authentifizieren bei Containerregistrierungen. Ein konkretes Beispiel für die Verwendung dieser Eigenschaft finden Sie im folgenden XML-Beispiel:

<PropertyGroup>
    <ContainerRegistry>registry.mycorp.com:1234</ContainerRegistry>
</PropertyGroup>

Dieses Tool unterstützt die Veröffentlichung in jeder Registrierung, die die HTTP-API V2 der Docker-Registrierung unterstützt. Dies schließt explizit die folgenden Registrierungen ein (und implizit wahrscheinlich noch viel mehr):

Hinweise zur Verwendung dieser Registrierungen finden Sie in den registrierungsspezifischen Hinweisen.

ContainerRepository

Das Containerrepository ist der Name des Images selbst, z. B. dotnet/runtime oder my-app. Standardmäßig wird der AssemblyName des Projekts verwendet.

<PropertyGroup>
    <ContainerRepository>my-app</ContainerRepository>
</PropertyGroup>

ContainerImageName

Der Name des Containerimages bestimmt den Namen des Images selbst, z. B dotnet/runtime oder my-app. Standardmäßig wird der AssemblyName des Projekts verwendet.

<PropertyGroup>
    <ContainerImageName>my-app</ContainerImageName>
</PropertyGroup>

Hinweis

Ab .NET 8 ist ContainerImageName zugunsten von ContainerRepository veraltet.

Imagenamen bestehen aus einem oder mehreren durch Schrägstrich getrennten Segmenten, von denen jedes nur alphanumerische Kleinbuchstaben, Punkte, Unterstriche und Bindestriche enthalten darf und mit einem Buchstaben oder einer Zahl beginnen muss. Alle anderen Zeichen führen dazu, dass ein Fehler ausgelöst wird.

ContainerImageTag(s)

Die Eigenschaft „Containerimagetag“ bestimmt die Tags, die für das Image generiert werden. Um ein einzelnes Tag anzugeben, verwenden Sie ContainerImageTag. Für mehrere Tags verwenden Sie ContainerImageTags.

Wichtig

Wenn Sie ContainerImageTagsverwenden, erhalten Sie mehrere Images: eines pro eindeutigem Tag.

Tags dienen häufig zum Verweisen auf verschiedene Versionen einer App. Sie können aber auch auf verschiedene Betriebssystemdistributionen oder sogar unterschiedliche Konfigurationen verweisen.

Ab .NET 8 lautet der Standardwert latest, wenn kein Tag angegeben wird.

Standardmäßig wird die Version des Projekts als Tagwert verwendet.

Um die Standardeinstellung zu überschreiben, geben Sie eine der folgenden Optionen an:

<PropertyGroup>
    <ContainerImageTag>1.2.3-alpha2</ContainerImageTag>
</PropertyGroup>

Um mehrere Tags anzugeben, geben Sie in der Eigenschaft ContainerImageTags eine durch Semikolon getrennte Reihe von Tags an, ähnlich wie beim Festlegen mehrerer TargetFrameworks:

<PropertyGroup>
    <ContainerImageTags>1.2.3-alpha2;latest</ContainerImageTags>
</PropertyGroup>

Tags dürfen nur maximal 127 alphanumerische Zeichen, Punkte, Unterstriche und Bindestriche enthalten. Sie müssen mit einem alphanumerischen Zeichen oder Unterstrich beginnen. Jedes andere Format führt dazu, dass ein Fehler ausgelöst wird.

Hinweis

Bei Verwendung von ContainerImageTags werden die Tags durch ein ;-Zeichen getrennt. Wenn Sie dotnet publish über die Befehlszeile aufrufen (wie bei den meisten CI/CD-Umgebungen), müssen Sie die Werte mit einem einzelnen ' umschließen und im Inneren in doppelte Anführungszeichen (") einschließen, zum Beispiel: ='"tag-1;tag-2"'. Betrachten Sie folgenden dotnet publish-Befehl:

dotnet publish -p ContainerImageTags='"1.2.3-alpha2;latest"'

Das führt dazu, dass zwei Images generiert werden: my-app:1.2.3-alpha2 und my-app:latest.

Tipp

Wenn Probleme mit der ContainerImageTags-Eigenschaft auftreten, sollten Sie stattdessen die Umgebungsvariable ContainerImageTags festlegen:

ContainerImageTags='1.2.3;latest' dotnet publish

ContainerLabel

Die Containerbezeichnung fügt dem Container eine Metadatenbezeichnung hinzu. Bezeichnungen haben zur Laufzeit keine Auswirkungen auf den Container, werden aber häufig zum Speichern von Versions- und Erstellungsmetadaten zur Verwendung durch Sicherheitsscanner und andere Infrastrukturtools genutzt. Sie können eine beliebige Anzahl von Containerbezeichnungen angeben.

Der Knoten ContainerLabel hat zwei Attribute:

  • Include: der Schlüssel der Bezeichnung.
  • Value: der Wert der Bezeichnung (darf leer sein).
<ItemGroup>
    <ContainerLabel Include="org.contoso.businessunit" Value="contoso-university" />
</ItemGroup>

Eine Liste der standardmäßig erstellten Bezeichnungen finden Sie unter Standardcontainerbezeichnungen.

Konfigurieren der Containerausführung

Um die Ausführung des Containers zu steuern, können Sie die folgenden MSBuild-Eigenschaften verwenden.

ContainerWorkingDirectory

Der Knoten mit dem Containerarbeitsverzeichnis bestimmt das Arbeitsverzeichnis des Containers, also das Verzeichnis, in dem Befehle ausgeführt werden, wenn kein anderer Befehl ausgeführt wird.

Standardmäßig wird der Verzeichniswert /app als Arbeitsverzeichnis verwendet.

<PropertyGroup>
    <ContainerWorkingDirectory>/bin</ContainerWorkingDirectory>
</PropertyGroup>

ContainerPort

Der Containerport fügt der Liste der bekannten Ports für den Container TCP- oder UDP-Ports hinzu. Dadurch können Containerruntimes wie Docker diese Ports automatisch dem Hostcomputer zuordnen. Dies wird häufig als Dokumentation für den Container verwendet, kann aber auch zum Aktivieren der automatischen Portzuordnung dienen.

Der Knoten ContainerPort hat zwei Attribute:

  • Include: die Portnummer, die verfügbar gemacht werden soll.
  • Type: standardmäßig tcp, gültige Werte sind tcp oder udp.
<ItemGroup>
    <ContainerPort Include="80" Type="tcp" />
</ItemGroup>

Ab .NET 8 wird ContainerPort basierend auf mehreren bekannten ASP.NET-Umgebungsvariablen abgeleitet, wenn der Wert nicht explizit angegeben wird:

  • ASPNETCORE_URLS
  • ASPNETCORE_HTTP_PORTS
  • ASPNETCORE_HTTPS_PORTS

Wenn diese Umgebungsvariablen vorhanden sind, werden ihre Werte analysiert und in TCP-Portzuordnungen konvertiert. Diese Umgebungsvariablen werden aus Ihrem Basisimage gelesen, sofern vorhanden, oder aus den Umgebungsvariablen, die in Ihrem Projekt definiert sind, über ContainerEnvironmentVariable-Elemente. Weitere Informationen finden Sie unter ContainerEnvironmentVariable.

ContainerEnvironmentVariable

Der Knoten für die Umgebungsvariablen des Containers ermöglicht Ihnen, dem Container Umgebungsvariablen hinzuzufügen. Umgebungsvariablen sind für die im Container ausgeführte App unmittelbar zugänglich und dienen häufig dazu, das Laufzeitverhalten der ausgeführten App zu ändern.

Der Knoten ContainerEnvironmentVariable hat zwei Attribute:

  • Include: der Name der Umgebungsvariablen.
  • Value: der Wert der Umgebungsvariablen.
<ItemGroup>
  <ContainerEnvironmentVariable Include="LOGGER_VERBOSITY" Value="Trace" />
</ItemGroup>

Weitere Informationen finden Sie unter .NET-Umgebungsvariablen.

Konfigurieren von Containerbefehlen

Standardmäßig starten die Containertools Ihre App entweder mit der generierten AppHost-Binärdatei für Ihre App (wenn Ihre App einen AppHost verwendet) oder durch den Befehl dotnet und die DLL Ihrer App.

Sie können jedoch steuern, wie Ihre App ausgeführt wird, indem Sie eine Kombination aus ContainerAppCommand, ContainerAppCommandArgs, ContainerDefaultArgs und ContainerAppCommandInstruction verwenden.

Diese unterschiedlichen Konfigurationspunkte sind vorhanden, da unterschiedliche Basisimages unterschiedliche Kombinationen der Containereigenschaften ENTRYPOINT und COMMAND verwenden, und alle davon unterstützt werden sollen. Die Standardwerte sollten von den meisten Apps verwendet werden können. Wenn Sie das App-Startverhalten jedoch anpassen möchten, sollten Sie:

  • die auszuführende Binärdatei ermitteln und als ContainerAppCommand festlegen
  • ermitteln, welche Argumente für die Ausführung Ihrer Anwendung erforderlich sind, und diese als ContainerAppCommandArgs festlegen
  • ermitteln, welche Argumente (falls vorhanden) optional sind und von Benutzer*innen überschrieben werden können und diese als ContainerDefaultArgs festlegen
  • Legen Sie ContainerAppCommandInstruction auf DefaultArgs fest.

Weitere Informationen finden Sie in den folgenden Konfigurationselementen.

ContainerAppCommand

Das ContainerAppCommand-Konfigurationselement ist der logische Einstiegspunkt Ihrer App. Für die meisten Apps ist dies der AppHost, die generierte ausführbare Binärdatei für Ihre App. Wenn Ihre App keinen AppHost generiert, lautet dieser Befehl in der Regel dotnet <your project dll>. Diese Werte werden nach jedem ENTRYPOINT-Element in Ihrem Basiscontainer oder direkt angewendet, wenn kein ENTRYPOINT-Element definiert ist.

Die ContainerAppCommand-Konfiguration weist eine einzelne Include-Eigenschaft auf, die den Befehl, die Option oder das Argument darstellt, die im Einstiegspunktbefehl verwendet werden sollen:

<ItemGroup Label="ContainerAppCommand Assignment">
  <!-- This is how you would start the dotnet ef tool in your container -->
  <ContainerAppCommand Include="dotnet" />
  <ContainerAppCommand Include="ef" />

  <!-- This shorthand syntax means the same thing, note the semicolon separating the tokens. -->
  <ContainerAppCommand Include="dotnet;ef" />
</ItemGroup>

ContainerAppCommandArgs

Dieses ContainerAppCommandArgs-Konfigurationselement stellt alle logisch erforderlichen Argumente für Ihre App dar, die auf ContainerAppCommand angewendet werden sollen. Standardmäßig werden keine für eine App generiert. Wenn vorhanden, werden die Argumente auf Ihren Container angewendet, wenn er ausgeführt wird.

Die ContainerAppCommandArgs-Konfiguration verfügt über eine einzelne Include-Eigenschaft, die die Option oder das Argument darstellt, die auf den Befehl ContainerAppCommand angewendet werden soll.

<ItemGroup>
  <!-- Assuming the ContainerAppCommand defined above, 
       this would be the way to force the database to update.
  -->
  <ContainerAppCommandArgs Include="database" />
  <ContainerAppCommandArgs Include="update" />

  <!-- This is the shorthand syntax for the same idea -->
  <ContainerAppCommandArgs Include="database;update" />
</ItemGroup>

ContainerDefaultArgs

Dieses ContainerDefaultArgs-Konfigurationselement stellt alle durch Benutzer*innen überschreibbaren Argumente für Ihre App dar. Das ist eine gute Möglichkeit, Standardwerte anzugeben, die Ihre App benötigt, um leicht gestartet und angepasst werden zu können.

Die ContainerDefaultArgs-Konfiguration verfügt über eine einzelne Include-Eigenschaft, die die Option oder das Argument darstellt, die auf den Befehl ContainerAppCommand angewendet werden soll.

<ItemGroup>
  <!-- Assuming the ContainerAppCommand defined above, 
       this would be the way to force the database to update.
  -->
  <ContainerDefaultArgs Include="database" />
  <ContainerDefaultArgs Include="update" />

  <!-- This is the shorthand syntax for the same idea -->
  <ContainerDefaultArgs Include="database;update" />
</ItemGroup>

ContainerAppCommandInstruction

Mit der ContainerAppCommandInstruction-Konfiguration können Sie steuern, wie die ContainerEntrypoint, ContainerEntrypointArgs, ContainerAppCommand, ContainerAppCommandArgs und ContainerDefaultArgs kombiniert werden, um den endgültigen Befehl zu bilden, der im Container ausgeführt wird. Hierbei ist maßgeblich, ob ENTRYPOINT im Basisimage vorhanden ist. Diese Eigenschaft akzeptiert einen von drei Werten: "DefaultArgs", "Entrypoint" oder "None".

  • Entrypoint:
    • In diesem Modus wird der Einstiegspunkt durch ContainerAppCommand, ContainerAppCommandArgs und ContainerDefaultArgs definiert.
  • None:
    • In diesem Modus wird der Einstiegspunkt durch ContainerEntrypoint, ContainerEntrypointArgs und ContainerDefaultArgs definiert.
  • DefaultArgs:
    • Dies ist der komplexeste Modus. Wenn keines der ContainerEntrypoint[Args]-Elemente vorhanden ist, werden ContainerAppCommand[Args] und ContainerDefaultArgs zum Erstellen des Einstiegspunkts und Befehls verwendet. Wenn der Einstiegspunkt für Basisimages auf dotnet oder /usr/bin/dotnet hartcodiert ist, wird er übersprungen, sodass Sie die vollständige Kontrolle haben.
    • Wenn sowohl ContainerEntrypoint als auch ContainerAppCommand vorhanden sind, wird ContainerEntrypoint zum Einstiegspunkt, und ContainerAppCommand wird zum Befehl.

Hinweis

Die Konfigurationselemente ContainerEntrypoint und ContainerEntrypointArgs sind ab .NET 8 veraltet.

Wichtig

Dies gilt für fortgeschrittene Benutzer*innen: Die meisten Apps sollten ihren Einstiegspunkt nicht in diesem Maß anpassen müssen. In den Diskussionen zu .NET SDK-Containerbuilds auf GitHub finden Sie weitere Informationen oder können Anwendungsfälle für Ihre Szenarios posten.

ContainerUser

Die Benutzerkonfigurationseigenschaft steuert den Standardbenutzer, der den Container ausführt. Dieser wird häufig verwendet, um den Container als Nicht-Root-Benutzer auszuführen, was eine bewährte Methode für die Sicherheit ist. Es gibt einige Einschränkungen für diese Konfiguration, die Sie beachten sollten:

  • Sie kann verschiedene Formate aufweisen (Benutzernamen, Linux-Benutzer-IDs, Gruppenname, Linux-Gruppen-ID, username:groupname und andere ID-Varianten).
  • Es gibt keine Überprüfung, dass der angegebene Benutzer oder die angegebene Gruppe im Image vorhanden ist.
  • Das Ändern des Benutzers kann das Verhalten der App beeinflussen, insbesondere in Bezug auf Aspekte wie Dateisystemberechtigungen.

Der Standardwert dieses Felds variiert je nach Projekt-TFM und Zielbetriebssystem:

  • Wenn die Zielversion .NET 8 oder höher ist und Sie Microsoft-Runtimeimages verwenden:
    • Unter Linux wird der Nicht-Root-Benutzer app verwendet (per Benutzer-ID angegeben)
    • Unter Windows wird der Nicht-Root-Benutzer ContainerUser verwendet
  • Andernfalls wird standardmäßig kein ContainerUser verwendet.
<PropertyGroup>
  <ContainerUser>my-existing-app-user</ContainerUser>
</PropertyGroup>

Tipp

Die Umgebungsvariable APP_UID wird verwendet, um Benutzerinformationen in Ihrem Container festzulegen. Dieser Wert kann aus Umgebungsvariablen stammen, die in Ihrem Basisimage definiert sind (z. B. Microsoft .NET-Images), oder Sie können ihn über die ContainerEnvironmentVariable-Syntax festlegen.

Sie können jedoch mithilfe von ContainerEntrypoint und ContainerEntrypointArgs steuern, wie Ihre App ausgeführt wird.

ContainerEntrypoint

Mithilfe des Containereinstiegspunkts kann der ENTRYPOINT des Containers angepasst werden. Dabei handelt es sich um die ausführbare Datei, die beim Starten des Containers aufgerufen wird. Bei Builds, die einen App-Host erstellen, ist er standardmäßig auf ContainerEntrypoint festgelegt. Bei Builds, die keine ausführbare Datei erstellen, wird dotnet path/to/app.dll als ContainerEntrypoint verwendet.

Der Knoten ContainerEntrypoint hat ein einzelnes Attribut:

  • Include: der Befehl, die Option oder das Argument zur Verwendung im Befehl ContainerEntrypoint.

Betrachten Sie beispielsweise das folgende Beispiel einer .NET-Projektelementgruppe:

<ItemGroup Label="Entrypoint Assignment">
  <!-- This is how you would start the dotnet ef tool in your container -->
  <ContainerEntrypoint Include="dotnet" />
  <ContainerEntrypoint Include="ef" />

  <!-- This shorthand syntax means the same thing.
       Note the semicolon separating the tokens. -->
  <ContainerEntrypoint Include="dotnet;ef" />
</ItemGroup>

ContainerEntrypointArgs

Der Knoten „Args“ des Containereinstiegspunkts bestimmt die Standardargumente, die ContainerEntrypoint bereitgestellt werden. Er sollte verwendet werden, wenn ContainerEntrypoint ein Programm ist, das der Benutzer möglicherweise eigenständig verwenden möchte. Standardmäßig werden keine ContainerEntrypointArgs in Ihrem Auftrag erstellt.

Der Knoten ContainerEntrypointArg hat ein einzelnes Attribut:

  • Include: Die Option oder das Argument, die/das auf den Befehl ContainerEntrypoint angewendet werden soll.

Betrachten Sie die folgende .NET-Projektelementgruppe:

<ItemGroup>
  <!-- Assuming the ContainerEntrypoint defined above,
       this would be the way to update the database by
       default, but let the user run a different EF command. -->
  <ContainerEntrypointArgs Include="database" />
  <ContainerEntrypointArgs Include="update" />

  <!-- This is the shorthand syntax for the same idea -->
  <ContainerEntrypointArgs Include="database;update" />
</ItemGroup>

Standardcontainerbezeichnungen

Bezeichnungen werden häufig verwendet, um konsistente Metadaten für Containerimages bereitzustellen. Dieses Paket enthält einige Standardbezeichnungen, um die generierten Images besser pflegen zu können.

  • org.opencontainers.image.created ist auf das ISO 8601-Format der aktuellen DateTime-Angabe in UTC festgelegt.

Weitere Informationen finden Sie unter Implementieren herkömmlicher Bezeichnungen in einer vorhandenen Bezeichnungsinfrastruktur.

Bereinigen von Ressourcen

In diesem Artikel haben Sie einen .NET-Worker als Containerimage veröffentlicht. Wenn Sie möchten, können Sie diese Ressource löschen. Verwenden Sie den Befehl „docker images“, um eine Liste der installierten Images anzuzeigen.

docker images

Betrachten Sie die folgende Beispielausgabe:

REPOSITORY            TAG       IMAGE ID       CREATED          SIZE
dotnet-worker-image   1.0.0     25aeb97a2e21   12 seconds ago   191MB

Tipp

Imagedateien können groß sein. Normalerweise würden Sie temporäre Container entfernen, die Sie während des Tests und der Entwicklung Ihrer App erstellt haben. In der Regel behalten Sie die Basisimages mit installierter Runtime, wenn Sie planen, andere Images auf Basis dieser Runtime zu erstellen.

Um das Image zu löschen, kopieren Sie die Image-ID und führen den Befehl docker image rm aus:

docker image rm 25aeb97a2e21

Nächste Schritte