Conteneuriser une référence d’application .NET
Dans cet article de référence, vous allez apprendre à configurer l’image conteneur générée lorsque vous publiez une application .NET en tant que conteneur. Cet article décrit les différentes propriétés que vous pouvez définir pour contrôler l’image, l’environnement d’exécution et les commandes exécutées au démarrage du conteneur.
Configurer l’image conteneur
Vous pouvez contrôler de nombreux aspects du conteneur généré via les propriétés MSBuild. En règle générale, si vous pouvez utiliser une commande dans un Dockerfile pour définir une configuration, vous pouvez effectuer la même opération via MSBuild.
Note
Les seules exceptions à ce problème sont RUN
commandes. En raison de la façon dont les conteneurs sont générés, ceux-ci ne peuvent pas être émulés. Si vous avez besoin de cette fonctionnalité, vous pouvez envisager d’utiliser un dockerfile pour générer vos images conteneur.
Il n’existe aucun moyen d’effectuer des commandes RUN
avec le Kit de développement logiciel (SDK) .NET. Ces commandes sont souvent utilisées pour installer certains packages de système d’exploitation ou créer un utilisateur de système d’exploitation, ou tout nombre d’éléments arbitraires. Si vous souhaitez continuer à utiliser la fonctionnalité de génération de conteneurs du Kit de développement logiciel (SDK) .NET, vous pouvez plutôt créer une image de base personnalisée avec ces modifications, puis utiliser cette image de base. Pour plus d’informations, consultez ContainerBaseImage
.
ContainerArchiveOutputPath
Pour créer une image conteneur dans une archive tar.gz, utilisez la propriété ContainerArchiveOutputPath
. Cette fonctionnalité est utile si votre flux de travail n’est pas simple et nécessite que vous, par exemple, exécutez un outil d’analyse sur vos images avant de les envoyer (push). Une fois l’archive créée, vous pouvez la déplacer, l’analyser ou la charger dans une chaîne d’outils Docker locale.
Pour publier dans une archive, ajoutez la propriété ContainerArchiveOutputPath
à votre commande dotnet publish
, par exemple :
dotnet publish \
-p PublishProfile=DefaultContainer \
-p ContainerArchiveOutputPath=./images/sdk-container-demo.tar.gz
Vous pouvez spécifier un nom de dossier ou un chemin d’accès avec un nom de fichier spécifique. Si vous spécifiez le nom du dossier, le nom de fichier généré pour le fichier d’archive d’images est nommé $(ContainerRepository).tar.gz
. Ces archives peuvent contenir plusieurs balises à l’intérieur de celles-ci, car un seul fichier est créé pour toutes les ContainerImageTags
.
Configuration du nommage d’images conteneur
Les images conteneur suivent une convention d’affectation de noms spécifique. Le nom de l’image est composé de plusieurs parties, du registre, du port facultatif, du référentiel et de la famille et des balises facultatives.
REGISTRY[:PORT]/REPOSITORY[:TAG[-FAMILY]]
Par exemple, considérez le nom complet de l’image mcr.microsoft.com/dotnet/runtime:8.0-alpine
:
-
mcr.microsoft.com
est le registre (et, dans ce cas, représente le registre de conteneurs Microsoft). -
dotnet/runtime
est le référentiel (mais certains considèrent cetteuser/repository
). -
8.0-alpine
est la balise et la famille (la famille est un spécificateur facultatif qui permet de lever l’ambiguïté de l’empaquetage du système d’exploitation).
Certaines propriétés décrites dans les sections suivantes correspondent à la gestion des parties du nom de l’image générée. Considérez le tableau suivant qui mappe la relation entre le nom de l’image et les propriétés de build :
Partie nom de l’image | MSBuild, propriété | Exemples de valeurs |
---|---|---|
REGISTRY[:PORT] |
ContainerRegistry |
mcr.microsoft.com:443 |
PORT |
ContainerPort |
:443 |
REPOSITORY |
ContainerRepository |
dotnet/runtime |
TAG |
ContainerImageTag |
8.0 |
FAMILY |
ContainerFamily |
-alpine |
Les sections suivantes décrivent les différentes propriétés qui peuvent être utilisées pour contrôler l’image conteneur générée.
ContainerBaseImage
La propriété d’image de base de conteneur contrôle l’image utilisée comme base pour votre image. Par défaut, les valeurs suivantes sont déduites en fonction des propriétés de votre projet :
- Si votre projet est autonome, l’image
mcr.microsoft.com/dotnet/runtime-deps
est utilisée comme image de base. - Si votre projet est un projet ASP.NET Core, l’image
mcr.microsoft.com/dotnet/aspnet
est utilisée comme image de base. - Sinon, l’image
mcr.microsoft.com/dotnet/runtime
est utilisée comme image de base.
La balise de l’image est déduite comme composant numérique de votre TargetFramework
choisie. Par exemple, un projet ciblant net6.0
génère la balise 6.0
de l’image de base déduite, et un projet net7.0-linux
utilise la balise 7.0
, et ainsi de suite.
Si vous définissez une valeur ici, vous devez définir le nom complet de l’image à utiliser comme base, y compris toute balise que vous préférez :
<PropertyGroup>
<ContainerBaseImage>mcr.microsoft.com/dotnet/runtime:8.0</ContainerBaseImage>
</PropertyGroup>
Avec le Kit de développement logiciel (SDK) .NET version 8.0.200, l’inférence ContainerBaseImage
est améliorée pour optimiser la taille et la sécurité :
- Le ciblage des identificateurs d'
linux-musl-x64
ou d'linux-musl-arm64
runtime choisit automatiquement les variantes d’imagealpine
pour vous assurer que votre projet s’exécute :- Si le projet utilise
PublishAot=true
, la variantenightly/runtime-deps
jammy-chiseled-aot
de l’image de base pour une taille et une sécurité optimales. - Si le projet utilise
InvariantGlobalization=false
, les variantes-extra
sont utilisées pour garantir que la localisation fonctionne toujours.
- Si le projet utilise
Pour plus d’informations sur les tailles et les caractéristiques des variantes d’image, consultez rapport de taille d’image conteneur .NET 8.0.
ContainerFamily
À compter de .NET 8, vous pouvez utiliser la propriété ContainerFamily
MSBuild pour choisir une autre famille d’images conteneur fournies par Microsoft comme image de base pour votre application. Quand elle est définie, cette valeur est ajoutée à la fin de la balise spécifique au TFM sélectionnée, en modifiant la balise fournie. Par exemple, pour utiliser les variantes Alpine Linux des images de base .NET, vous pouvez définir ContainerFamily
sur alpine
:
<PropertyGroup>
<ContainerFamily>alpine</ContainerFamily>
</PropertyGroup>
La configuration de projet précédente génère une balise finale de 8.0-alpine
pour une application cible .NET 8.
Ce champ est libre et peut souvent être utilisé pour sélectionner différentes distributions de système d’exploitation, configurations de package par défaut ou toute autre saveur des modifications apportées à une image de base. Ce champ est ignoré lorsque ContainerBaseImage
est défini. Pour plus d’informations, consultez images conteneur .NET.
ContainerRuntimeIdentifier
La propriété ContainerRuntimeIdentifier
spécifie le système d’exploitation et l’architecture de votre conteneur si le ContainerBaseImage
prend en charge plusieurs plateformes. Par exemple, l’image mcr.microsoft.com/dotnet/runtime
prend en charge linux-x64
, linux-arm
, linux-arm64
et win10-x64
. Par défaut, cette valeur est définie sur la RuntimeIdentifier
utilisée lors de la publication du conteneur. En règle générale, vous n’avez pas besoin de définir cette propriété explicitement ; Utilisez plutôt l’option -r
avec la commande dotnet publish
. Si l’image choisie ne prend pas en charge la RuntimeIdentifier
spécifiée, une erreur indique les identificateurs pris en charge.
Vous pouvez toujours définir la propriété ContainerBaseImage
sur un nom d’image complet, y compris la balise, pour éviter d’avoir à utiliser cette propriété du tout.
<PropertyGroup>
<ContainerRuntimeIdentifier>linux-arm64</ContainerRuntimeIdentifier>
</PropertyGroup>
Pour plus d’informations sur les identificateurs d’exécution pris en charge par .NET, consultez catalogue RID.
ContainerRegistry
La propriété de registre de conteneurs contrôle le registre de destination, l’emplacement vers lequel l’image nouvellement créée sera envoyée. Par défaut, il est envoyé (push) au démon Docker local, mais vous pouvez également spécifier un registre distant. Lorsque vous utilisez un Registre distant qui nécessite une authentification, vous vous authentifiez à l’aide des mécanismes de docker login
connus. Pour plus d’informations, consultez l’authentification auprès des registres de conteneurs pour plus d’informations. Pour obtenir un exemple concret d’utilisation de cette propriété, considérez l’exemple XML suivant :
<PropertyGroup>
<ContainerRegistry>registry.mycorp.com:1234</ContainerRegistry>
</PropertyGroup>
Cet outil prend en charge la publication sur n’importe quel registre qui prend en charge l’API HTTP du Registre Docker V2. Cela inclut explicitement les registres suivants (et probablement beaucoup plus implicitement) :
- Azure Container Registry
- Amazon Elastic Container Registry
- Google Artifact Registry
- Docker Hub
- packages GitHub
- de Registre de conteneurs hébergé par GitLab
- Quay.io
Pour obtenir des notes sur l’utilisation de ces registres, consultez les notes spécifiques au Registre.
ContainerRepository
Le référentiel de conteneurs est le nom de l’image elle-même, par exemple, dotnet/runtime
ou my-app
. Par défaut, la AssemblyName
du projet est utilisée.
<PropertyGroup>
<ContainerRepository>my-app</ContainerRepository>
</PropertyGroup>
Les noms d’images se composent d’un ou plusieurs segments délimités par des barres obliques, chacun pouvant contenir uniquement des caractères alphanumériques minuscules, des points, des traits de soulignement et des tirets, et doit commencer par une lettre ou un nombre. Les autres caractères entraînent la levée d’une erreur.
ContainerImageTag(s)
La propriété de balise d’image conteneur contrôle les balises générées pour l’image. Pour spécifier une balise unique, utilisez ContainerImageTag
et pour plusieurs balises, utilisez ContainerImageTags
.
Important
Lorsque vous utilisez ContainerImageTags
, vous obtiendrez plusieurs images, une par balise unique.
Les balises sont souvent utilisées pour faire référence à différentes versions d’une application, mais elles peuvent également faire référence à différentes distributions de système d’exploitation, voire à différentes configurations.
À compter de .NET 8, lorsqu’une balise n’est pas fournie, la valeur par défaut est latest
.
Pour remplacer la valeur par défaut, spécifiez l’une des options suivantes :
<PropertyGroup>
<ContainerImageTag>1.2.3-alpha2</ContainerImageTag>
</PropertyGroup>
Pour spécifier plusieurs balises, utilisez un jeu de balises délimité par des points-virgules dans la propriété ContainerImageTags
, similaire à la définition de plusieurs TargetFrameworks
:
<PropertyGroup>
<ContainerImageTags>1.2.3-alpha2;latest</ContainerImageTags>
</PropertyGroup>
Les balises ne peuvent contenir que 127 caractères alphanumériques, points, traits de soulignement et tirets. Ils doivent commencer par un caractère alphanumérique ou un trait de soulignement. Tout autre formulaire entraîne une erreur levée.
Note
Lorsque vous utilisez ContainerImageTags
, les balises sont délimitées par un caractère ;
. Si vous appelez dotnet publish
à partir de la ligne de commande (comme c’est le cas avec la plupart des environnements CI/CD), vous devez encapsuler les valeurs dans une seule '
et un wrapper interne avec des guillemets doubles "
, par exemple (='"tag-1;tag-2"'
). Tenez compte de la commande dotnet publish
suivante :
dotnet publish -p ContainerImageTags='"1.2.3-alpha2;latest"'
Cela entraîne la génération de deux images : my-app:1.2.3-alpha2
et my-app:latest
.
Pourboire
Si vous rencontrez des problèmes avec la propriété ContainerImageTags
, envisagez de définir une variable d’environnement ContainerImageTags
à la place :
$Env:ContainerImageTags='1.2.3;latest'; dotnet publish --os linux --arch x64 /t:PublishContainer
ContainerLabel
L’étiquette de conteneur ajoute une étiquette de métadonnées au conteneur. Les étiquettes sont souvent utilisées pour stocker les métadonnées de version et de création à utiliser par les scanneurs de sécurité et d’autres outils d’infrastructure. Vous pouvez spécifier n’importe quel nombre d’étiquettes de conteneur.
Le nœud ContainerLabel
a deux attributs :
-
Include
: clé de l’étiquette. -
Value
: valeur de l’étiquette (cela peut être vide).
<ItemGroup>
<ContainerLabel Include="org.contoso.businessunit" Value="contoso-university" />
</ItemGroup>
Pour obtenir la liste des étiquettes créées par défaut, consultez étiquettes de conteneur par défaut.
Configurer l’exécution du conteneur
Pour contrôler l’exécution du conteneur, vous pouvez utiliser les propriétés MSBuild suivantes.
ContainerWorkingDirectory
Le nœud de répertoire de travail du conteneur contrôle le répertoire de travail du conteneur, le répertoire dans lequel les commandes sont exécutées si aucune autre commande n’est exécutée.
Par défaut, la valeur du répertoire /app
est utilisée comme répertoire de travail.
<PropertyGroup>
<ContainerWorkingDirectory>/bin</ContainerWorkingDirectory>
</PropertyGroup>
ContainerPort
Le port de conteneur ajoute des ports TCP (Transmission Control Protocol) ou UDP (User Datagram Protocol) à la liste des ports connus pour le conteneur. Cela permet aux runtimes de conteneur tels que Docker de mapper ces ports à l’ordinateur hôte automatiquement. Cela est souvent utilisé comme documentation pour le conteneur, mais peut également être utilisé pour activer le mappage automatique des ports.
Le nœud ContainerPort
a deux attributs :
-
Include
: numéro de port à exposer. -
Type
: valeurs par défauttcp
, les valeurs valides sonttcp
ouudp
.
<ItemGroup>
<ContainerPort Include="80" Type="tcp" />
</ItemGroup>
À compter de .NET 8, le ContainerPort
est déduit lorsqu’il n’est pas fourni explicitement en fonction de plusieurs variables d’environnement ASP.NET connues :
ASPNETCORE_URLS
ASPNETCORE_HTTP_PORTS
ASPNETCORE_HTTPS_PORTS
Si ces variables d’environnement sont présentes, leurs valeurs sont analysées et converties en mappages de ports TCP. Ces variables d’environnement sont lues à partir de votre image de base, le cas échéant, ou à partir des variables d’environnement définies dans votre projet via ContainerEnvironmentVariable
éléments. Pour plus d’informations, consultez ContainerEnvironmentVariable.
ContainerEnvironmentVariable
Le nœud de variable d’environnement de conteneur vous permet d’ajouter des variables d’environnement au conteneur. Les variables d’environnement sont accessibles à l’application s’exécutant immédiatement dans le conteneur et sont souvent utilisées pour modifier le comportement d’exécution de l’application en cours d’exécution.
Le nœud ContainerEnvironmentVariable
a deux attributs :
-
Include
: nom de la variable d’environnement. -
Value
: valeur de la variable d’environnement.
<ItemGroup>
<ContainerEnvironmentVariable Include="LOGGER_VERBOSITY" Value="Trace" />
</ItemGroup>
Pour plus d’informations, consultez variables d’environnement .NET.
Note
Il n’est actuellement pas possible de définir des variables d’environnement à partir de l’interface CLI .NET lors de la publication d’une image conteneur. Pour plus d’informations, consultez GitHub : les builds de conteneur du Kit de développement logiciel (SDK) .NET.
Configurer des commandes de conteneur
Par défaut, les outils de conteneur lancent votre application à l’aide du fichier binaire AppHost généré pour votre application (si votre application utilise un AppHost) ou de la commande dotnet
ainsi que la DLL de votre application.
Toutefois, vous pouvez contrôler l’exécution de votre application à l’aide d’une combinaison de ContainerAppCommand
, de ContainerAppCommandArgs
, de ContainerDefaultArgs
et de ContainerAppCommandInstruction
.
Ces différents points de configuration existent, car différentes images de base utilisent différentes combinaisons du conteneur ENTRYPOINT
et COMMAND
propriétés, et vous souhaitez pouvoir les prendre en charge. Les valeurs par défaut doivent être utilisables pour la plupart des applications, mais si vous souhaitez personnaliser le comportement de lancement de votre application, vous devez :
- Identifiez le fichier binaire à exécuter et définissez-le comme
ContainerAppCommand
- Identifiez quels arguments sont requis pour que votre application s’exécute et les définisse comme
ContainerAppCommandArgs
- Identifiez quels arguments (le cas échéant) sont facultatifs et peuvent être remplacés par un utilisateur et les définir comme
ContainerDefaultArgs
- Définir
ContainerAppCommandInstruction
surDefaultArgs
Pour plus d’informations, consultez les éléments de configuration suivants.
ContainerAppCommand
L’élément de configuration de la commande d’application est le point d’entrée logique de votre application. Pour la plupart des applications, il s’agit de AppHost, le fichier binaire exécutable généré pour votre application. Si votre application ne génère pas d’AppHost, cette commande est généralement dotnet <your project dll>
. Ces valeurs sont appliquées après une ENTRYPOINT
dans votre conteneur de base, ou directement si aucune ENTRYPOINT
n’est définie.
La configuration ContainerAppCommand
a une propriété Include
unique, qui représente la commande, l’option ou l’argument à utiliser dans la commande de point d’entrée :
<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
Cette commande d’application args élément de configuration représente tous les arguments logiquement requis pour votre application qui doivent être appliqués au ContainerAppCommand
. Par défaut, aucune n’est générée pour une application. Lorsqu’il est présent, les arguments sont appliqués à votre conteneur lorsqu’il est exécuté.
La configuration ContainerAppCommandArgs
a une propriété Include
unique, qui représente l’option ou l’argument à appliquer à la commande ContainerAppCommand
.
<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
Cet élément de configuration d’arguments par défaut représente tous les arguments substituables par l’utilisateur pour votre application. Il s’agit d’un bon moyen de fournir des valeurs par défaut que votre application peut avoir besoin d’exécuter de manière à faciliter le démarrage, mais toujours facile à personnaliser.
La configuration ContainerDefaultArgs
a une propriété Include
unique, qui représente l’option ou l’argument à appliquer à la commande ContainerAppCommand
.
<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
La configuration des instructions de commande d’application permet de contrôler la façon dont le ContainerEntrypoint
, ContainerEntrypointArgs
, ContainerAppCommand
, ContainerAppCommandArgs
et ContainerDefaultArgs
sont combinés pour former la commande finale exécutée dans le conteneur. Cela dépend considérablement si une ENTRYPOINT
est présente dans l’image de base. Cette propriété prend l’une des trois valeurs suivantes : "DefaultArgs"
, "Entrypoint"
ou "None"
.
-
Entrypoint
:- Dans ce mode, le point d’entrée est défini par
ContainerAppCommand
,ContainerAppCommandArgs
etContainerDefaultArgs
.
- Dans ce mode, le point d’entrée est défini par
-
None
:- Dans ce mode, le point d’entrée est défini par
ContainerEntrypoint
,ContainerEntrypointArgs
etContainerDefaultArgs
.
- Dans ce mode, le point d’entrée est défini par
-
DefaultArgs
:- Il s’agit du mode le plus complexe : si aucun des éléments
ContainerEntrypoint[Args]
n’est présent, lesContainerAppCommand[Args]
et lesContainerDefaultArgs
sont utilisés pour créer le point d’entrée et la commande. Le point d’entrée de l’image de base pour les images de base qui ont été codées en dur pourdotnet
ou/usr/bin/dotnet
est ignoré afin que vous ayez un contrôle complet. - Si
ContainerEntrypoint
etContainerAppCommand
sont présents,ContainerEntrypoint
devient le point d’entrée etContainerAppCommand
devient la commande.
- Il s’agit du mode le plus complexe : si aucun des éléments
Note
Les éléments de configuration ContainerEntrypoint
et ContainerEntrypointArgs
sont déconseillés à partir de .NET 8.
Important
Cela est destiné aux applications avancées que la plupart des utilisateurs n’ont pas besoin de personnaliser leur point d’entrée à ce degré. Pour plus d’informations et si vous souhaitez fournir des cas d’usage pour vos scénarios, consultez GitHub : conteneur du Kit de développement logiciel (SDK) .NET génère des discussions.
ContainerUser
La propriété de configuration utilisateur contrôle l’utilisateur par défaut sur lequel le conteneur s’exécute. Il est souvent utilisé pour exécuter le conteneur en tant qu’utilisateur non racine, qui est une bonne pratique pour la sécurité. Il existe quelques contraintes pour que cette configuration sache :
- Il peut prendre différentes formes : nom d’utilisateur, ID d’utilisateur Linux, nom du groupe, ID de groupe Linux,
username:groupname
et autres variantes d’ID. - Il n’existe aucune vérification indiquant que l’utilisateur ou le groupe spécifié existe sur l’image.
- La modification de l’utilisateur peut modifier le comportement de l’application, en particulier en ce qui concerne les éléments tels que autorisations de système de fichiers.
La valeur par défaut de ce champ varie selon le TFM du projet et le système d’exploitation cible :
- Si vous ciblez .NET 8 ou version ultérieure et que vous utilisez les images runtime Microsoft, puis :
- sur Linux, l’utilisateur sans racine
app
est utilisé (bien qu’il soit référencé par son ID d’utilisateur) - sur Windows, l’utilisateur sans racine
ContainerUser
est utilisé
- sur Linux, l’utilisateur sans racine
- Sinon, aucune
ContainerUser
par défaut n’est utilisée
<PropertyGroup>
<ContainerUser>my-existing-app-user</ContainerUser>
</PropertyGroup>
Pourboire
La variable d’environnement APP_UID
est utilisée pour définir les informations utilisateur dans votre conteneur. Cette valeur peut provenir de variables d’environnement définies dans votre image de base (comme les images Microsoft .NET) ou vous pouvez la définir vous-même via la syntaxe ContainerEnvironmentVariable
.
Pour configurer votre application pour qu’elle s’exécute en tant qu’utilisateur racine, définissez la propriété ContainerUser
sur root
. Dans votre fichier projet, ajoutez les éléments suivants :
<PropertyGroup>
<ContainerUser>root</ContainerUser>
</PropertyGroup>
Vous pouvez également définir cette valeur lors de l’appel de dotnet publish
à partir de la ligne de commande :
dotnet publish -p ContainerUser=root
Étiquettes de conteneur par défaut
Les étiquettes sont souvent utilisées pour fournir des métadonnées cohérentes sur des images conteneur. Ce package fournit certaines étiquettes par défaut pour favoriser une meilleure maintenance des images générées.
-
org.opencontainers.image.created
est défini sur le format ISO 8601 de la valeur actuelle de DateTime.UtcNow.
Pour plus d’informations, consultez Implémenter des étiquettes conventionnelles au-dessus de l’infrastructure d’étiquettes existante.
Voir aussi
- Containerize d’une application .NET avec de publication dotnet
- images conteneur .NET