GNU/Linux >> Tutoriels Linux >  >> Panels >> Docker

Un microservice d'application .NET Core conteneurisé complet et aussi petit que possible

OK, peut-être techniquement pas un microservice, mais c'est un mot à la mode ces jours-ci, n'est-ce pas ? Il y a quelques semaines, j'ai blogué sur les améliorations apportées aux déploiements ASP.NET Core sur Zeit's now.sh et sur la création de petites images de conteneurs. À la fin, j'ai pu réduire de moitié la taille de mon conteneur.

La coupe que j'utilisais est expérimentale et très agressive. Si votre application charge des choses au moment de l'exécution - comme le font parfois ASP.NET Razor Pages - vous risquez d'obtenir des erreurs étranges au moment de l'exécution lorsqu'un type est manquant. Certains types peuvent avoir été coupés !

Par exemple :

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)

Aïe !

Je fais un déploiement autonome, puis coupe le résultat ! Richard Lander a un excellent exemple de dockerfile. Notez comment il fait l'ajout de package avec la CLI dotnet avec "dotnet add package" et la garniture suivante dans le Dockerfile (au lieu de l'ajouter au csproj de votre copie de développement local).

J'ajoute le Tree Trimming Linker dans le Dockerfile, de sorte que le découpage se produit lorsque l'image du conteneur est construite. J'utilise la commande dotnet pour "dotnet add package ILLink.Tasks. Cela signifie que je n'ai pas besoin de référencer le package de l'éditeur de liens au moment du développement - tout est au moment de la construction du conteneur.

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

J'ai fini par rencontrer ce bogue dans le Linker (il n'est pas publié) mais il existe une solution de contournement simple. J'ai juste besoin de définir la propriété CrossGenDuringPublish à false dans le fichier projet.

Si vous regardez les instructions avancées pour l'éditeur de liens, vous pouvez voir que vous pouvez "raciner" des types ou des assemblages. Racine signifie "ne plaisante pas avec ceux-ci ou des trucs qui leur sont suspendus". J'ai donc juste besoin d'exercer mon application au moment de l'exécution et de m'assurer que tous les types dont mon application a besoin sont disponibles, mais pas inutiles.

J'ai ajouté les assemblages que je voulais conserver (et non supprimer) lors du découpage/du lien vers mon fichier de projet :

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

Ma stratégie pour déterminer quels assemblys "raciner" et exclure du découpage consistait littéralement à itérer. Construisez, coupez, testez, ajoutez un assemblage en lisant le message d'erreur et répétez.

Cet exemple d'application ASP.NET Core se déploiera proprement sur Zeit avec la plus petite empreinte d'image possible. https://github.com/shanselman/superzeit

Ensuite, je vais essayer un microservice réel (par opposition à un site Web complet, c'est ce que c'est) et voir à quel point je peux obtenir cela. Tellement amusant !

MISE À JOUR : Cette technique fonctionne également avec "dotnet new webapi" et représente environ 73 mo par "images docker" et 34 mo lorsqu'elle est envoyée et écrasée via la CLI "maintenant" de Zeit.

Parrain : L'avenant 2018.2 est arrivé ! Publication sur IIS, prise en charge de Docker dans le débogueur, vérification orthographique intégrée, prise en charge de la barre tactile MacBook, prise en charge complète de C# 7.3, prise en charge avancée de Unity, etc.


Docker
  1. Un microservice d'application .NET Core conteneurisé complet et aussi petit que possible

  2. Détecter qu'une application .NET Core est en cours d'exécution dans un conteneur Docker et SkippableFacts dans XUnit

  3. Visual Basic est-il pris en charge par .NET Core sous Linux ?

  4. Exécution d'une application ASP.NET Core autonome sur Ubuntu

  5. .NET core X509Store sur Linux

Création, exécution et test de .NET Core et ASP.NET Core 2.1 dans Docker sur un Raspberry Pi (ARM32)

Un émulateur GameBoy côté serveur multi-joueurs écrit en .NET Core et Angular

Essayer de nouvelles images Docker Alpine .NET Core

.NET et Docker

Explorer ASP.NET Core avec Docker dans les conteneurs Linux et Windows

Installation de PowerShell Core sur un Raspberry Pi (alimenté par .NET Core)