Contenedorización de una referencia de aplicación de .NET
En este artículo de referencia, aprenderá a configurar la imagen de contenedor que se genera al publicar una aplicación .NET como contenedor. En este artículo se describen las distintas propiedades que puede establecer para controlar la imagen, el entorno de ejecución y los comandos que se ejecutan cuando se inicia el contenedor.
Configuración de la imagen de contenedor
Puede controlar muchos aspectos del contenedor generado a través de las propiedades de MSBuild. En general, si puede usar un comando en un Dockerfile para establecer alguna configuración, puede hacer lo mismo a través de MSBuild.
Nota
Las únicas excepciones a esto son comandos RUN
. Debido a la forma en que se compilan los contenedores, no se pueden emular. Si necesita esta funcionalidad, puede considerar la posibilidad de usar una Dockerfile para compilar las imágenes de contenedor.
No hay forma de realizar comandos RUN
con el SDK de .NET. Estos comandos se suelen usar para instalar algunos paquetes del sistema operativo o crear un nuevo usuario del sistema operativo o cualquier número de cosas arbitrarias. Si desea seguir usando la característica de creación de contenedores del SDK de .NET, puede crear una imagen base personalizada con estos cambios y, a continuación, usar esta imagen base. Para obtener más información, consulte ContainerBaseImage
.
ContainerArchiveOutputPath
Para crear una imagen de contenedor dentro de un archivo de tar.gz, use la propiedad ContainerArchiveOutputPath
. Esta característica es útil si el flujo de trabajo no es sencillo y requiere que, por ejemplo, ejecute una herramienta de examen sobre las imágenes antes de insertarlas. Una vez creado el archivo, puede moverlo, examinarlo o cargarlo en una cadena de herramientas local de Docker.
Para publicar en un archivo, agregue la propiedad ContainerArchiveOutputPath
al comando dotnet publish
, por ejemplo:
dotnet publish \
-p PublishProfile=DefaultContainer \
-p ContainerArchiveOutputPath=./images/sdk-container-demo.tar.gz
Puede especificar un nombre de carpeta o una ruta de acceso con un nombre de archivo específico. Si especifica el nombre de carpeta, el nombre de archivo generado para el archivo de archivo de imágenes se denomina $(ContainerRepository).tar.gz
. Estos archivos pueden contener varias etiquetas dentro de ellos, solo como se crea un solo archivo para todos los ContainerImageTags
.
Configuración de nomenclatura de imágenes de contenedor
Las imágenes de contenedor siguen una convención de nomenclatura específica. El nombre de la imagen se compone de varias partes, el registro, el puerto opcional, el repositorio y la etiqueta y la familia opcionales.
REGISTRY[:PORT]/REPOSITORY[:TAG[-FAMILY]]
Por ejemplo, considere el nombre completo de la imagen mcr.microsoft.com/dotnet/runtime:8.0-alpine
:
-
mcr.microsoft.com
es el registro (y en este caso representa el registro de contenedor de Microsoft). -
dotnet/runtime
es el repositorio (pero algunos consideran esteuser/repository
). -
8.0-alpine
es la etiqueta y la familia (la familia es un especificador opcional que ayuda a desambiguar el empaquetado del sistema operativo).
Algunas propiedades descritas en las secciones siguientes corresponden a la administración de partes del nombre de imagen generado. Tenga en cuenta la tabla siguiente que asigna la relación entre el nombre de la imagen y las propiedades de compilación:
Elemento nombre de imagen | Propiedad de MSBuild | Valores de ejemplo |
---|---|---|
REGISTRY[:PORT] |
ContainerRegistry |
mcr.microsoft.com:443 |
PORT |
ContainerPort |
:443 |
REPOSITORY |
ContainerRepository |
dotnet/runtime |
TAG |
ContainerImageTag |
8.0 |
FAMILY |
ContainerFamily |
-alpine |
En las secciones siguientes se describen las distintas propiedades que se pueden usar para controlar la imagen de contenedor generada.
ContainerBaseImage
La propiedad de imagen base del contenedor controla la imagen utilizada como base para la imagen. De forma predeterminada, los siguientes valores se deducen en función de las propiedades del proyecto:
- Si el proyecto es independiente, la imagen de
mcr.microsoft.com/dotnet/runtime-deps
se usa como imagen base. - Si el proyecto es un proyecto de ASP.NET Core, la imagen de
mcr.microsoft.com/dotnet/aspnet
se usa como imagen base. - De lo contrario, la imagen
mcr.microsoft.com/dotnet/runtime
se usa como imagen base.
La etiqueta de la imagen se deduce para que sea el componente numérico del TargetFramework
elegido. Por ejemplo, un proyecto destinado a net6.0
da como resultado la etiqueta 6.0
de la imagen base deducida y un proyecto de net7.0-linux
usa la etiqueta 7.0
, etc.
Si establece un valor aquí, debe establecer el nombre completo de la imagen que se usará como base, incluida cualquier etiqueta que prefiera:
<PropertyGroup>
<ContainerBaseImage>mcr.microsoft.com/dotnet/runtime:8.0</ContainerBaseImage>
</PropertyGroup>
Con la versión 8.0.200 del SDK de .NET, la ContainerBaseImage
inferencia se ha mejorado para optimizar el tamaño y la seguridad:
- Como destino los identificadores de
linux-musl-x64
olinux-musl-arm64
runtime, elige automáticamente las variantes de imagen dealpine
para asegurarse de que el proyecto se ejecuta:- Si el proyecto usa
PublishAot=true
, la variantenightly/runtime-deps
jammy-chiseled-aot
de la imagen base para mejorar el tamaño y la seguridad. - Si el proyecto usa
InvariantGlobalization=false
, las variantes de-extra
se usan para garantizar que la localización siga funcionando.
- Si el proyecto usa
Para obtener más información sobre los tamaños y características de las variantes de imagen, consulte informe de tamaño de imagen de contenedor de .NET 8.0.
ContainerFamily
A partir de .NET 8, puede usar la propiedad ContainerFamily
MSBuild para elegir una familia diferente de imágenes de contenedor proporcionadas por Microsoft como imagen base para la aplicación. Cuando se establece, este valor se anexa al final de la etiqueta específica del TFM seleccionada, cambiando la etiqueta proporcionada. Por ejemplo, para usar las variantes de Alpine Linux de las imágenes base de .NET, puede establecer ContainerFamily
en alpine
:
<PropertyGroup>
<ContainerFamily>alpine</ContainerFamily>
</PropertyGroup>
La configuración del proyecto anterior da como resultado una etiqueta final de 8.0-alpine
para una aplicación de destino de .NET 8.
Este campo es de forma libre y, a menudo, se puede usar para seleccionar diferentes distribuciones del sistema operativo, configuraciones de paquetes predeterminadas o cualquier otro sabor de cambios en una imagen base. Este campo se omite cuando se establece ContainerBaseImage
. Para obtener más información, consulte imágenes de contenedor de .NET.
ContainerRuntimeIdentifier
La propiedad ContainerRuntimeIdentifier
especifica el sistema operativo y la arquitectura del contenedor si el ContainerBaseImage
admite varias plataformas. Por ejemplo, la imagen de mcr.microsoft.com/dotnet/runtime
admite linux-x64
, linux-arm
, linux-arm64
y win10-x64
. De forma predeterminada, se establece en el RuntimeIdentifier
usado al publicar el contenedor. Normalmente, no es necesario establecer esta propiedad explícitamente; en su lugar, use la opción -r
con el comando dotnet publish
. Si la imagen elegida no admite el RuntimeIdentifier
especificado, un error indica los identificadores admitidos.
Siempre puede establecer la propiedad ContainerBaseImage
en un nombre de imagen completo, incluida la etiqueta , para evitar tener que usar esta propiedad en absoluto.
<PropertyGroup>
<ContainerRuntimeIdentifier>linux-arm64</ContainerRuntimeIdentifier>
</PropertyGroup>
Para obtener más información sobre los identificadores en tiempo de ejecución admitidos por .NET, consulte catálogo rid.
ContainerRegistry
La propiedad del registro de contenedor controla el registro de destino, el lugar en el que se insertará la imagen recién creada. De forma predeterminada, se inserta en el demonio de Docker local, pero también puede especificar un registro remoto. Cuando se usa un registro remoto que requiere autenticación, se autentica mediante los mecanismos de docker login
conocidos. Para obtener más información, consulte autenticación en registros de contenedor para obtener más información. Para obtener un ejemplo concreto del uso de esta propiedad, considere el siguiente ejemplo XML:
<PropertyGroup>
<ContainerRegistry>registry.mycorp.com:1234</ContainerRegistry>
</PropertyGroup>
Esta herramienta admite la publicación en cualquier registro que admita el API HTTP del Registro de Docker V2. Esto incluye los siguientes registros explícitamente (y probablemente muchos más implícitamente):
- de Azure Container Registry
- de Amazon Elastic Container Registry
- del Registro de artefactos de Google
- de Docker Hub
- paquetes de GitHub
- de Container Registry hospedado en GitLab
- Quay.io
Para obtener notas sobre cómo trabajar con estos registros, consulte las notas específicas del registro .
ContainerRepository
El repositorio de contenedor es el nombre de la propia imagen, por ejemplo, dotnet/runtime
o my-app
. De forma predeterminada, se usa el AssemblyName
del proyecto.
<PropertyGroup>
<ContainerRepository>my-app</ContainerRepository>
</PropertyGroup>
Los nombres de imagen constan de uno o varios segmentos delimitados por barras diagonales, cada uno de los cuales solo puede contener caracteres alfanuméricos en minúsculas, puntos, caracteres de subrayado y guiones, y debe comenzar con una letra o un número. Cualquier otro carácter produce un error.
ContainerImageTag(s)
La propiedad de etiqueta de imagen de contenedor controla las etiquetas que se generan para la imagen. Para especificar una sola etiqueta, use ContainerImageTag
y para varias etiquetas use ContainerImageTags
.
Importante
Cuando use ContainerImageTags
, terminará con varias imágenes, una por etiqueta única.
Las etiquetas se suelen usar para hacer referencia a diferentes versiones de una aplicación, pero también pueden hacer referencia a distintas distribuciones del sistema operativo o incluso a configuraciones diferentes.
A partir de .NET 8, cuando no se proporciona una etiqueta, el valor predeterminado es latest
.
Para invalidar el valor predeterminado, especifique una de las siguientes opciones:
<PropertyGroup>
<ContainerImageTag>1.2.3-alpha2</ContainerImageTag>
</PropertyGroup>
Para especificar varias etiquetas, use un conjunto de etiquetas delimitado por punto y coma en la propiedad ContainerImageTags
, similar a establecer varias TargetFrameworks
:
<PropertyGroup>
<ContainerImageTags>1.2.3-alpha2;latest</ContainerImageTags>
</PropertyGroup>
Las etiquetas solo pueden contener hasta 127 caracteres alfanuméricos, puntos, caracteres de subrayado y guiones. Deben comenzar con un carácter alfanumérico o un carácter de subrayado. Cualquier otro formulario da como resultado un error que se produce.
Nota
Al usar ContainerImageTags
o cualquier propiedad de MSBuild que necesite configurar ;
valores delimitados. Si llama a dotnet publish
desde la línea de comandos (como sucede con la mayoría de los entornos de CI/CD), debe comprender las limitaciones de la incapacidad del entorno para desambiguar los delimitadores y las comillas, lo que requiere un escape adecuado. Esto difiere entre PowerShell y Bash. Tenga en cuenta los siguientes comandos dotnet publish
en sus respectivos entornos:
dotnet publish --os linux --arch x64 /t:PublishContainer /p:ContainerImageTags=`"1.2.3-alpha2`;latest`"
En PowerShell, los caracteres ;
y "
deben escaparse.
dotnet publish --os linux --arch x64 /t:PublishContainer /p:ContainerImageTags=\"1.2.3-alpha2;latest\"
En Bash, solo es necesario escapar el carácter "
.
Esto da como resultado dos imágenes que se generan: my-app:1.2.3-alpha2
y my-app:latest
.
Propina
Si experimenta problemas con la propiedad ContainerImageTags
, considere la posibilidad de determinar el ámbito de una variable de entorno ContainerImageTags
en su lugar:
$Env:ContainerImageTags='1.2.3;latest'; dotnet publish --os linux --arch x64 /t:PublishContainer
ContainerLabel
La etiqueta de contenedor agrega una etiqueta de metadatos al contenedor. Las etiquetas se suelen usar para almacenar los metadatos de versión y creación para usarlos por escáneres de seguridad y otras herramientas de infraestructura. Puede especificar cualquier número de etiquetas de contenedor.
El nodo ContainerLabel
tiene dos atributos:
-
Include
: clave de la etiqueta. -
Value
: el valor de la etiqueta (puede estar vacío).
<ItemGroup>
<ContainerLabel Include="org.contoso.businessunit" Value="contoso-university" />
</ItemGroup>
Para obtener una lista de etiquetas creadas de forma predeterminada, consulte etiquetas de contenedor predeterminadas.
Configuración de la ejecución del contenedor
Para controlar la ejecución del contenedor, puede usar las siguientes propiedades de MSBuild.
ContainerWorkingDirectory
El nodo del directorio de trabajo del contenedor controla el directorio de trabajo del contenedor, el directorio en el que se ejecutan los comandos si no se ejecuta otro comando.
De forma predeterminada, el valor del directorio /app
se usa como directorio de trabajo.
<PropertyGroup>
<ContainerWorkingDirectory>/bin</ContainerWorkingDirectory>
</PropertyGroup>
ContainerPort
El puerto de contenedor agrega puertos protocolo de control de transmisión (TCP) o protocolo de datagramas de usuario (UDP) a la lista de puertos conocidos para el contenedor. Esto permite que los entornos de ejecución de contenedor como Docker asignen estos puertos a la máquina host automáticamente. A menudo se usa como documentación para el contenedor, pero también se puede usar para habilitar la asignación automática de puertos.
El nodo ContainerPort
tiene dos atributos:
-
Include
: número de puerto que se va a exponer. -
Type
: el valor predeterminado estcp
, los valores válidos setcp
oudp
.
<ItemGroup>
<ContainerPort Include="80" Type="tcp" />
</ItemGroup>
A partir de .NET 8, el ContainerPort
se deduce cuando no se proporciona explícitamente en función de varias variables de entorno de ASP.NET conocidas:
ASPNETCORE_URLS
ASPNETCORE_HTTP_PORTS
ASPNETCORE_HTTPS_PORTS
Si estas variables de entorno están presentes, sus valores se analizan y convierten en asignaciones de puertos TCP. Estas variables de entorno se leen desde la imagen base, si están presentes o desde las variables de entorno definidas en el proyecto a través de ContainerEnvironmentVariable
elementos. Para obtener más información, consulte ContainerEnvironmentVariable.
ContainerEnvironmentVariable
El nodo de variable de entorno de contenedor permite agregar variables de entorno al contenedor. Las variables de entorno son accesibles para la aplicación que se ejecuta en el contenedor inmediatamente y a menudo se usan para cambiar el comportamiento en tiempo de ejecución de la aplicación en ejecución.
El nodo ContainerEnvironmentVariable
tiene dos atributos:
-
Include
: el nombre de la variable de entorno. -
Value
: valor de la variable de entorno.
<ItemGroup>
<ContainerEnvironmentVariable Include="LOGGER_VERBOSITY" Value="Trace" />
</ItemGroup>
Para obtener más información, consulte variables de entorno de .NET.
Nota
Actualmente no es posible establecer variables de entorno desde la CLI de .NET al publicar una imagen de contenedor. Para obtener más información, consulte GitHub: compilaciones de contenedores del SDK de .NET.
Configuración de comandos de contenedor
De forma predeterminada, las herramientas de contenedor inician la aplicación mediante el archivo binario appHost generado para la aplicación (si la aplicación usa un AppHost) o el comando dotnet
más el archivo DLL de la aplicación.
Sin embargo, puedes controlar cómo se ejecuta la aplicación mediante alguna combinación de ContainerAppCommand
, ContainerAppCommandArgs
, ContainerDefaultArgs
y ContainerAppCommandInstruction
.
Estos distintos puntos de configuración existen porque las distintas imágenes base usan combinaciones diferentes de las propiedades ENTRYPOINT
y COMMAND
del contenedor, y desea poder admitir todas ellas. Los valores predeterminados deben usarse para la mayoría de las aplicaciones, pero si desea personalizar el comportamiento de inicio de la aplicación, debe:
- Identifique el binario que se va a ejecutar y establézcalo como
ContainerAppCommand
- Identifique qué argumentos se necesarios para que la aplicación se ejecute y establézcalos como
ContainerAppCommandArgs
- Identifique qué argumentos (si los hay) son opcionales y podría invalidarse por un usuario y establecerlos como
ContainerDefaultArgs
- Establezca
ContainerAppCommandInstruction
enDefaultArgs
Para obtener más información, consulte los siguientes elementos de configuración.
ContainerAppCommand
El elemento de configuración del comando de la aplicación es el punto de entrada lógico de la aplicación. Para la mayoría de las aplicaciones, este es el appHost, el archivo binario ejecutable generado para la aplicación. Si la aplicación no genera un AppHost, este comando suele ser dotnet <your project dll>
. Estos valores se aplican después de cualquier ENTRYPOINT
en el contenedor base o directamente si no se define ningún ENTRYPOINT
.
La configuración de ContainerAppCommand
tiene una sola propiedad Include
, que representa el comando, la opción o el argumento que se va a usar en el comando entrypoint:
<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
Este elemento de configuración de argumentos del comando de aplicación representa los argumentos lógicos necesarios para la aplicación que se deben aplicar a la ContainerAppCommand
. De forma predeterminada, no se genera ninguna para una aplicación. Cuando está presente, los argumentos se aplican al contenedor cuando se ejecuta.
La configuración de ContainerAppCommandArgs
tiene una sola propiedad Include
, que representa la opción o argumento que se va a aplicar al comando 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
Este elemento de configuración predeterminado de argumentos representa los argumentos reemplazables por el usuario para la aplicación. Esta es una buena manera de proporcionar valores predeterminados que la aplicación podría necesitar para ejecutarse de una manera que facilita el inicio, pero aún es fácil de personalizar.
La configuración de ContainerDefaultArgs
tiene una sola propiedad Include
, que representa la opción o argumento que se va a aplicar al comando 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 configuración de instrucciones de comando de la aplicación ayuda a controlar la forma en que se combinan los ContainerEntrypoint
, ContainerEntrypointArgs
, ContainerAppCommand
, ContainerAppCommandArgs
y ContainerDefaultArgs
para formar el comando final que se ejecuta en el contenedor. Esto depende en gran medida de si un ENTRYPOINT
está presente en la imagen base. Esta propiedad toma uno de estos tres valores: "DefaultArgs"
, "Entrypoint"
o "None"
.
-
Entrypoint
:- En este modo, el punto de entrada se define mediante
ContainerAppCommand
,ContainerAppCommandArgs
yContainerDefaultArgs
.
- En este modo, el punto de entrada se define mediante
-
None
:- En este modo, el punto de entrada se define mediante
ContainerEntrypoint
,ContainerEntrypointArgs
yContainerDefaultArgs
.
- En este modo, el punto de entrada se define mediante
-
DefaultArgs
:- Este es el modo más complejo, si ninguno de los elementos de
ContainerEntrypoint[Args]
está presente, losContainerAppCommand[Args]
yContainerDefaultArgs
se usan para crear el punto de entrada y el comando. El punto de entrada de imagen base para las imágenes base que tienen codificada de forma rígida paradotnet
o/usr/bin/dotnet
se omite para que tenga control completo. - Si
ContainerEntrypoint
yContainerAppCommand
están presentes,ContainerEntrypoint
se convierte en el punto de entrada yContainerAppCommand
se convierte en el comando .
- Este es el modo más complejo, si ninguno de los elementos de
Nota
Los elementos de configuración ContainerEntrypoint
y ContainerEntrypointArgs
están en desuso a partir de .NET 8.
Importante
Esto es para los usuarios avanzados: las aplicaciones más avanzadas no deben necesitar personalizar su punto de entrada en este grado. Para obtener más información y si desea proporcionar casos de uso para sus escenarios, consulte GitHub: el contenedor del SDK de .NET crea discusiones.
ContainerUser
La propiedad de configuración de usuario controla el usuario predeterminado en el que se ejecuta el contenedor. Esto suele usarse para ejecutar el contenedor como usuario no raíz, que es un procedimiento recomendado para la seguridad. Hay algunas restricciones para que esta configuración tenga en cuenta lo siguiente:
- Puede tomar varios formularios: nombre de usuario, identificadores de usuario de Linux, nombre de grupo, identificador de grupo de Linux,
username:groupname
y otras variantes de identificador. - No hay ninguna comprobación de que el usuario o grupo especificado existe en la imagen.
- Cambiar el usuario puede modificar el comportamiento de la aplicación, especialmente en lo que respecta a cosas como permisos del sistema de archivos.
El valor predeterminado de este campo varía según el TFM del proyecto y el sistema operativo de destino:
- Si tiene como destino .NET 8 o superior y usa las imágenes en tiempo de ejecución de Microsoft, haga lo siguiente:
- en Linux, se usa el
app
de usuario sin raíz (aunque se hace referencia a él por su identificador de usuario). - en Windows se usa el
ContainerUser
de usuario sin raíz
- en Linux, se usa el
- De lo contrario, no se usa ningún
ContainerUser
predeterminado.
<PropertyGroup>
<ContainerUser>my-existing-app-user</ContainerUser>
</PropertyGroup>
Propina
La variable de entorno APP_UID
se usa para establecer información de usuario en el contenedor. Este valor puede provenir de variables de entorno definidas en la imagen base (como las imágenes de Microsoft .NET) o puede establecerla usted mismo a través de la sintaxis de ContainerEnvironmentVariable
.
Para configurar la aplicación para que se ejecute como usuario raíz, establezca la propiedad ContainerUser
en root
. En el archivo del proyecto, agregue lo siguiente:
<PropertyGroup>
<ContainerUser>root</ContainerUser>
</PropertyGroup>
Como alternativa, puede establecer este valor al llamar a dotnet publish
desde la línea de comandos:
dotnet publish -p ContainerUser=root
Etiquetas de contenedor predeterminadas
Las etiquetas se suelen usar para proporcionar metadatos coherentes en las imágenes de contenedor. Este paquete proporciona algunas etiquetas predeterminadas para fomentar una mejor capacidad de mantenimiento de las imágenes generadas.
-
org.opencontainers.image.created
se establece en el formato ISO 8601 del valor actual de DateTime.UtcNow.
Para obtener más información, consulte Implementación de etiquetas convencionales sobre la infraestructura de etiquetas existente.