GNU/Linux >> LINUX-Kenntnisse >  >> Panels >> Docker

Ein vollständiger containerisierter .NET Core-Anwendungsmikrodienst, der so klein wie möglich ist

OK, technisch vielleicht kein Microservice, aber das ist heutzutage ein heißes Schlagwort, oder? Vor ein paar Wochen habe ich über Verbesserungen bei ASP.NET Core-Bereitstellungen auf now.sh von Zeit gebloggt und kleine Container-Images erstellt. Am Ende konnte ich meine Behältergröße halbieren.

Das Trimmen, das ich verwendet habe, ist experimentell und sehr aggressiv. Wenn Ihre App Dinge zur Laufzeit lädt – wie es ASP.NET Razor Pages manchmal tut – erhalten Sie möglicherweise seltsame Fehler zur Laufzeit, wenn ein Typ fehlt. Einige Typen wurden möglicherweise entfernt!

Zum Beispiel:

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)

Huch!

Ich mache eine eigenständige Bereitstellung und trimme dann das Ergebnis! Richard Lander hat ein großartiges Dockerfile-Beispiel. Beachten Sie, wie er das Hinzufügen des Pakets mit der dotnet-Befehlszeilenschnittstelle mit „dotnet add package“ und anschließendem Trimmen innerhalb von durchführt das Dockerfile (im Gegensatz zu dem Hinzufügen zum csproj Ihrer lokalen Entwicklungskopie).

Ich füge den Tree Trimming Linker in der Docker-Datei hinzu, sodass das Trimmen erfolgt, wenn das Container-Image erstellt wird. Ich verwende den dotnet-Befehl, um „dotnet das Paket ILLink.Tasks hinzuzufügen. Das bedeutet, dass ich zur Entwicklungszeit nicht auf das Linker-Paket verweisen muss – es ist alles zur Container-Build-Zeit.“

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

Am Ende bin ich auf diesen Fehler im Linker gestoßen (er ist nicht veröffentlicht), aber es gibt eine einfache Problemumgehung. Ich muss nur die Eigenschaft CrossGenDuringPublish setzen bis false in der Projektdatei.

Wenn Sie sich die erweiterten Anweisungen für den Linker ansehen, können Sie sehen, dass Sie Typen oder Assemblys "rooten" können. Root bedeutet "nicht mit diesen oder Dingen, die daran hängen, herumspielen". Also muss ich meine App nur zur Laufzeit testen und sicherstellen, dass alle Typen, die meine App benötigt, verfügbar sind, aber keine unnötigen.

Ich habe die Baugruppen hinzugefügt, die ich beim Trimmen/Verknüpfen mit meiner Projektdatei behalten (nicht entfernen) wollte:

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

Meine Strategie, um herauszufinden, welche Assemblys "rooten" und vom Trimmen ausgeschlossen werden sollten, bestand buchstäblich darin, nur zu iterieren. Erstellen, trimmen, testen, eine Baugruppe hinzufügen, indem Sie die Fehlermeldung lesen, und wiederholen.

Diese ASP.NET Core-Beispiel-App wird sauber auf Zeit mit dem kleinstmöglichen Image-Footprint bereitgestellt. https://github.com/shanselman/superzeit

Als nächstes werde ich einen tatsächlichen Microservice ausprobieren (im Gegensatz zu einer vollständigen Website, was das ist) und sehen, wie klein ich das bekommen kann. So viel Spaß!

AKTUALISIERUNG: Diese Technik funktioniert auch mit „dotnet new webapi“ und beträgt etwa 73 MB pro „Docker-Images“ und 34 MB, wenn sie über die „now“-CLI von Zeit gesendet und gequetscht werden.

Sponsor: Rider 2018.2 ist da! Veröffentlichen in IIS, Docker-Unterstützung im Debugger, integrierte Rechtschreibprüfung, MacBook Touch Bar-Unterstützung, vollständige C# 7.3-Unterstützung, erweiterte Unity-Unterstützung und mehr.


Docker
  1. So installieren Sie .NET Core unter Debian 10

  2. Was sind die Funktionen einer Anwendung, die zu einer Kern-/vorinstallierten/Standard-Ubuntu-Anwendung wird?

  3. Ein vollständiger containerisierter .NET Core-Anwendungsmikrodienst, der so klein wie möglich ist

  4. Erkennen, dass eine .NET Core-App in einem Docker-Container ausgeführt wird, und SkipableFacts in XUnit

  5. Optimieren der Größen von ASP.NET Core Docker-Images

Erstellen, Ausführen und Testen von .NET Core und ASP.NET Core 2.1 in Docker auf einem Raspberry Pi (ARM32)

Ein serverseitiger Multiplayer-GameBoy-Emulator, geschrieben in .NET Core und Angular

Testen neuer .NET Core Alpine Docker-Images

.NET und Docker

Erkunden von ASP.NET Core mit Docker in Linux- und Windows-Containern

Installieren von PowerShell Core auf einem Raspberry Pi (powered by .NET Core)