ASP .NET 7

Hola! hace ya tiempo que no hago ningun post. Hoy os voy a explicar como conseguir compilar una aplicación ASP NET 7 en Native AOT con docker.

¿Que es Native AOT?

Compilar en nativo o «Native AOT» significa que tu aplicación se compila de manera especifica para una maquina (arquitectura) especifica generando un archivo ejecutable y completamente independiente sin necesidad de tener instalado dotnet.

¿Que ventajas tiene?

  • Un unico archivo
  • Se reduce el tiempo de inicio: Al estar ya compilado el tiempo de carga iniciar se reduce
    • La aplicación está lista para atender las solicitudes más rápidamente.
    • La implementación mejora cuando los orquestadores de contenedores necesitan administrar la transición de una versión de la aplicación a otra.
  • Se reduce la demanda de memoria: pueden tener demandas de memoria reducidas en función del trabajo que realice la aplicación. El menor consumo de memoria puede dar lugar a una mayor rendimiento por consume de memoria y a una mejor escalabilidad.

Aqui es pongo una comparación del rendimiento.

Como se puede apreciar tanto su consumo de memoria con tiempo de iniciación se reduce considerablemente.

Sobre el tamaño de la aplicación es relativo. Si cuando haces la compilación AOT le indicas que haga trim si que se puede reducir el tamaño pero en algunos casos puede ser que no puedas hacer trim.

Para que nos entendamos, para poder hacer compilación nativa AOT se tienen que incluir todas las librerias de .net. Al no tirar del sdk de dotnet tiene que tener todo lo que nos aporta de manera externa dotnet. Al necesitarlo «todo» la applicación puede volverse un poco gorda, pero para esto se hace trim o trimming, como quieras llamarlo, esto lo que hace es borrar todo aquello que no usa tu aplicación. Del ecosistema de dotnet en realidad solo vas a usar una parte por lo tanto no lo necesitas todo, eso es hacer trim, esto para los desarrolladores de Xamarin os puede sonar.

Vamos al lio

Lo primero que debemos hacer es indicarle al proyecto que queremos que se publique con compilación Native AOT y que haga TRIM. Se le puede especificar en el propio comando de donet publish o indicarlo en el proyecto. Yo os lo voy a poner un ejemplo de como indicarlo en el mismo proyecto (.csproj), creo que así sera más fácil de ver.

  <PropertyGroup>
		<TargetFramework>net7.0</TargetFramework>
		<Nullable>enable</Nullable>
		<ImplicitUsings>enable</ImplicitUsings>
		
		<PublishSingleFile>true</PublishSingleFile>
		<PublishReadyToRun>true</PublishReadyToRun>
		<RuntimeIdentifier>linux-musl-x64</RuntimeIdentifier> 
		<NativeCodeGen>Optimize</NativeCodeGen>
		<UseAppHost>true</UseAppHost>
                <PublishAot>true</PublishAot>
		<SuppressTrimAnalysisWarnings>true</SuppressTrimAnalysisWarnings>
                <PublishTrimmed>true</PublishTrimmed>
	</PropertyGroup>
  • RuntimeIdentifier: Aqui le indicamos el tipo de CPU para el que queremos que se compile
  • UseAppHost: Le indicamos que es un self-host.
  • PublishAot: Compilacion en Native AOT.
  • SuppressTrimAnalysisWarnings: Eliminar los mensajes de tipo warning por el trim. Son mensajes de advertencia que bueno, si no quieres que te contamine el log los puedes quitar con esta etiqueta.
  • PublishTrimmed: Que nos haga trim.
  • NativeCodeGen: Como queremos que nos optimice el codigo, por tamaño o rendimiento.

De todos esos parámetros los importantes son el PublishAot y el PublishTrimmed

Como hacerlo con docker

# Seleccionar la imagen de .NET SDK 7 con Alpine como base
FROM mcr.microsoft.com/dotnet/sdk:7.0-alpine AS build


# Establecer el directorio de trabajo en /app

WORKDIR /app

# Copiar el resto del código y compilar la aplicación
COPY . .

RUN dotnet publish ./NombreDelProyecto.csproj -c Release -r linux-musl-x64 --self-contained true /p:PublishSingleFile=true /p:UseAppHost=true -o /out


# Crear una imagen Docker mínima basada en Alpine
FROM mcr.microsoft.com/dotnet/runtime-deps:7.0-alpine


# Establecer el directorio de trabajo en /app
WORKDIR /app

# Copiar la aplicación publicada en el contenedor
COPY --from=build /out .
ENV ASPNETCORE_URLS=http://+:8080
EXPOSE 8080
# Comando de entrada para ejecutar la aplicación
ENTRYPOINT ["./<NombreDelProyecto>"]

Solución de posibles problemas

Si al hacer el dotnet publish os peta, lo más probable es que le falten a la imagen algunas librerías que necesita para poder compilarlo. Lo mejor es buscar una version más actualizada de las imagines docker de base.

Yo os recomiendo que esto no lo hagáis por defecto, sólo si necesitáis un plus de rendimiento.