Buenas prácticas para contenerizar aplicaciones .NET
Marcelo Oliveira
31 de agosto de 2022
0 minutos de lecturaLa contenerización con Docker se ha convertido en una tendencia importante en el desarrollo de aplicaciones web que muchos desarrolladores de .NET han adoptado. Contenerizar aplicaciones .NET ofrece muchas ventajas atractivas para desarrolladores e ingenieros de DevOps, incluso cuando trabajan con versiones antiguas de .NET Framework 4.x. Sin embargo, si no sabemos cómo usar los contenedores correctamente, obtendremos pocos beneficios de ellos.
En este artículo, veremos algunas buenas prácticas para contenerizar aplicaciones .NET, incluidas las que usan la versión 4.x del framework. También hablaremos sobre el uso de imágenes pequeñas y el análisis de imágenes para reducir los riesgos de seguridad y eliminar componentes innecesarios de nuestros contenedores.
Requisitos
Antes de comenzar, necesitarás:
Descargar e instalar Visual Studio 2022.
Tener un cliente local de Docker para ejecutar contenedores localmente. Puedes usar Docker Desktop, que requiere Windows 10 o una versión posterior. Asegúrate de elegir la instalación para Windows.
Descargar e instalar la interfaz de línea de comandos de Snyk (CLI).
Crear una cuenta gratuita de Snyk.
Considera contenerizar tus aplicaciones .NET (incluso .NET Framework 4.x)
A partir de .NET Core 1.0, las aplicaciones web se volvieron multiplataforma, portátiles y de código abierto, lo que permitió a los desarrolladores migrarlas a Docker y aprovechar al máximo la contenerización.
Sin embargo, aunque las versiones más recientes de .NET que se ejecutan en Linux reciben más atención, los contenedores de Windows son compatibles con las versiones antiguas de .NET, exclusivas de Windows, de las que dependen innumerables aplicaciones empresariales. Además, no todas las organizaciones que mantienen aplicaciones web de .NET Framework están listas para migrarlas a versiones más recientes. Por eso tiene sentido contenerizar nuestras aplicaciones de .NET Framework 4.x.
Los siguientes pasos muestran cómo crear y ejecutar una aplicación de Web Forms de ASP.NET contenerizada en Visual Studio 2022.
Primero, ejecuta Docker Desktop en tu equipo de desarrollo:

En la ventana Get started de Visual Studio, selecciona Create a new project.

Escribe “Web Forms” en el cuadro de texto Search for templates y selecciona ASP.NET Web Application (.NET Framework).

Ingresa un nombre para la nueva aplicación (por ejemplo, WebFormsApp), especifica la ubicación en el disco, selecciona .NET Framework 4.8 y haz clic en Create.

Luego, selecciona el tipo Web Forms.

Asegúrate de que las opciones Web Forms y Docker support estén marcadas y haz clic en Create.

Espera a que Visual Studio cree el proyecto. Esta es la estructura del proyecto tal como aparece en Visual Studio:

Ahora, abre Docker Desktop. Verás que el contenedor WebFormsApp se está ejecutando en el puerto 61469:

Abre la pestaña Images para ver la imagen WebFormsApp, desde la que se ejecuta el contenedor WebFormsApp.

Por último, presiona Ctrl+F5 para compilar tu imagen de Docker y ejecutarla localmente. Cuando la imagen del contenedor se compile y se ejecute en un contenedor de Docker, Visual Studio abrirá la aplicación web en tu navegador predeterminado.

Ahora, vuelve a Visual Studio y haz clic en el archivo Dockerfile:

Se abrirá el Dockerfile, que configura el proyecto para ejecutarse en un contenedor.

La instrucción FROM inicia una nueva etapa de compilación y establece la imagen base para las instrucciones posteriores. En este caso, la imagen es aspnet:4.8-windowsservercore-ltsc2019, que Docker descarga del repositorio de imágenes de Microsoft.
Por supuesto, es más probable que tu proyecto de Web Forms no se haya creado inicialmente con compatibilidad con Docker. Para simular esta situación, crea un nuevo proyecto de ASP.NET Web Forms, pero esta vez sin compatibilidad con Docker:

Ahora, agreguemos un Dockerfile al nuevo proyecto. Haz clic con el botón derecho en el nombre del proyecto, elige el menú Add y luego el submenú Docker Support:

Así, Visual Studio creará automáticamente el Dockerfile del proyecto.

Ten en cuenta que Visual Studio ya seleccionó la imagen y la ruta del código fuente a partir de los cuales se generará el contenedor.

A partir de aquí, tu proyecto ya cuenta con la compatibilidad y las ventajas inherentes a la contenerización con Docker, como portabilidad, agilidad, entregas más rápidas, mayor seguridad y una administración más sencilla.
Mantén las imágenes de contenedor lo más pequeñas posible
Los contenedores de Linux y Windows ofrecen imágenes base ligeras que contienen solo las aplicaciones y los servicios necesarios para que tu aplicación funcione. Una imagen pequeña con dependencias mínimas reduce la cantidad de vulnerabilidades que pueden introducirse a través de ellas y, por lo tanto, la superficie de ataque.
Veamos algunas imágenes base que los desarrolladores de .NET podrían considerar para crear contenedores pequeños. Primero, si todavía usas ASP.NET Framework 4.x, que no es compatible con Linux, tu única opción son los contenedores de Windows. Las imágenes base ligeras recomendadas por Microsoft son Windows Server Core y Nano Server.
Windows Server Core es un sistema operativo mínimo, gestionado mediante la línea de comandos, para ejecutar funciones de Windows Server y aplicaciones que no requieren la interfaz gráfica estándar de Windows. Nano Server es un sistema operativo optimizado para nubes privadas y centros de datos. Nano Server no permite el inicio de sesión local, ocupa menos espacio y se reinicia mucho más rápido que Server Core.
Para .NET Core y .NET 5 o versiones posteriores, las imágenes del SDK solo deben usarse para la compilación, mientras que las imágenes de runtime deben usarse en implementaciones de producción como parte de una compilación de varias etapas. Algunas imágenes base ligeras adecuadas son Debian bullseye-slim-amd64 y Alpine Linux.
Podemos reducir aún más el tamaño de las imágenes base si usamos imágenes para las dependencias del runtime de .NET y compilamos nuestra aplicación .NET en modo autocontenido, de modo que solo descarguemos las dependencias que necesita nuestra aplicación, y nada más.
Ahora, practiquemos la compilación de una aplicación web .NET 6 con imágenes ligeras. Abre Visual Studio 2022, haz clic en Create New Project y selecciona el tipo ASP.NET Core Web App.

Asígnale un nombre al proyecto, por ejemplo, WebApp.

Haz clic en Next y selecciona estas opciones:
Framework .NET 6.0
Tipo de autenticación: None
Configurar para HTTPS: marcado
Habilitar Docker: marcado
Sistema operativo de Docker: Linux

Haz clic en el botón Create y observa el nuevo proyecto en Visual Studio.

Ahora, presiona F5 para ejecutar la aplicación web alojada en tu contenedor local de Docker.

Ahora, ejecuta el comando docker images para obtener una lista de las imágenes de Docker en tu sistema:
El resultado de este comando será similar al siguiente:
Ten en cuenta que la aplicación se está ejecutando en un contenedor de Linux y que el tamaño de la imagen webapp anterior es de 208 MB.
A continuación, reduzcamos el tamaño de la imagen del contenedor de nuestra aplicación web.
Detén la aplicación en Visual Studio y abre el archivo Dockerfile. Verás el siguiente bloque, que indica a Docker que descargue las imágenes dotnet/aspnet:6.0 y dotnet/sdk:6.0 del Microsoft Container Registry (mcr) y las use como imágenes base para el contenedor de la aplicación:
Luego, presiona F5 para volver a ejecutar la aplicación. Cuando la aplicación web esté funcionando, ejecuta el comando docker images para obtener una lista de las imágenes de Docker en tu sistema:
La lista de imágenes se verá así:
Ten en cuenta que la imagen webapp se volvió a compilar y ahora ocupa 100 MB (108 MB menos que la imagen original).
Analiza las imágenes para detectar vulnerabilidades
Actualizar el código con frecuencia es una buena práctica por sí misma. Entre las ventajas más evidentes están el acceso a nuevas funciones, correcciones de errores, una mejor interfaz de usuario y un mayor rendimiento. Pero las actualizaciones de seguridad son igual de importantes.
Es posible que el sistema operativo o las bibliotecas de la imagen base tengan vulnerabilidades sin corregir. Además, cualquier script, código o aplicación que se agregue a la imagen base podría contener vulnerabilidades que no queremos incluir accidentalmente en producción.
Analizar los contenedores para detectar vulnerabilidades es fundamental para evaluar posibles riesgos de seguridad y tomar las medidas adecuadas. En este caso, elijamos una imagen antigua de .NET: mcr.microsoft.com/dotnet/core/aspnet:2.2.
Abramos el proyecto en Visual Studio y agreguemos un Dockerfile al nuevo proyecto. Haz clic con el botón derecho en el nombre del proyecto, elige el menú Add y luego haz clic en el submenú Docker Support.
Ahora, abre el archivo Dockerfile y reemplaza su contenido con el siguiente código:
A continuación, veremos cómo aplicar el análisis de imágenes para descubrir qué tan vulnerable es nuestro contenedor. Primero, ejecuta el comando de la CLI docker images para mostrar una lista de tus imágenes locales actuales:
Luego, ejecuta el comando snyk auth para autenticarte en la CLI de Snyk:
Una vez autenticada la cuenta, podremos usar la CLI de Snyk. Ejecutemos el comando snyk container test <repository>:<tag> para analizar la imagen que compilamos localmente y que está disponible en nuestro daemon local de Docker:

El comando snyk container test genera una lista de los componentes instalados en la imagen, envía esa lista al servicio de Snyk y devuelve una lista de las vulnerabilidades de nuestra imagen.
En total, el análisis de la imagen encontró 193 vulnerabilidades:

Para monitorear la imagen, ejecuta el comando snyk container monitor <repository>:<tag>:

El comando snyk container monitor genera una lista de los componentes instalados en la imagen, envía esa lista al servicio de Snyk y devuelve un enlace al servicio de Snyk en http://app.snyk.io/org/{YOUR-ACCOUNT}/, donde puedes ver los resultados:

Los 3 mejores consejos para contenerizar
Hemos visto muchas ventajas atractivas de contenerizar aplicaciones .NET para desarrolladores e ingenieros de DevOps. Sin embargo, los contenedores no son una solución mágica para todos los problemas. Aún debemos implementar buenas prácticas que ayuden a entender mejor los contenedores y orienten sobre cómo aprovecharlos al máximo.
A pesar de la creencia persistente de que los contenedores son solo para aplicaciones de .NET Core, hemos visto que también pueden beneficiar a las aplicaciones de .NET Framework 4.x.
En cuanto al tamaño de la imagen del contenedor, cuanto más pequeña, mejor. Por suerte, aprendimos que algunas imágenes base son lo bastante pequeñas para contener solo lo que necesita nuestra aplicación para ejecutarse y reducir la superficie de ataque del contenedor.
Por último, vimos cómo mitigar los riesgos de seguridad mediante el análisis de imágenes de contenedor y manteniéndolas actualizadas. Los comandos Snyk container test y Snyk container monitor son herramientas invaluables que nos ayudan a analizar nuestros contenedores .NET y monitorearlos continuamente para detectar vulnerabilidades. Si se usa correctamente, la contenerización puede brindar una capa adicional de seguridad y flexibilidad a nuestras aplicaciones, sin importar su antigüedad.
Seguridad de contenedores centrada en los desarrolladores
Snyk encuentra y corrige automáticamente vulnerabilidades en imágenes de contenedores y cargas de trabajo de Kubernetes.
