Compartir a través de


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 este user/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 TargetFrameworkelegido. 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 o linux-musl-arm64 runtime, elige automáticamente las variantes de imagen de alpine para asegurarse de que el proyecto se ejecuta:
    • Si el proyecto usa PublishAot=true, la variante nightly/runtime-depsjammy-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.

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-arm64y 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 RuntimeIdentifierespecificado, 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 es tcp, los valores válidos se tcp o udp.
<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, ContainerDefaultArgsy 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 en DefaultArgs

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, ContainerAppCommandArgsy 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, ContainerAppCommandArgsy ContainerDefaultArgs.
  • None:
    • En este modo, el punto de entrada se define mediante ContainerEntrypoint, ContainerEntrypointArgsy ContainerDefaultArgs.
  • DefaultArgs:
    • Este es el modo más complejo, si ninguno de los elementos de ContainerEntrypoint[Args] está presente, los ContainerAppCommand[Args] y ContainerDefaultArgs 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 para dotnet o /usr/bin/dotnet se omite para que tenga control completo.
    • Si ContainerEntrypoint y ContainerAppCommand están presentes, ContainerEntrypoint se convierte en el punto de entrada y ContainerAppCommand se convierte en el comando .

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:groupnamey 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
  • 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.

Consulte también