GNU/Linux >> Tutoriales Linux >  >> Panels >> Docker

Un microservicio completo de aplicaciones .NET Core en contenedores que es lo más pequeño posible

De acuerdo, tal vez técnicamente no sea un microservicio, pero esa es una palabra de moda en estos días, ¿verdad? Hace unas semanas escribí en un blog sobre las mejoras en las implementaciones de ASP.NET Core en now.sh de Zeit y la creación de imágenes de contenedores pequeños. Al final, pude reducir el tamaño de mi contenedor a la mitad.

El recorte que estaba usando es experimental y muy agresivo. Si su aplicación carga cosas en tiempo de ejecución, como a veces lo hace ASP.NET Razor Pages, puede terminar recibiendo errores extraños en tiempo de ejecución cuando falta un tipo. ¡Es posible que se hayan recortado algunos tipos!

Por ejemplo:

fail: Microsoft.AspNetCore.Server.Kestrel[13]
Connection id "0HLGQ1DIEF1KV", Request id "0HLGQ1DIEF1KV:00000001": An unhandled exception was thrown by the application.
System.TypeLoadException: Could not load type 'Microsoft.AspNetCore.Diagnostics.IExceptionHandlerPathFeature' from assembly 'Microsoft.Extensions.Primitives, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'.
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.Invoke(HttpContext context)
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Hosting.Internal.HostingApplication.ProcessRequestAsync(Context context)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)

¡Ay!

¡Estoy haciendo una implementación autónoma y luego recorte el resultado! Richard Lander tiene un gran ejemplo de dockerfile. Tenga en cuenta cómo está haciendo la adición de paquetes con la CLI de dotnet con "paquete de adición de dotnet" y el recorte posterior dentro de el Dockerfile (en lugar de agregarlo al csproj de su copia de desarrollo local).

Estoy agregando Tree Trimming Linker en el Dockerfile, por lo que el recorte ocurre cuando se crea la imagen del contenedor. Estoy usando el comando dotnet para "dotnet add package ILLink.Tasks". Esto significa que no necesito hacer referencia al paquete del enlazador en el momento del desarrollo; todo es en el momento de la creación del contenedor.

FROM microsoft/dotnet:2.1-sdk-alpine AS build
WORKDIR /app

# copy csproj and restore as distinct layers
COPY *.sln .
COPY nuget.config .
COPY superzeit/*.csproj ./superzeit/
RUN dotnet restore

# copy everything else and build app
COPY . .
WORKDIR /app/superzeit
RUN dotnet build

FROM build AS publish
WORKDIR /app/superzeit
# add IL Linker package
RUN dotnet add package ILLink.Tasks -v 0.1.5-preview-1841731 -s https://dotnet.myget.org/F/dotnet-core/api/v3/index.json
RUN dotnet publish -c Release -o out -r linux-musl-x64 /p:ShowLinkerSizeComparison=true

FROM microsoft/dotnet:2.1-runtime-deps-alpine AS runtime
ENV DOTNET_USE_POLLING_FILE_WATCHER=true
WORKDIR /app
COPY --from=publish /app/superzeit/out ./
ENTRYPOINT ["./superzeit"]

Terminé con este error en el Linker (no está publicado), pero hay una solución fácil. Solo necesito establecer la propiedad CrossGenDuringPublish a false en el archivo del proyecto.

Si observa las Instrucciones avanzadas para Linker, puede ver que puede "rootear" tipos o ensamblajes. Root significa "no te metas con estos o cosas que cuelgan de ellos". Así que solo necesito ejercitar mi aplicación en tiempo de ejecución y asegurarme de que todos los tipos que necesita mi aplicación estén disponibles, pero no los innecesarios.

Agregué los ensamblajes que quería mantener (no eliminar) mientras recortaba/enlazaba a mi archivo de proyecto:

<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<CrossGenDuringPublish>false</CrossGenDuringPublish>
</PropertyGroup>

<ItemGroup>
<LinkerRootAssemblies Include="Microsoft.AspNetCore.Mvc.Razor.Extensions;Microsoft.Extensions.FileProviders.Composite;Microsoft.Extensions.Primitives;Microsoft.AspNetCore.Diagnostics.Abstractions" />
</ItemGroup>

<ItemGroup>
<!-- this can be here, or can be done all at runtime in the Dockerfile -->
<!-- <PackageReference Include="ILLink.Tasks" Version="0.1.5-preview-1841731" /> -->
<PackageReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>

</Project>

Mi estrategia para averiguar qué ensamblajes "rootear" y excluir del recorte fue, literalmente, iterar. Cree, recorte, pruebe, agregue un ensamblaje leyendo el mensaje de error y repita.

Esta aplicación ASP.NET Core de muestra se implementará limpiamente en Zeit con la huella de imagen más pequeña posible. https://github.com/shanselman/superzeit

A continuación, probaré un microservicio real (a diferencia de un sitio web completo, que es lo que es) y veré qué tan pequeño puedo obtener eso. ¡Qué divertido!

ACTUALIZACIÓN: Esta técnica también funciona con "dotnet new webapi" y tiene aproximadamente 73 megas por "imágenes acoplables" y son 34 megas cuando se envían y aplastan a través de la CLI "ahora" de Zeit.

Patrocinador: ¡El piloto 2018.2 ya está aquí! Publicación en IIS, compatibilidad con Docker en el depurador, revisión ortográfica integrada, compatibilidad con MacBook Touch Bar, compatibilidad total con C# 7.3, compatibilidad avanzada con Unity y más.


Docker
  1. Cómo instalar .NET Core en Debian 10

  2. ¿Cuáles son las características de una aplicación que se convierte en una aplicación principal/preinstalada/predeterminada de Ubuntu?

  3. ¿Es posible realizar una copia de seguridad completa del VPS en el propio VPS?

  4. Optimización de los tamaños de imagen de ASP.NET Core Docker

  5. ¿Visual Basic es compatible con .NET Core en Linux?

Creación, ejecución y prueba de .NET Core y ASP.NET Core 2.1 en Docker en una Raspberry Pi (ARM32)

Un emulador de GameBoy del lado del servidor para varios jugadores escrito en .NET Core y Angular

Probar nuevas imágenes de .NET Core Alpine Docker

.NET y Docker

Exploración de ASP.NET Core con Docker en contenedores de Linux y Windows

Instalación de PowerShell Core en una Raspberry Pi (con tecnología de .NET Core)