Compartir vía


Introducción a la creación de contenedores del SDK de .NET

Aunque es posible contenedorizar aplicaciones .NET con un Dockerfile, hay razones convincentes para contenedorizar aplicaciones directamente con el SDK de .NET. En este artículo se proporciona información general sobre la característica de creación de contenedores del SDK de .NET, con detalles relacionados con la telemetría, las consideraciones de publicación, las propiedades de compilación y la autenticación en los registros de contenedor.

Consideraciones sobre el proyecto de publicación

Ahora que tiene una aplicación .NET, puede publicarla como contenedor. Antes de hacerlo, hay varias consideraciones importantes que debe tener en cuenta. Antes de la versión 8.0.200 del SDK de .NET, se necesitaba el paquete NuGet de 📦 Microsoft.NET.Build.Containers. Este paquete no es necesario para la versión 8.0.200 del SDK de .NET y versiones posteriores, ya que la compatibilidad con contenedores se incluye de forma predeterminada.

Para habilitar la publicación de una aplicación .NET como contenedor, se requieren las siguientes propiedades de compilación:

  • IsPublishable: Configurar en true. Esta propiedad se establece implícitamente en true para los tipos de proyecto ejecutables, como console, webappy worker.
  • EnableSdkContainerSupport: establezca en true cuando el tipo de proyecto sea una aplicación de consola.

Para habilitar explícitamente la compatibilidad con contenedores del SDK, tenga en cuenta el siguiente fragmento de código de archivo de proyecto:

<PropertyGroup>
  <IsPublishable>true</IsPublishable>
  <EnableSdkContainerSupport>true</EnableSdkContainerSupport>
</PropertyGroup>

Conmutadores de publicación y propiedades de compilación

Al igual que con todos los comandos de la CLI de .NET, puede especificar propiedades de MSBuild en la línea de comandos. Hay muchos formularios de sintaxis válidos disponibles para proporcionar propiedades, como:

  • /p:PropertyName=Value
  • -p:PropertyName=Value
  • -p PropertyName=Value
  • --property PropertyName=Value

Puede usar la sintaxis que prefiera, pero la documentación muestra ejemplos con el formulario de -p.

Sugerencia

Para ayudar a solucionar problemas, considere la posibilidad de usar los registros de MSBuid. Para generar un archivo de registro binario (binlog), agregue el modificador -bl al comando dotnet publish. Los archivos Binlog son útiles para diagnosticar problemas de compilación y se pueden abrir en el visor de registros estructurado de MSBuild . Proporcionan un seguimiento detallado del proceso de compilación, esencial para el análisis de MSBuild. Para obtener más información, consulte Solución de problemas y creación de registros para MSBuild.

Publicar perfiles y destinos

Al usar dotnet publish, especificar un perfil con -p PublishProfile=DefaultContainer puede establecer una propiedad que hace que el SDK desencadene otro destino después del proceso de publicación. Se trata de una manera indirecta de lograr el resultado deseado. Por otro lado, el uso de dotnet publish /t:PublishContainer invoca directamente el objetivo de PublishContainer, logrando el mismo resultado, pero de forma más sencilla.

En otras palabras, el siguiente comando de la CLI de .NET:

dotnet publish -p PublishProfile=DefaultContainer

Que establece la propiedad PublishProfile en DefaultContainer, es equivalente al siguiente comando:

dotnet publish /t:PublishContainer

La diferencia entre los dos métodos es que el primero usa un perfil para establecer la propiedad, mientras que el último invoca directamente el destino. La razón por la que esto es importante es que los perfiles son una característica de MSBuild y se pueden usar para establecer propiedades de forma más compleja que simplemente establecerlas directamente.

Un problema clave es que no todos los tipos de proyecto admiten perfiles o tienen el mismo conjunto de perfiles disponibles. Además, hay una disparidad en el nivel de compatibilidad con los perfiles entre distintas herramientas, como Visual Studio y la CLI de .NET. Por lo tanto, el uso de objetivos suele ser un método más claro y ampliamente admitido para lograr el mismo resultado.

Autenticación en registros de contenedor

La interacción con registros de contenedor privados requiere autenticación con esos registros.

Docker tiene un patrón establecido con esto a través del comando docker login, que es una forma de interactuar con un archivo de configuración de Docker que contiene reglas para autenticarse con registros específicos. Este archivo y los tipos de autenticación que codifica son compatibles con Microsoft.Net.Build.Containers para la autenticación del Registro. Esto debe garantizar que este paquete funcione correctamente con cualquier registro desde el que pueda docker pull y docker push. Este archivo se almacena normalmente en ~/.docker/config.json, pero se puede especificar además a través de la variable DOCKER_CONFIG, que apunta a un directorio que contiene un archivo config.json.

Tipos de autenticación

El archivo config.json contiene tres tipos de autenticación:

Nombre de usuario o contraseña explícitos

La sección auths del archivo config.json es una asignación de clave-valor entre los nombres del Registro y las cadenas de nombre de usuario:contraseña codificadas en Base64. En un escenario común de Docker, la ejecución de docker login <registry> -u <username> -p <password> crea nuevos elementos en este mapa. Estas credenciales son populares en los sistemas de integración continua (CI), donde el inicio de sesión se realiza mediante tokens al principio de una ejecución. Sin embargo, son menos populares para las máquinas de desarrollo para el usuario final debido al riesgo de seguridad de tener credenciales sin cifrar en un archivo.

Aplicaciones auxiliares de credenciales

La sección credHelpers del archivo config.json es un mapa clave/valor entre los nombres de registro y los nombres de programas específicos que se pueden utilizar para crear y recuperar credenciales para ese registro. Esto suele usarse cuando determinados registros tienen requisitos de autenticación complejos. Para que este tipo de autenticación funcione, debe tener una aplicación denominada docker-credential-{name} en el PATHde su sistema. Este tipo de credenciales tiende a ser seguro, pero puede ser difícil de configurar en máquinas de desarrollo o CI.

Cadenas de claves del sistema

La sección credsStore es una sola propiedad de cadena cuyo valor es el nombre de un programa auxiliar de credenciales de Docker que sabe cómo interactuar con el administrador de contraseñas del sistema. Para Windows, esto puede ser wincred por ejemplo. Estos son populares con los instaladores de Docker para macOS y Windows.

Autenticación mediante variables de entorno

En algunos escenarios, el mecanismo de autenticación estándar de Docker descrito anteriormente simplemente no es suficiente. Esta herramienta tiene un mecanismo adicional para proporcionar credenciales a los registros: variables de entorno. Si se usan variables de entorno, el mecanismo de proporcionar credenciales no se usará en absoluto. Se admiten las siguientes variables de entorno:

  • DOTNET_CONTAINER_REGISTRY_UNAME: debe ser el nombre de usuario del registro. Si la contraseña del registro es un token, el nombre de usuario debe ser "<token>".
  • DOTNET_CONTAINER_REGISTRY_PWORD: debe ser la contraseña o el token del registro.

Nota

A partir del SDK de .NET 8.0.400, se han actualizado las variables de entorno para las operaciones de contenedor. Las variables SDK_CONTAINER_* ahora tienen el prefijo DOTNET_CONTAINER_*.

Este mecanismo es potencialmente vulnerable a la pérdida de credenciales, por lo que solo debe usarse en escenarios en los que el otro mecanismo no esté disponible. Por ejemplo, si está utilizando la herramienta de contenedores de SDK dentro de un contenedor de Docker. Además, este mecanismo no tiene espacio de nombres: intenta usar las mismas credenciales para el registro de origen (donde se encuentra la imagen base) y el registro de destino (donde se inserta la imagen final).

Uso de registros no seguros

Se supone que la mayoría del acceso al registro es seguro, lo que significa que HTTPS se usa para interactuar con el registro. Sin embargo, no todos los registros se configuran con certificados TLS, especialmente en situaciones como un registro corporativo privado detrás de una VPN. Para admitir estos casos de uso, las herramientas de contenedor proporcionan formas de declarar que un registro específico usa una comunicación no segura.

A partir de .NET 8.0.400, el SDK comprende estos archivos y formatos de configuración y usará automáticamente esa configuración para determinar si se debe usar HTTP o HTTPS. La configuración de un registro para la comunicación no segura varía en función de la herramienta de contenedor que prefiera.

Docker

Docker almacena su configuración de registro en la configuración del demonio. Para agregar nuevos registros no seguros, se agregan nuevos hosts a la propiedad de matriz "insecure-registries".

{
  "insecure-registries": [
    "registry.mycorp.net"
  ]
}

Nota

Debe reiniciar el daemon de Docker para aplicar los cambios en este archivo.

Podman

Podman usa un archivo TOML de registries.conf para almacenar la información de conexión del registro. Este archivo normalmente reside en /etc/containers/registries.conf. Para agregar nuevos registros no seguros, se agrega una sección TOML para contener la configuración del Registro y, a continuación, la opción insecure debe establecerse en true.

[[registry]]
location = "registry.mycorp.net"
insecure = true

Nota

Debe reiniciar Podman para aplicar los cambios en el archivo registries.conf.

Variables de entorno

A partir de la versión 9.0.100, el SDK de .NET reconoce registros no seguros que se pasan a través de la variable de entorno DOTNET_CONTAINER_INSECURE_REGISTRIES. Esta variable toma una lista separada por comas de dominios para tratar como no segura de la misma manera que los ejemplos de Docker y Podman anteriores.

$Env:DOTNET_CONTAINER_INSECURE_REGISTRIES=localhost:5000,registry.mycorp.com; dotnet publish -t:PublishContainer -p:ContainerRegistry=registry.mycorp.com -p:ContainerBaseImage=localhost:5000/dotnet/runtime:9.0

Telemetría

Al publicar una aplicación de .NET como contenedor, las herramientas de contenedor del SDK de .NET recopilan y envían telemetría de uso sobre cómo se usan las herramientas. Los datos recopilados se suman a la telemetría enviada por la CLI de .NET, pero utilizan los mismos mecanismos y, lo que es más importante, se adhieren a los mismos controles de exclusión.

La telemetría recopilada está pensada para ser general en la naturaleza y no filtrar ninguna información personal, el propósito previsto es ayudar a medir:

  • Uso general de la característica de contenedorización del SDK de .NET.
  • Tasas de éxito y error, junto con información general sobre qué tipos de errores se producen con más frecuencia.
  • Uso de características específicas de la tecnología, como publicar en varios tipos de registro o cómo se invocó la publicación.

Para no participar en la telemetría, establezca la variable de entorno DOTNET_CLI_TELEMETRY_OPTOUT en true. Para obtener más información, consulte Telemetría de la CLI de .NET.

Telemetría de inferencia

La siguiente información sobre cómo ocurrió el proceso de inferencia de la imagen base está registrada:

Punto de fecha Explicación Valor de ejemplo
InferencePerformed Si los usuarios especifican manualmente imágenes base frente a usar la inferencia. true
TargetFramework El TargetFramework elegido al realizar la inferencia de imágenes base. net8.0
BaseImage Valor de la imagen base elegida, pero solo si esa imagen base es una de las imágenes generadas por Microsoft. Si un usuario especifica cualquier imagen distinta de las imágenes generadas por Microsoft en mcr.microsoft.com, este valor es NULL. mcr.microsoft.com/dotnet/aspnet
BaseImageTag Valor de la etiqueta elegida, pero solo si esa etiqueta es para una de las imágenes generadas por Microsoft. Si un usuario especifica cualquier imagen distinta de las imágenes generadas por Microsoft en mcr.microsoft.com, este valor es NULL. 8.0
ContainerFamily Valor de la propiedad ContainerFamily si un usuario usó la característica ContainerFamily para elegir un "sabor" de una de nuestras imágenes base. Esto solo se establece si el usuario ha seleccionado o inferido una de las imágenes .NET producidas por Microsoft de mcr.microsoft.com jammy-chiseled
ProjectType El tipo de proyecto que se está contenedorizando. AspNetCore o Console
PublishMode Cómo se ha empaquetado la aplicación. Aot, Trimmed, SelfContainedo FrameworkDependent
IsInvariant Si la imagen elegida requiere una globalización invariable o el usuario optó por ella manualmente. true
TargetRuntime El RID para el que se publicó esta aplicación. linux-x64

Telemetría de creación de imágenes

Se anota la siguiente información sobre cómo ocurrió el proceso de creación y publicación del contenedor:

Punto de fecha Explicación Valor de ejemplo
RemotePullType Si la imagen base procede de un registro remoto, ¿qué tipo de registro era? Azure, AWS, Google, GitHub, DockerHub, MRC u Otros
LocalPullType Si la imagen base procede de un origen local, como un demonio de contenedor o un tarball. Docker, Podman, Tarball
RemotePushType Si la imagen se insertó en un registro remoto, ¿qué tipo de registro era? Azure, AWS, Google, GitHub, DockerHub, MRC u Otros
LocalPushType Si la imagen se envió a un destino local, ¿cuál fue? Docker, Podman, Tarball

Además, si se producen varios tipos de errores durante el proceso, se recopilan datos sobre el tipo de error que ocurrió.

Punto de fecha Explicación Valor de ejemplo
Error El tipo de error que se produjo unknown_repository, credential_failure, rid_mismatch, local_load.
Direction Si el error es un credential_failure, ¿se produjo en el registro de inserción o de extracción? push
Dirección RID de destino Si el error era un rid_mismatch, ¿qué RID se solicitó? linux-x64
Los RIDs disponibles Si el error fue un rid_mismatch, ¿qué RIDs admitía la imagen base? linux-x64,linux-arm64

Consulte también