Inclusión de una aplicación .NET en un contenedor mediante dotnet publish

Los contenedores tienen muchas características y ventajas, como ser una infraestructura inmutable, proporcionar una arquitectura portátil y permitir la escalabilidad. La imagen puede usarse para crear contenedores para un entorno de desarrollo local, una nube privada o una nube pública. En este tutorial aprenderá a incluir una aplicación .NET en un contenedor usando el comando dotnet publish.

Requisitos previos

Instale estos requisitos previos:

Además de estos requisitos previos, se recomienda estar familiarizado con los servicios de trabajo de .NET.

Creación de aplicaciones .NET

Necesita incluir una aplicación .NET en un contenedor. Empezaremos creando una aplicación a partir de una plantilla. Abra el terminal, cree una carpeta de trabajo (sample-directory) si aún no lo ha hecho y cambie de directorio para situarse en esa carpeta. En la carpeta de trabajo, ejecute el siguiente comando para crear un proyecto en un subdirectorio llamado Worker:

dotnet new worker -o Worker -n DotNet.ContainerImage

El árbol de carpetas tiene un aspecto similar al siguiente:

📁 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

El comando dotnet new crea una carpeta llamada Worker y genera un servicio de trabajo que, cuando se ejecuta, registra un mensaje cada segundo. En la sesión de terminal, cambie de directorio y vaya a la carpeta Worker. Use el comando dotnet run para iniciar la aplicación.

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...

La plantilla de trabajo se repite en bucle indefinidamente. Use el comando Cancelar Ctrl+C para detenerla.

Adición del paquete NuGet

Actualmente, es necesario el paquete NuGet Microsoft.NET.Build.Containers para publicar proyectos que no son web como un contenedor. Para agregar el paquete NuGet Microsoft.NET.Build.Containers a la plantilla de trabajo, ejecute el siguiente comando dotnet add package:

dotnet add package Microsoft.NET.Build.Containers

Sugerencia

Si va a compilar una aplicación web mediante el SDK de .NET 7.0.300 o una versión posterior, el paquete ya no es necesario. El SDK ya contiene la misma funcionalidad.

Establecimiento del nombre de la imagen de contenedor

Al publicar una aplicación como un contenedor, hay varias opciones de configuración disponibles.

El nombre de la imagen de contenedor es de forma predeterminada el nombre AssemblyName del proyecto. Si ese nombre no es válido como nombre de imagen de contenedor, se puede invalidar especificando un nombre ContainerRepository, como se muestra en el archivo del proyecto siguiente:

<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>

Para obtener más información, consulte ContainerRepository.

El nombre de la imagen de contenedor es de forma predeterminada el nombre AssemblyName del proyecto. Si ese nombre no es válido como un nombre de imagen de contenedor, puede invalidarlo especificando (ContainerImageName obsoleto) o el ContainerRepository preferido, como se muestra en el siguiente archivo de proyecto:

<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>

Para obtener más información, consulte ContainerImageName.

Publicación de una aplicación .NET

Para publicar la aplicación .NET como un contenedor, use el siguiente comando dotnet publish:

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

El comando de la CLI de .NET anterior publica la aplicación como un contenedor con las siguientes características:

  • Tiene Linux como sistema operativo de destino (--os linux).
  • Especifica una arquitectura x64 (--arch x64).
  • Usa la configuración de versión (-c Release).

Importante

Para crear el contenedor localmente, el demonio de Docker debe estar en ejecución. Si no lo está cuando intente publicar la aplicación como un contenedor, experimentará un error similar al siguiente:

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

Sugerencia

En función del tipo de aplicación que se va a incluir en un contenedor, los modificadores de línea de comandos (opciones) pueden variar. Por ejemplo, el argumento /t:PublishContainer es necesario únicamente con aplicaciones .NET que no son web, como las plantillas console y worker. En las plantillas web, reemplace el argumento /t:PublishContainer por -p:PublishProfile=DefaultContainer. Para obtener más información, vea Creación de contenedores del SDK de .NET, problema n.º 141.

El comando genera una salida similar a la del ejemplo:

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

Este comando compila la aplicación de trabajo en la carpeta publish e inserta el contenedor en el registro de Docker local.

Configuración de la imagen de contenedor

Muchos aspectos del contenedor generado se pueden controlar mediante propiedades de MSBuild. En general, si puede usar un comando en un Dockerfile para establecer alguna configuración, podrá hacer lo mismo a través de MSBuild.

Nota:

Las únicas excepciones a esto son los comandos RUN. Debido a la forma en que los contenedores se compilan, no se pueden emular. Si necesita esta funcionalidad, deberá usar un Dockerfile para compilar las imágenes de contenedor.

ContainerArchiveOutputPath

A partir de .NET 8, puede crear un contenedor directamente como archivo tar.gz. 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 del archivo de imágenes será $(ContainerRepository).tar.gz. Estos archivos pueden contener varias etiquetas dentro de ellos, solo cuando 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 de imagen completo 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 como user/repository).
  • 8.0-alpine es la etiqueta y la familia (la familia es un especificador opcional que ayuda a eliminar la ambigüedad del 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
Elemento nombre de imagen Propiedad de MSBuild Valores de ejemplo
REGISTRY[:PORT] ContainerRegistry mcr.microsoft.com:443
PORT ContainerPort :443
REPOSITORY ContainerImageName dotnet/runtime
TAG ContainerImageTag 8.0

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 que se usa como base de la imagen. De forma predeterminada, se deducen los siguientes valores en función de las propiedades del proyecto:

  • Si el proyecto es autocontenido, se usa la imagen mcr.microsoft.com/dotnet/runtime-deps como imagen base.
  • Si el proyecto es un proyecto de ASP.NET Core, se usa la imagen mcr.microsoft.com/dotnet/aspnet como imagen base.
  • De lo contrario, se usa la imagen mcr.microsoft.com/dotnet/runtime.

La etiqueta de la imagen se deduce para que sea el componente numérico del TargetFramework elegido. Por ejemplo, un proyecto que tiene como destino net6.0 da como resultado la etiqueta 6.0 de la imagen base deducida, y un proyecto con net7.0-linux como destino 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 de su preferencia:

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

ContainerFamily

A partir de .NET 8, puede usar la propiedad de MSBuild ContainerFamily 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 de 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 con .NET 8 como destino.

Este campo se introduce de forma libre y, a menudo, se puede usar para seleccionar diferentes distribuciones del sistema operativo, configuraciones de paquetes predeterminadas o cualquier otro tipo de cambios en una imagen base. Se omite este campo al establecerse ContainerBaseImage. Para obtener más información, vea Imágenes de contenedor .NET.

ContainerRuntimeIdentifier

La propiedad de identificador del entorno de ejecución del contenedor controla el sistema operativo y la arquitectura que usa el contenedor si ContainerBaseImage admite más de una plataforma. Por ejemplo, la imagen mcr.microsoft.com/dotnet/runtime actualmente admite las imágenes linux-x64, linux-arm, linux-arm64 y win10-x64 con la misma etiqueta, por lo que las herramientas necesitan una manera de indicarles cuál de estas versiones desea usar. De forma predeterminada, se establece en el valor de RuntimeIdentifier que eligió al publicar el contenedor. Rara vez es necesario establecer esta propiedad de forma explícita. En su lugar, utilice la opción -r para el comando dotnet publish. Si la imagen que elige no es compatible con el RuntimeIdentifier que había elegido, esto dará como resultado un error que describe los runtimeIdentifiers que la imagen admite.

Siempre puede establecer la propiedad ContainerBaseImage en un nombre de imagen completo, incluida la etiqueta, para no tener que usar esta propiedad.

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

Para obtener más información sobre los identificadores del entorno de ejecución admitidos por .NET, consulte Catálogo RID.

ContainerRegistry

La propiedad del registro de contenedor controla el registro del destino, es decir, dónde se va a 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 utilizan los conocidos mecanismos de docker login para ello. Para obtener información más detallada, consulte Autenticación en registros de contenedor. Para obtener un ejemplo concreto del uso de esta propiedad, vea el siguiente ejemplo XML:

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

Esta herramienta permite publicar en cualquier registro que admita Docker Registry HTTP API V2. Esto incluye los siguientes registros de forma explícita (y probablemente muchos más de forma implícita):

Para obtener instrucciones sobre cómo trabajar con estos registros, consulte las notas específicas de cada registro.

ContainerRepository

El repositorio de contenedores es el nombre de la imagen en sí, por ejemplo, dotnet/runtime o my-app. De forma predeterminada, se usa el nombre AssemblyName del proyecto.

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

ContainerImageName

El nombre de la imagen de contenedor controla el nombre de la imagen en sí, por ejemplo, dotnet/runtime o my-app. De forma predeterminada, se usa el nombre AssemblyName del proyecto.

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

Nota:

A partir de .NET 8, ContainerImageName queda obsoleto en favor de ContainerRepository.

Los nombres de imagen constan de uno o varios segmentos delimitados por barras diagonales que solo pueden contener caracteres alfanuméricos en minúscula, puntos, caracteres de subrayado y guiones, y deben comenzar con una letra o un número. El uso de cualquier otro carácter producirá un error.

ContainerImageTag(s)

La propiedad de etiqueta de imagen de contenedor controla las etiquetas que se generan relativas a 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 distintas versiones de una aplicación, pero también pueden hacer referencia a distribuciones de sistema operativo diferentes o, incluso, a configuraciones diferentes.

A partir de .NET 8, cuando no se proporciona una etiqueta, el valor predeterminado es latest.

De forma predeterminada, se usa el valor de Version del proyecto como valor de etiqueta.

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 delimitadas por punto y coma en la propiedad ContainerImageTags (similar a establecer varios TargetFrameworks):

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

Las etiquetas solo pueden contener un máximo de 127 caracteres alfanuméricos, puntos, caracteres de subrayado y guiones. Deben empezar por un carácter alfanumérico o por un carácter de subrayado. El uso de cualquier otro formato producirá un error.

Nota:

Al usar ContainerImageTags, las etiquetas se delimitan mediante un carácter ;. Si llama a dotnet publish desde la línea de comandos (como sucede con la mayoría de los entornos de CI/CD), deberá ajustar de forma externa los valores en una ' simple y de forma interna con comillas dobles ", por ejemplo (='"tag-1;tag-2"'). Tenga en cuenta el siguiente comando dotnet publish:

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

Esto da como resultado que se generen dos imágenes: my-app:1.2.3-alpha2 y my-app:latest.

Sugerencia

Si experimenta problemas con la propiedad ContainerImageTags, considere la posibilidad de determinar el ámbito de una variable de entorno ContainerImageTags en su lugar:

ContainerImageTags='1.2.3;latest' dotnet publish

ContainerLabel

La etiqueta de contenedor agrega una etiqueta de metadatos al contenedor. Las etiquetas no tienen ningún impacto en el contenedor en tiempo de ejecución, pero suelen usarse para almacenar los metadatos de versión y creación para que puedan usarse en los exámenes de seguridad y en 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: 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, vea Etiquetas de contenedor predeterminadas.

Configuración de la ejecución de contenedor

Para controlar la ejecución de 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 ningún otro comando.

De forma predeterminada, se usa el valor del directorio /app como directorio de trabajo.

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

ContainerPort

El puerto de contenedor agrega puertos TCP o UDP a la lista de puertos conocidos del contenedor. Esto permite que los entornos de ejecución del contenedor, como Docker, asignen estos puertos automáticamente al equipo host. Esto se suele usar como documentación del 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 son tcp o udp.
<ItemGroup>
    <ContainerPort Include="80" Type="tcp" />
</ItemGroup>

A partir de .NET 8, se infiere ContainerPort 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 analizarán y convertirán en asignaciones de puertos TCP. Estas variables de entorno se leen de la imagen base, si está presente, o de las variables de entorno definidas en el proyecto a través de elementos ContainerEnvironmentVariable. 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 de inmediato para la aplicación que se ejecuta en el contenedor, 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: 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, vea Variables de entorno.

Configuración de comandos de contenedor

De forma predeterminada, las herramientas de contenedor inician la aplicación mediante el archivo binario AppHost generado de la aplicación (si la aplicación usa una instancia de AppHost), o bien el comando dotnet más el archivo DLL de la aplicación.

Sin embargo, puede controlar cómo se ejecuta la aplicación mediante una 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 admitirlos todos. Los valores predeterminados deberían poder usarse para la mayoría de las aplicaciones, pero si quiere personalizar el comportamiento de inicio de la aplicación, debe:

  • Identificar el archivo binario que se va a ejecutar y establecerlo como ContainerAppCommand
  • Identificar qué argumentos son necesarios para que se ejecute la aplicación y establecerlos como ContainerAppCommandArgs
  • Identificar qué argumentos (si los hay) son opcionales y podrían invalidarse por parte de 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, es AppHost, el archivo binario ejecutable generado de la aplicación. Si la aplicación no genera una instancia de AppHost, este comando normalmente será dotnet <your project dll>. Estos valores se aplican después de cualquier elemento ENTRYPOINT en el contenedor base o directamente si no se define ningún elemento ENTRYPOINT.

La configuración 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 la aplicación representa los argumentos lógicamente necesarios para la aplicación que se deben aplicar a ContainerAppCommand. De manera predeterminada, ninguno se genera para una aplicación. Cuando están presentes, los argumentos se aplican al contenedor cuando se ejecuta.

La configuración 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 de argumentos predeterminado representa los argumentos que puede invalidar 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 facilite su inicio y, al mismo tiempo, su personalización.

La configuración 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 del comando de la aplicación ayuda a controlar el modo en que se combinan 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 elemento ENTRYPOINT está presente en la imagen base. Esta propiedad adopta uno de estos tres valores: "DefaultArgs", "Entrypoint" o "None".

  • Entrypoint:
    • En este modo, ContainerAppCommand, ContainerAppCommandArgs y ContainerDefaultArgs definen el elemento entrypoint.
  • None:
    • En este modo, ContainerEntrypoint, ContainerEntrypointArgs y ContainerDefaultArgs definen el elemento entrypoint.
  • DefaultArgs:
    • Este es el modo más complejo (si ninguno de los elementos ContainerEntrypoint[Args] está presente, ContainerAppCommand[Args] y ContainerDefaultArgs se usan para crear el elemento entrypoint y el comando. El elemento entrypoint de la imagen base para las imágenes base que lo tienen codificado de forma rígida en dotnet o /usr/bin/dotnet se omite para que tenga un control total.
    • Si tanto ContainerEntrypoint como ContainerAppCommand están presentes, ContainerEntrypoint se convierte en el elemento entrypoint y ContainerAppCommand se convierte en el comando.

Nota:

Los elementos de configuración ContainerEntrypoint y ContainerEntrypointArgs han quedado en desuso desde .NET 8.

Importante

Esto es para los usuarios avanzados: la mayoría de las aplicaciones no deberían tener que personalizar su elemento entrypoint hasta este grado. Para obtener más información y si desea proporcionar casos de uso para sus escenarios, consulte las discusiones sobre compilaciones de contenedor del SDK de .NET en GitHub.

ContainerUser

La propiedad de configuración de usuario controla el usuario predeterminado con el que se ejecuta el contenedor. A menudo se usa para ejecutar el contenedor como usuario sin raíz, que es un procedimiento recomendado de seguridad. Hay algunas restricciones para que esta configuración que deben tenerse en cuenta:

  • Puede tomar diversas formas: nombre de usuario, identificadores de usuario de Linux, nombre de grupo, identificador de grupo de Linux, username:groupname y otras variantes de identificador.
  • No está confirmado que el usuario o grupo especificado exista en la imagen.
  • Cambiar el usuario puede modificar el comportamiento de la aplicación, especialmente en lo que respecta a cosas como los 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 usa como destino .NET 8 o versiones posteriores y las imágenes en tiempo de ejecución de Microsoft:
    • en Linux, se usa el usuario sin raíz app (aunque su identificador de usuario le hace referencia)
    • en Windows, se usa el usuario sin raíz ContainerUser
  • De lo contrario, no se usa ningún valor predeterminado ContainerUser
<PropertyGroup>
  <ContainerUser>my-existing-app-user</ContainerUser>
</PropertyGroup>

Sugerencia

La variable de entorno APP_UID se usa para establecer la 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 establecerlo usted mismo a través de la sintaxis ContainerEnvironmentVariable.

Sin embargo, puede controlar cómo se ejecuta la aplicación mediante ContainerEntrypoint y ContainerEntrypointArgs.

ContainerEntrypoint

El punto de entrada del contenedor se puede usar para personalizar el objeto ENTRYPOINT del contenedor, que es el ejecutable al que se llama cuando se inicia el contenedor. De forma predeterminada, en las compilaciones que crean un host de aplicación, se establece como ContainerEntrypoint. En las compilaciones que no crean un archivo ejecutable, dotnet path/to/app.dll se usa como ContainerEntrypoint.

El nodo ContainerEntrypoint tiene un único atributo:

  • Include: comando, opción o argumento que se va a usar en el comando ContainerEntrypoint.

Veamos el siguiente ejemplo de grupo de elementos de proyecto de .NET:

<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

El nodo de argumentos de punto de entrada de contenedor controla los argumentos predeterminados proporcionados a ContainerEntrypoint. Esto debe usarse cuando ContainerEntrypoint sea un programa que el usuario podría querer usar por sí mismo. De forma predeterminada, no se crean ContainerEntrypointArgs en su nombre.

El nodo ContainerEntrypointArg tiene un único atributo:

  • Include: opción o argumento que se va a aplicar al comando ContainerEntrypoint.

Veamos el siguiente ejemplo de grupo de elementos de proyecto de .NET:

<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>

Etiquetas de contenedor predeterminadas

Las etiquetas se suelen usar para proporcionar unos metadatos coherentes en imágenes de contenedor. Este paquete proporciona algunas etiquetas predeterminadas para propiciar una mejor capacidad de mantenimiento de las imágenes generadas.

  • org.opencontainers.image.created se establece en el formato ISO 8601 del DateTime UTC actual.

Para obtener más información, vea Implementación de etiquetas convencionales sobre la infraestructura de etiquetas existente.

Limpieza de recursos

En este artículo, ha publicado un trabajo de .NET como una imagen de contenedor. Si lo desea, elimine este recurso. Use el comando docker images para ver una lista de las imágenes instaladas.

docker images

Considere la siguiente salida de ejemplo:

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

Sugerencia

Los archivos de imagen pueden ser grandes. Por lo general, quitaría los contenedores temporales que creó al probar y desarrollar la aplicación. Habitualmente, estas imágenes base se conservan con el runtime instalado si se planea crear otras imágenes basadas en ese runtime.

Para eliminar la imagen, copie el identificador de la imagen y ejecute el comando docker image rm:

docker image rm 25aeb97a2e21

Pasos siguientes