GNU/Linux >> Linux Esercitazione >  >> Panels >> Docker

Un microservizio dell'applicazione .NET Core containerizzato completo, il più piccolo possibile

OK, forse non è tecnicamente un microservizio, ma questa è una parola d'ordine calda in questi giorni, giusto? Alcune settimane fa ho scritto sul blog Miglioramenti sulle distribuzioni di ASP.NET Core su now.sh di Zeit e sulla creazione di immagini di contenitori di piccole dimensioni. Alla fine sono riuscito a dimezzare le dimensioni del mio contenitore.

Il taglio che stavo usando è sperimentale e molto aggressivo. Se l'app carica le cose in fase di esecuzione, come a volte ASP.NET Razor Pages, è possibile che vengano visualizzati strani errori in fase di esecuzione quando manca un tipo. Alcuni tipi potrebbero essere stati eliminati!

Ad esempio:

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)

Accidenti!

Sto eseguendo una distribuzione autonoma e quindi ritagliare il risultato! Richard Lander ha un ottimo esempio di dockerfile. Nota come sta facendo l'aggiunta del pacchetto con l'interfaccia a riga di comando dotnet con "dotnet add package" e il successivo ritaglio entro il Dockerfile (anziché aggiungerlo al csproj della tua copia di sviluppo locale).

Sto aggiungendo il Tree Trimming Linker nel Dockerfile, quindi il ritaglio avviene quando viene creata l'immagine del contenitore. Sto usando il comando dotnet per "dotnet aggiungere il pacchetto ILLink.Tasks. Ciò significa che non ho bisogno di fare riferimento al pacchetto linker in fase di sviluppo:è tutto in fase di compilazione del contenitore.

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

Alla fine ho riscontrato questo bug nel Linker (non è stato rilasciato) ma c'è una soluzione semplice. Devo solo impostare la proprietà CrossGenDuringPublish a false nel file di progetto.

Se guardi le Istruzioni avanzate per il Linker puoi vedere che puoi "rootare" tipi o assiemi. Root significa "non scherzare con questi o cose che pendono da loro". Quindi devo solo esercitare la mia app in fase di esecuzione e assicurarmi che tutti i tipi di cui la mia app ha bisogno siano disponibili, ma non quelli non necessari.

Ho aggiunto gli assiemi che volevo conservare (non rimuovere) durante il taglio/il collegamento al file del mio progetto:

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

La mia strategia per capire quali assembly "root" ed escludere dal taglio era letteralmente semplicemente ripetere. Costruisci, taglia, testa, aggiungi un assieme leggendo il messaggio di errore e ripeti.

Questa app ASP.NET Core di esempio verrà distribuita in modo pulito su Zeit con il minor footprint dell'immagine possibile. https://github.com/shanselman/superzeit

Successivamente proverò un vero Microservizio (al contrario di un sito Web completo, che è quello che è) e vedrò quanto piccolo posso ottenerlo. Che divertimento!

AGGIORNAMENTO: Questa tecnica funziona anche con "dotnet new webapi" ed è di circa 73 mega per "immagini docker" ed è di 34 mega quando viene inviata e schiacciata tramite la CLI "ora" di Zeit.

Sponsor: Rider 2018.2 è qui! Pubblicazione su IIS, supporto Docker nel debugger, controllo ortografico integrato, supporto per MacBook Touch Bar, supporto completo per C# 7.3, supporto avanzato Unity e altro ancora.


Docker
  1. Come installare .NET Core su Debian 10

  2. Quali sono le caratteristiche di un'applicazione che diventa un'applicazione Ubuntu principale/preinstallata/predefinita?

  3. È possibile eseguire il backup VPS completo nel VPS stesso?

  4. Un microservizio dell'applicazione .NET Core containerizzato completo, il più piccolo possibile

  5. Rilevamento che un'app .NET Core è in esecuzione in un contenitore Docker e SkippableFacts in XUnit

Creazione, esecuzione e test di .NET Core e ASP.NET Core 2.1 in Docker su un Raspberry Pi (ARM32)

Un emulatore GameBoy lato server multigiocatore scritto in .NET Core e Angular

Provare nuove immagini Docker Alpine .NET Core

.NET e Docker

Esplorazione di ASP.NET Core con Docker in entrambi i contenitori Linux e Windows

Installazione di PowerShell Core su un Raspberry Pi (con tecnologia .NET Core)