GNU/Linux >> Znalost Linux >  >> Panels >> Docker

Optimalizace velikostí obrazu ASP.NET Core Docker

Existuje skvělý příspěvek od Steva Lastera z roku 2016 o optimalizaci velikostí obrázků ASP.NET Docker. Od té doby Docker přidal vícefázové soubory sestavení, takže můžete udělat více v jednom Dockerfile... což se zdá jako jeden krok, i když tomu tak není. Kontejnery jsou o snadném a spolehlivém nasazení a také o hustotě. Jistě chcete používat co nejméně paměti, ale je také hezké je udělat co nejmenší, abyste neztráceli čas jejich přemisťováním po síti. Velikost souboru obrázku může také ovlivnit dobu spuštění kontejneru. Navíc je prostě uklizený.

Tento týden jsem na svém stole stavěl malý 6uzlový Raspberry Pi (ARM) Kubenetes Cluster – stejně jako vy – a všiml jsem si, že velikost mých obrázků byla o něco větší, než bych chtěl. Toto je větší problém, protože se jedná o systém s relativně nízkou spotřebou, ale znovu, proč s sebou nosit x zbytečných megabajtů, když nemusíte?

Alex Ellis má skvělý blog o vytváření aplikací .NET Core pro Raspberry Pi spolu s videem na YouTube. Ve svém videu a blogu staví konzolovou aplikaci „Console.WriteLine()“, která je skvělá pro OpenFaas (otevřená platforma bez serveru), ale chtěl jsem mít na clusteru Raspberry Pi k8 také aplikace ASP.NET Core. Zahrnul to jako „výzvu“ na svůj blog, takže výzva přijata! Děkujeme za vaši pomoc a podporu, Alexi!

ASP.NET Core na Dockeru (na ARM)

Nejprve vytvořím základní aplikaci ASP.NET Core. Mohl bych udělat webové API, ale tentokrát udělám MVC s Razor Pages. Aby bylo jasno, jde o totéž, jen s odlišnými výchozími body. Stránky nebo JSON mohu přidat kdykoli později.

Začnu s "dotnet new mvc" (nebo dotnet new břitva atd.). Budu to spouštět v Dockeru, spravovaném Kuberenetes, a i když vždy mohu změnit WebHost v Program.cs, abych změnil způsob spouštění webového serveru Kestrel takto:

WebHost.CreateDefaultBuilder(args)
.UseUrls("http://*:5000;http://localhost:5001;https://hostname:5002")

Pro případy použití Dockeru je jednodušší změnit naslouchající URL pomocí proměnné prostředí. Jistě, mohlo by to být 80, ale já mám rád 5000. Když vytvořím Dockerfile, nastavím proměnnou prostředí ASPNETCORE_URLS na http://+:5000.

Optimalizovaný MultiStage Dockerfile pro ASP.NET

Existuje řada „správných“ způsobů, jak toho dosáhnout, takže budete chtít přemýšlet o svých scénářích. Níže uvidíte, že používám ARM (protože Raspberry Pi), takže pokud vidíte chyby spusťte svůj kontejner jako "qemu:Unsupported syscall:345", pak se pokoušíte spustit obraz ARM na x86/x64. Budu stavět kontejner ARM z Windows, ale nemohu ho zde spustit. Musím to poslat do registru kontejnerů a pak říct svému clusteru Raspberry Pi, aby to stáhl, a PAK to tam poběží.

Tady je to, co zatím mám. POZNÁMKA, některé věci jsou komentovány, takže buďte při vědomí. Toto je/bylo pro mě učební cvičení. Nekopírujte/nevkládejte, pokud nevíte, co se děje! A pokud dojde k chybě, zde je GitHub Gist mého Dockerfile, který můžete změnit a vylepšit.

Je důležité pochopit, že .NET Core má SDK s nástroji pro vytváření a vývojové sady a kompilátory a podobně, a pak má běhové prostředí. Běhové prostředí nemá funkci „vytvořit aplikaci“, má pouze funkci „spustit aplikaci“. V současné době neexistuje SDK pro ARM, takže to je omezení, že (poněkud elegantně) pracujeme s vícestupňovým souborem sestavení. Ale i kdyby existovala sada SDK pro ARM, stále bychom chtěli použít Dockerfile, jako je tento, protože je efektivnější s prostorem a vytváří menší obrázek.

Pojďme to rozebrat. Existují dvě fáze. První FROM je obrázek SDK, který vytváří kód. Sestavení provádíme uvnitř Dockeru – což je krásný a skvělý spolehlivý způsob vytváření sestav.

PRO TIP: Docker umí chytře vytvářet přechodné obrázky a vykonává nejméně práce , ale je užitečné, když my (autoři) uděláme správnou věc, abychom tomu pomohli.

Podívejte se například, kam zkopírujeme soubor .csproj a poté provedeme „obnovení dotnetu“? Často uvidíte lidi dělat "KOPÍROVAT..." a poté proveďte obnovu. To neumožňuje Dockeru zjistit, co se změnilo, a vy nakonec zaplatíte za obnovení při KAŽDÉ SESTAVENÍ.

Provedením těchto dvou kroků – zkopírujte projekt, obnovte, zkopírujte kód, to znamená, že váš mezikrok „obnovení dotnetu“ bude uložen do mezipaměti Dockeru a věci budou MNOHEM rychlejší.

Po sestavení provedete publikování. Pokud znáte cíl jako já (linux-arm), můžete publikovat RID (runtime id), které je samostatné s -r linux-arm (nebo debian, nebo cokoli jiného) a získáte kompletní self- obsažená verze vaší aplikace.

V opačném případě stačí publikovat kód své aplikace a ke spuštění použít runtime image .NET Core. Protože pro tento obrázek používám kompletní samostatné sestavení, bylo by přehnané zahrnout TAKÉ .NET runtime. Pokud se podíváte na centrum Docker pro Microsoft/dotnet, uvidíte obrázky nazvané „deps“ pro „závislosti“. To jsou obrázky, které jsou umístěny na vrcholu debianu a obsahují věci, které .NET potřebuje ke svému běhu – ale ne .NET samotný.

Zásobník obrázků vypadá obecně takto (například)

  • Z debian:stretch
  • OD microsoft/dotnet:2.0-runtime-deps
  • OD microsoft/dotnet:2.0-runtime

Takže máte svůj základní obraz, své závislosti a svůj .NET runtime. Obrázek SDK by obsahoval ještě více věcí, protože potřebuje sestavit kód. Znovu, proto to používáme pro obrázek „jako tvůrce“ a poté zkopírujeme výsledky kompilace a vložte je do jiného runtime obrazu. Získáte to nejlepší ze všech světů.

FROM microsoft/dotnet:2.0-sdk as builder  

RUN mkdir -p /root/src/app/aspnetcoreapp
WORKDIR /root/src/app/aspnetcoreapp

#copy just the project file over
# this prevents additional extraneous restores
# and allows us to re-use the intermediate layer
# This only happens again if we change the csproj.
# This means WAY faster builds!
COPY aspnetcoreapp.csproj .
#Because we have a custom nuget.config, copy it in
COPY nuget.config .
RUN dotnet restore ./aspnetcoreapp.csproj

COPY . .
RUN dotnet publish -c release -o published -r linux-arm

#Smaller - Best for apps with self-contained .NETs, as it doesn't include the runtime
# It has the *dependencies* to run .NET Apps. The .NET runtime image sits on this
FROM microsoft/dotnet:2.0.0-runtime-deps-stretch-arm32v7

#Bigger - Best for apps .NETs that aren't self-contained.
#FROM microsoft/dotnet:2.0.0-runtime-stretch-arm32v7

# These are the non-ARM images.
#FROM microsoft/dotnet:2.0.0-runtime-deps
#FROM microsoft/dotnet:2.0.0-runtime

WORKDIR /root/
COPY --from=builder /root/src/app/aspnetcoreapp/published .
ENV ASPNETCORE_URLS=http://+:5000
EXPOSE 5000/tcp
# This runs your app with the dotnet exe included with the runtime or SDK
#CMD ["dotnet", "./aspnetcoreapp.dll"]
# This runs your self-contained .NET Core app. You built with -r to get this
CMD ["./aspnetcoreapp"]

Všimněte si také, že mám vlastní nuget.config, takže pokud to uděláte také, budete se muset ujistit, že je k dispozici v době sestavení, aby bylo možné obnovit dotnet, aby vyzvedl všechny balíčky.

Zahrnul jsem okomentováním spoustu FROMů ve druhé fázi. Používám pouze ARM, ale chtěl jsem, abyste viděli ostatní.

Jakmile máme vytvořený kód zkopírován do našeho runtime obrazu, nastavíme naši proměnnou prostředí tak, aby vše poslouchalo interně na portu 5000 (pamatujete si to shora?) Potom spustíme naši aplikaci. Všimněte si, že jej můžete spustit s "dotnet foo.dll", pokud máte runtime, ale pokud jste jako já a používáte samostatné sestavení, pak spustíte "foo."

Abych to shrnul:

  • Vytvářejte pomocí nástroje FROM microsoft/dotnet:2.0-sdk jako builder
  • Zkopírujte výsledky do běhového prostředí
  • Používejte správné runtime FROM pro vás
    • Správná architektura CPU?
    • Použití .NET Runtime (typické) nebo použití samostatného sestavení (méně tak)
  • Posloucháte na správném portu (pokud se jedná o webovou aplikaci)?
  • Spouštíte aplikaci úspěšně a správně?
  • Máte .dockerignore? Velmi důležité pro .NET Builds, protože nechcete kopírovat přes /obj, /bin atd., ale chcete /published.
    obj/
    bin/
    !published /

Ještě trochu optimalizace

Existuje několik předběžných nástrojů „Tree Trimming“, které se mohou podívat na vaši aplikaci a odstranit kód a binární soubory, které nevoláte. Zahrnul jsem také Microsoft.Packaging.Tools.Trimming, abych to vyzkoušel a získal ještě více nepoužitého kódu z mého finálního obrázku pouhým přidáním balíčku do mého projektu.

Step 8/14 : RUN dotnet publish -c release -o published -r linux-arm /p:LinkDuringPublish=true
---> Running in 39404479945f
Microsoft (R) Build Engine version 15.4.8.50001 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

Trimmed 152 out of 347 files for a savings of 20.54 MB
Final app size is 33.56 MB
aspnetcoreapp -> /root/src/app/aspnetcoreapp/bin/release/netcoreapp2.0/linux-arm/aspnetcoreapp.dll
Trimmed 152 out of 347 files for a savings of 20.54 MB
Final app size is 33.56 MB

Pokud na konečném obrázku spustíte historii dockeru, můžete přesně vidět, odkud velikost pochází. Pokud/když Microsoft přejde ze základního obrazu Debianu na Alpine, mělo by to být ještě menší.

C:\Users\scott\Desktop\k8s for pi\aspnetcoreapp>docker history c60
IMAGE CREATED CREATED BY SIZE COMMENT
c6094ca46c3b 3 minutes ago /bin/sh -c #(nop) CMD ["dotnet" "./aspnet... 0B
b7dfcf137587 3 minutes ago /bin/sh -c #(nop) EXPOSE 5000/tcp 0B
a5ba51b91d9d 3 minutes ago /bin/sh -c #(nop) ENV ASPNETCORE_URLS=htt... 0B
8742269735bc 3 minutes ago /bin/sh -c #(nop) COPY dir:cc64bd3b9bacaeb... 56.5MB
28c008e38973 3 minutes ago /bin/sh -c #(nop) WORKDIR /root/ 0B
4bafd6e2811a 4 hours ago /bin/sh -c apt-get update && apt-get i... 45.4MB
<missing> 3 weeks ago /bin/sh -c #(nop) CMD ["bash"] 0B
<missing> 3 weeks ago /bin/sh -c #(nop) ADD file:8b7cf813a113aa2... 85.7MB

Zde je vývoj mého Dockerfile, jak jsem provedl změny a konečný výsledek byl stále menší a menší. Vypadá to, že 45 megů oříznutých s trochou práce nebo asi o 20 % menší.

C:\Users\scott\Desktop\k8s for pi\aspnetcoreapp>docker images | find /i "aspnetcoreapp"
shanselman/aspnetcoreapp 0.5 c6094ca46c3b About a minute ago 188MB
shanselman/aspnetcoreapp 0.4 083bfbdc4e01 12 minutes ago 196MB
shanselman/aspnetcoreapp 0.3 fa053b4ee2b4 About an hour ago 199MB
shanselman/aspnetcoreapp 0.2 ba73f14e29aa 4 hours ago 207MB
shanselman/aspnetcoreapp 0.1 cac2f0e3826c 3 hours ago 233MB

Později udělám blogový příspěvek, kde vložím tuto standardní webovou aplikaci ASP.NET Core do Kubernetes pomocí tohoto popisu YAML a zvětším ji na Raspberry Pi. Hodně se učím! Děkuji Alex Ellis a Glenn Condron a Jessie Frazelle za jejich čas!

Sponzor: Vytvářejte výkonné webové aplikace pro správu každého kroku životního cyklu dokumentu pomocí prohlížeče HTML5 DocuVieware a sady pro správu dokumentů. Podívejte se na naše ukázky a získejte, skenujte, upravujte, komentujte více než 100 formátů a přizpůsobujte své uživatelské rozhraní!


Docker
  1. Extrahovat soubor z obrázku Dockeru?

  2. Jak použít Dockerfile k vytvoření Docker Image

  3. Spuštění samostatné aplikace ASP.NET Core na Ubuntu

  1. Stručný úvod do Dockerfile

  2. Jak upravit obrázky Docker

  3. Jak potvrdit změny v obrazu Dockeru

  1. Jak spustit aplikaci .NET v Dockeru

  2. Co je to manifest obrazu Docker?

  3. Sdílení obrázků Docker na Docker Hub