{"id":7710,"date":"2020-10-20T11:11:10","date_gmt":"2020-10-20T09:11:10","guid":{"rendered":"https:\/\/whiteduck.de\/?p=7710"},"modified":"2021-09-21T15:52:51","modified_gmt":"2021-09-21T13:52:51","slug":"containerisierung-von-netcore-microservices","status":"publish","type":"post","link":"https:\/\/whiteduck.de\/en\/containerisierung-von-netcore-microservices\/","title":{"rendered":"Containerisierung von .NET Core Microservices &#8211; Tipps &#038; Tricks"},"content":{"rendered":"<p><div class=\"fusion-fullwidth fullwidth-box fusion-builder-row-1 fusion-flex-container nonhundred-percent-fullwidth non-hundred-percent-height-scrolling\" style=\"--awb-border-radius-top-left:0px;--awb-border-radius-top-right:0px;--awb-border-radius-bottom-right:0px;--awb-border-radius-bottom-left:0px;--awb-flex-wrap:wrap;\" ><\/div><div class=\"fusion-builder-row fusion-row fusion-flex-align-items-flex-start fusion-flex-content-wrap\" style=\"max-width:calc( 1170px + 0px );margin-left: calc(-0px \/ 2 );margin-right: calc(-0px \/ 2 );\"><\/div><div class=\"fusion-layout-column fusion_builder_column fusion-builder-column-0 fusion_builder_column_1_1 1_1 fusion-one-full fusion-column-first fusion-column-last\" style=\"--awb-bg-size:cover;width:100%;\"><div class=\"fusion-column-wrapper fusion-flex-column-wrapper-legacy\"><div class=\"fusion-clearfix\"><\/div><\/div><\/div><div class=\"fusion-title title fusion-title-1 fusion-sep-none fusion-title-text fusion-title-size-one\" style=\"--awb-margin-top-small:0px;--awb-margin-right-small:0px;--awb-margin-bottom-small:20px;--awb-margin-left-small:0px;\"><h1 class=\"fusion-title-heading title-heading-left fusion-responsive-typography-calculated\" style=\"margin:0;--fontSize:32;line-height:1.31;\"><\/p>\n<p>Containerisierung von .NET Core Microservices &#8211; Tipps &amp; Tricks<\/p>\n<p><\/h1><\/div><div class=\"fusion-text fusion-text-1\"><\/div><\/p>\n<p class=\"c-paragraph-2\">Es gibt bereits viele Artikel, in denen Sie Einzelheiten zur Containerisierung von .NET Core-Anwendung finden k\u00f6nnen. Trotzdem bin ich der Meinung, dass ein detaillierter Post helfen kann Best Practices f\u00fcr ein produktionsreifes Container-Image auf der Grundlage von Container- und .NET Core-Best Practices zu vermitteln.<\/p>\n<p class=\"c-paragraph-2\">Zum besseren Verst\u00e4ndnis werde ich alles im Detail anhand einer kleinen ASP .NET-Core Beispiel-Webanwendung erkl\u00e4ren. Mehr Details zur Anwendung selbst finden Sie <a class=\"c-hyperlink\" href=\"https:\/\/github.com\/whiteducksoftware\/sample-mvc\" target=\"_blank\" rel=\"noopener noreferrer\">hier<\/a>. Nat\u00fcrlich sind die unten genannten Praktiken nicht auf .NET Core beschr\u00e4nkt. Sie k\u00f6nnen diese auf Ihre weiteren Projekte und Anwendungsf\u00e4lle ausweiten.<\/p>\n<p class=\"c-paragraph-2\">Es gibt unz\u00e4hlige Anwendungsf\u00e4lle, weshalb es auch keine &#8220;one fits all&#8221;-L\u00f6sung gibt. Ich m\u00f6chte Ihnen zwei verschiedene Optionen vorstellen, welche ich pers\u00f6nlich am h\u00e4ufigsten verwende. Aber lassen Sie uns erst mit einigen Grundlagen beginnen.<\/p>\n<p><\/p>\n\n\n<h2 class=\"wp-block-heading\">Das g\u00e4ngige Beispiel<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Dies ist ein g\u00e4ngiges Beispiel f\u00fcr ein Dockerfile, das mir recht h\u00e4ufig begegnet: <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>FROM mcr.microsoft.com\/dotnet\/core\/aspnet:3.1\nWORKDIR \/app\nCOPY \/app\/output .\nEXPOSE 8080\nENTRYPOINT &#091;\"dotnet\", \"sample-mvc.dll\"]<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">An diesem Beispiel ist nichts falsch. Es wird funktionieren, aber es ist keineswegs optimiert. Weder f\u00fcr Performance noch f\u00fcr sicherheitsrelevante Aspekte und ist daher nicht optimal f\u00fcr eine Produktionsumgebung. Hier einige Beispiele:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Der Prozess wird im Container mit Root-Rechten ausgef\u00fchrt<\/li><li>Eine ineffiziente Reihenfolge der Befehle, die zu einem langsameren Build f\u00fchren k\u00f6nnen<\/li><li>Eine ineffiziente Image-Layer-Verwaltung, die sich auf das finale Container Image auswirkt<\/li><li>Langsamere Builds aufgrund der fehlenden `.dockerignore&#8217;-Datei<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Schauen wir uns ein weiteres Dockerfile-Beispiel etwas genauer an:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>FROM mcr.microsoft.com\/dotnet\/core\/sdk:3.1\nWORKDIR \/app\nADD \/src .\nRUN dotnet publish \\\n  -c Release \\\n  -o .\/output\nEXPOSE 8080\nENTRYPOINT &#091;\"dotnet\", \"sample-mvc.dll\"]<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In diesem Beispiel wird ein containerisierter Build verwendet. Dies bedeutet, dass der Anwendungs-Build selbst in den Docker-Build-Prozess verlagert wird. Dies ist ein gutes Pattern, das es Ihnen erlaubt, in einer unver\u00e4nderlichen und isolierten Umgebung die Anwendung zu bauen. Ein Nachteil ist jedoch, dass Sie Ihr Image auf der Grundlage eines gr\u00f6\u00dferen SDK-Images erstellen m\u00fcssen. Das SDK-Image stellt die f\u00fcr die Erstellung der Anwendung erforderlichen Abh\u00e4ngigkeiten bereit, w\u00e4re aber f\u00fcr die anschlie\u00dfende Ausf\u00fchrung nicht erforderlich. Es existiert jedoch eine Pattern, das dieses Problem l\u00f6st. Multi-stage Builds.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><span class=\"has-inline-color has-white-color\">.<\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Multi-stage Builds<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Wenn Sie eine \u00e4hnliche Version der oben genannten Dockerfiles verwenden, haben Sie vielleicht noch nicht von Multi-stage Container-Builds geh\u00f6rt. Mehrstufige Builds erm\u00f6glichen es uns, unseren Image-Build-Prozess in mehrere Schritte aufzuteilen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Die erste Stufe dient der Erstellung unserer Anwendung, f\u00fcr die wir die erforderlichen Abh\u00e4ngigkeiten bereitstellen m\u00fcssen. In der zweiten Stufe kopieren wir die Anwendungsartefakte in eine kleinere Laufzeitumgebung, die dann als unser endg\u00fcltiges Container Image verwendet wird. Ein entsprechendes Dockerfile sieht wie folgt aus:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>FROM mcr.microsoft.com\/dotnet\/core\/sdk:3.1 AS build-env\nWORKDIR \/app\nADD \/src .\nRUN dotnet publish \\\n  -c Release \\\n  -o .\/output\nFROM mcr.microsoft.com\/dotnet\/core\/aspnet:3.1\nWORKDIR \/app\nCOPY --from=build-env \/app\/output .\nEXPOSE 8080\nENTRYPOINT &#091;\"dotnet\", \"sample-mvc.dll\"]<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Schauen wir uns die einzelnen Schritte n\u00e4her an:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>FROM mcr.microsoft.com\/dotnet\/core\/sdk:3.1 AS build-env\n...\nRUN dotnet publish \\\n  -c Release \\\n  -o .\/output\n...<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Unser erster Schritt basiert auf dem SDK-Image, das alle Abh\u00e4ngigkeiten f\u00fcr die Erstellung unserer Anwendung bereitstellt.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>...\nFROM mcr.microsoft.com\/dotnet\/core\/aspnet:3.1\n...\nCOPY --from=build-env \/app\/output .\n...<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Im zweiten Scrhitt definieren wir ein neues Basis-Image, das diesmal nur unsere Laufzeitabh\u00e4ngigkeiten enth\u00e4lt. Dann kopieren wir die Anwendungsartefakte aus dem ersten Image in das zweite Image.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Damit sind wir nun in der Lage, ein kleineres und sichereres Container-Image zu erstellen, da es nur die zur Ausf\u00fchrung der Anwendung erforderlichen Abh\u00e4ngigkeiten enth\u00e4lt. Es gibt aber weiterhin noch Raum f\u00fcr Verbesserungen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Wenn Sie mehr \u00fcber die Best Practices von Dockerfile erfahren m\u00f6chten, empfehle ich Ihnen einen Blick auf&nbsp;<a rel=\"noreferrer noopener\" target=\"_blank\" href=\"https:\/\/docs.docker.com\/develop\/develop-images\/dockerfile_best-practices\/\">diese Seite<\/a>&nbsp;oder die offizielle Docker Dokumentation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><span class=\"has-inline-color has-white-color\">.<\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Sie haben die Wahl<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Wie bereits erw\u00e4hnt, gibt es nicht eine L\u00f6sung f\u00fcr alles. Sie variiert von Anwendungsfall zu Anwendungsfall. Mit den nachfolgenden Beispielen erhalten Sie zwei Beispiele sowie deren Vor- und Nachteile. Diese k\u00f6nnen Sie nat\u00fcrlich nach Ihren Bed\u00fcrfnissen anpassen.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Die Grundlage<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Das untenstehende Dockerfile ist eine optimierte Version des obigen Multi-Stage Beispiels und d\u00fcrfte f\u00fcr die meisten Szenarien gut geeignet sein.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ARG VERSION=3.1-alpine3.10\nFROM mcr.microsoft.com\/dotnet\/core\/sdk:$VERSION AS build-env\nWORKDIR \/app\nADD \/src\/*.csproj .\nRUN dotnet restore\nADD \/src .\nRUN dotnet publish \\\n  -c Release \\\n  -o .\/output\nFROM mcr.microsoft.com\/dotnet\/core\/aspnet:$VERSION\nRUN adduser \\\n  --disabled-password \\\n  --home \/app \\\n  --gecos '' app \\\n  &amp;&amp; chown -R app \/app\nUSER app\nWORKDIR \/app\nCOPY --from=build-env \/app\/output .\nENV DOTNET_RUNNING_IN_CONTAINER=true \\\n  ASPNETCORE_URLS=http:\/\/+:8080\nEXPOSE 8080\nENTRYPOINT &#091;\"dotnet\", \"sample-mvc.dll\"]<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Auch hier schauen wir uns die einzelnen Schritte genauer an:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ARG VERSION=3.1-alpine3.10\nFROM mcr.microsoft.com\/dotnet\/core\/sdk:$VERSION AS build-env\n...<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Wir definieren zun\u00e4chst unser Basis Image mit Hilfe einer ARG-Anweisung. Dies hilft uns, den Tag leicht zu aktualisieren, anstatt jedesmal mehrere Zeilen zu \u00e4ndern. Wie Sie vielleicht bemerkt haben, verwenden wir ein anderes Tag. Das&nbsp;<em>tag3.1-alpine3.10<\/em>&nbsp;besagt, dass dieses Image die ASP .NET-Version 3.1 enth\u00e4lt und auf Alpine 3.10 basiert.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Alpine Linux ist eine Linux-Distribution, die speziell f\u00fcr Anwendungsszenarien im Hinblick auf Sicherheit, Einfachheit und Ressourceneffizienz entwickelt wurde. In diesem Schritt kann Alpine Linux uns bereits dabei helfen, den Speicherbedarf unserer Build-Phase zu reduzieren.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>...\nFROM mcr.microsoft.com\/dotnet\/core\/aspnet:$VERSION\n...<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Da wir Multi-Stage Builds verwenden, m\u00fcssen wir auch das Image definieren, das in unserem zweiten Schritt verwendet wird. Hier werden wir die Alpine basierte ASP .NET-Laufzeitumgebung als unser Basis-Image verwenden. Wie bereits gesagt, erm\u00f6glicht uns Alpine kleinere und sicherere Container-Images zu erstellen.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ADD \/src\/*.csproj .\nRUN dotnet restore\nADD \/src .\nRUN dotnet publish \\\n  -c Release \\\n  -o .\/output<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Anders als im oberen Beispiel teilen wir diesmal den Build-Prozess in mehrere Teile auf. Der Befehl&nbsp;<code>dotnet restore<\/code>&nbsp;verwendet NuGet zur Wiederherstellung von Abh\u00e4ngigkeiten sowie von projektspezifischen Tools, die in der Projektdatei angegeben sind. Das Wiederherstellen von Abh\u00e4ngigkeiten ist ebenfalls Teil des Befehls&nbsp;<code>dotnet publish<\/code>, die Trennung erlaubt uns jedoch die Abh\u00e4ngigkeiten in einer separaten Image-Layer zu speichern. Dies verk\u00fcrzt die Zeit, die f\u00fcr den Aufbau des Images ben\u00f6tigt wird, und reduziert die Gr\u00f6\u00dfe des Downloads, da die Abh\u00e4ngigkeiten der Image-Layer nur dann neu aufgebaut werden, wenn die Abh\u00e4ngigkeiten ge\u00e4ndert werden.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>...\nRUN adduser \\\n  --disabled-password \\\n  --home \/app \\\n  --gecos '' app \\\n  &amp;&amp; chown -R app \/app\nUSER app\n...<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Um die Laufzeit unserer Anwendung zu sch\u00fctzen, m\u00fcssen wir sie ohne Root-Rechte ausf\u00fchren. Aus diesem Grund legen wir einen neuen Benutzer an und \u00e4ndern den Benutzerkontext unter Verwendung der USER-Definition.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>...\nENV DOTNET_RUNNING_IN_CONTAINER=true \\\n  ASPNETCORE_URLS=http:\/\/+:8080\nEXPOSE 8080\n...<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Da wir unsere Anwendung ohne jegliche Root-Privilegien ausf\u00fchren, m\u00fcssen wir diese auch auf einem Port h\u00f6her 1024 bereitstellen. In unserem Beispiel wurde 8080 gew\u00e4hlt. Mit der ENV-Definition k\u00f6nnen wir der Anwendung weitere Umgebungsvariablen mitgeben.&nbsp;<em>DOTNET_RUNNING_IN_CONTAINER=true<\/em>&nbsp;ist eine informelle Umgebungsvariable, um einen Entwickler\/Anwendung wissen zu lassen, dass der Prozess innerhalb eines Containers l\u00e4uft.&nbsp;<em>ASPNETCORE_URLS=http:\/\/+:8080<\/em>&nbsp;wird genutzt um den konfigurierten Port mit dem Port 8080 zu \u00fcberschreiben.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><span class=\"has-inline-color has-white-color\">.<\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Kleiner, kleiner, kleiner<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Wie bereits erw\u00e4hnt, d\u00fcrfte das obere Beispiel f\u00fcr die meisten der Szenarien geeignet sein. Das folgende Beispiel beschreibt eine M\u00f6glichkeit, ein m\u00f6glichst kleines Container-Image zu erstellen. Ein m\u00f6glicher Anwendungsfall k\u00f6nnte ein&nbsp;<a target=\"_blank\" rel=\"noreferrer noopener\" href=\"https:\/\/azure.microsoft.com\/de-de\/services\/iot-edge\/\">IoT Edge Szenario<\/a>, oder Umgebungen die eine optimierte Startzeit ben\u00f6tigen, sein. Allerdings gibt es auch einige Nachteile, auf die ich im Nachhinein noch n\u00e4her eingehen werde.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ARG VERSION=3.1-alpine3.10\nFROM mcr.microsoft.com\/dotnet\/core\/sdk:$VERSION AS build-env\nWORKDIR \/app\nADD \/src .\nRUN dotnet publish \\\n  --runtime alpine-x64 \\\n  --self-contained true \\\n  \/p:PublishTrimmed=true \\\n  \/p:PublishSingleFile=true \\\n  -c Release \\\n  -o .\/output\nFROM mcr.microsoft.com\/dotnet\/core\/runtime-deps:$VERSION\nRUN adduser \\\n  --disabled-password \\\n  --home \/app \\\n  --gecos '' app \\\n  &amp;&amp; chown -R app \/app\nUSER app\nWORKDIR \/app\nCOPY --from=build-env \/app\/output .\nENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 \\\n  DOTNET_RUNNING_IN_CONTAINER=true \\\n  ASPNETCORE_URLS=http:\/\/+:8080\nEXPOSE 8080\nENTRYPOINT &#091;\".\/sample-mvc\", \"--urls\", \"http:\/\/0.0.0.0:8080\"]<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Noch einmal schauen wir uns die einzelnen Schritte genauer an:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>...\nRUN dotnet publish \\\n  --runtime alpine-x64 \\\n  --self-contained true \\\n  \/p:PublishTrimmed=true \\\n  \/p:PublishSingleFile=true \\\n  -c Release \\\n  -o .\/output\n...<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Der gro\u00dfe Unterschied zum oberen Beispiel besteht darin, dass wir eine in sich geschlossene Anwendung bauen werden. Die Angabe des Parameters&nbsp;<code>--self-contained true<\/code>&nbsp;zwingt den Build dazu, alle Abh\u00e4ngigkeiten in das Anwendungsartefakt einzubeziehen. Das schlie\u00dft die .NET Core-Laufzeitumgebung ein. Aus diesem Grund m\u00fcssen wir auch die Laufzeitumgebung definieren, in der wir die Anwendung ausf\u00fchren m\u00f6chten. Dies geschieht mit dem Parameter&nbsp;<code>--runtime alpine-x64<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Da das fertige Image f\u00fcr die Gr\u00f6\u00dfe optimiert sein soll, definieren wir das Flag&nbsp;<code>\/p:PubishTrimmed=true<\/code>, das den Build-Prozess anweist, keine unbenutzten Bibliotheken einzubinden. Das Flag&nbsp;<code>\/p:PublishSingleFile=true<\/code>&nbsp;erlaubt es uns, den Build-Prozess selbst zu beschleunigen. Ein Nachteil ist, dass Sie dynamisch geladene Assemblys im Voraus definieren m\u00fcssen, um sicherzustellen, dass ben\u00f6tigte Bibliotheken im Image vorhanden sind. Weitere Informationen dazu finden Sie&nbsp;<a target=\"_blank\" rel=\"noreferrer noopener\" href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/core\/whats-new\/dotnet-core-3-0\">hier<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ein zweiter Nachteil ist, dass Code-\u00c4nderungen zu einer gr\u00f6\u00dferen \u00c4nderung f\u00fchren. Dies liegt daran, dass der Code und die Laufzeit in einem einzigen Image-Layer zusammengefasst sind. Jedes Mal, wenn sich der Code \u00e4ndert, muss der gesamte Image-Layer neu erzeugt und auch neu auf die Systeme heruntergeladen werden.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>...\nFROM mcr.microsoft.com\/dotnet\/core\/runtime-deps:$VERSION\n...<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Da das Anwendungsartefakt in sich geschlossen ist, brauchen wir keine Laufzeitumgebung mit dem Bild bereitzustellen. In diesem Beispiel habe ich das Runtime-deps-Image gew\u00e4hlt, das auf Alpine Linux basiert. Dieses Image ist auf die minimalen Abh\u00e4ngigkeiten reduziert, die zur Ausf\u00fchrung des Anwendungsartefakts erforderlich sind.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>...\nENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 \\\n  DOTNET_RUNNING_IN_CONTAINER=true \\\n  ASPNETCORE_URLS=http:\/\/+:8080\n...<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Eine weitere Optimierung der Image-Gr\u00f6\u00dfe ist die Verwendung des &#8220;globalization invariant&#8221; Modus. Dieser Modus ist n\u00fctzlich f\u00fcr Anwendungen, die nicht global bekannt sind und die Formatierungskonventionen, String-Vergleich und -Sortierreihenfolge der &#8220;invariant culture&#8221; verwenden k\u00f6nnen. Dieser Modus kann durch die Umgebungsvariable&nbsp;<em>DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1<\/em>&nbsp;aktiviert werden. Wenn Ihre Anwendung eine Globalisierung erfordert, m\u00fcssen Sie die&nbsp;<a target=\"_blank\" rel=\"noreferrer noopener\" href=\"https:\/\/pkgs.alpinelinux.org\/package\/edge\/main\/x86\/icu\">ICU library<\/a>&nbsp;installieren und die Umgebungsvariable entfernen. Dadurch wird die Gr\u00f6\u00dfe Ihres Container-Image um etwa 28 MB zunehmen. Weitere Einzelheiten \u00fcber den &#8220;globalization invariant&#8221; Modus finden Sie&nbsp;<a target=\"_blank\" rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/dotnet\/runtime\/blob\/master\/docs\/design\/features\/globalization-invariant-mode.md\">hier<\/a>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>...\nENTRYPOINT &#091;\".\/sample-mvc\", \"--urls\", \"http:\/\/0.0.0.0:8080\"]<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">F\u00fcr die in sich geschlossene Anwendungen m\u00fcssen wir die ENTRYPOINT-Definition \u00e4ndern, um das Artifakt selbst auszuf\u00fchren.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Die Gr\u00f6\u00dfe dieses Images wird etwa 73 MB betragen (einschlie\u00dflich der Beispielapplikation). Dies ist recht klein. Hier der Vergleich zu anderen Images:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>ein Image, das auf einem gew\u00f6hnlichen Multi-Stage Dockerfile basiert: 250 MB<\/li><li>ein Image, das auf dem oberen Multi-Stage Dockerfile basiert: 124 MB<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Wie bereits oben erw\u00e4hnt: Welches Dockerfile f\u00fcr Sie am besten geeignet ist, h\u00e4ngt von Ihrem Anwendungsfall ab. Kleiner ist nicht unbedingt besser.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Es gibt bereits viele Artikel, in denen Sie Einzelheiten zur Containerisierung von .NET Core-Anwendung finden k\u00f6nnen. Trotzdem bin ich der Meinung, dass ein detaillierter Post helfen kann Best Practices f\u00fcr ein produktionsreifes Container-Image auf der Grundlage von Container- und .NET Core-Best Practices zu vermitteln. Zum besseren Verst\u00e4ndnis werde ich alles im Detail anhand einer kleinen <a href=\"https:\/\/whiteduck.de\/en\/containerisierung-von-netcore-microservices\/\"> <\/p>\n<div style=\"color:#ff9900\">[&#8230;]<\/div>\n<p><\/a><\/p>\n","protected":false},"author":8,"featured_media":7713,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_tribe_events_control_status":"","_tribe_events_control_status_canceled_reason":"","_tribe_events_control_status_postponed_reason":"","_tribe_events_control_online":"","_tribe_events_control_online_url":"","footnotes":""},"categories":[432],"tags":[341,343,258,342,163,158,117,111],"class_list":["post-7710","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cloud-native","tag-net-core","tag-net-core-microservices","tag-azure-iot-edge","tag-build-image","tag-container","tag-docker","tag-github","tag-microservices"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.7 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Containerisierung von .NET Core Microservices - Tipps &amp; Tricks - white duck<\/title>\n<meta name=\"description\" content=\"Lesen Sie \u00fcber Best Practices f\u00fcr ein produktionsreifes Container-Image auf der Grundlage von Container- und .NET Core Anwendungen.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/whiteduck.de\/en\/containerisierung-von-netcore-microservices\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Containerisierung von .NET Core Microservices - Tipps &amp; Tricks - white duck\" \/>\n<meta property=\"og:description\" content=\"Lesen Sie \u00fcber Best Practices f\u00fcr ein produktionsreifes Container-Image auf der Grundlage von Container- und .NET Core Anwendungen.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/whiteduck.de\/en\/containerisierung-von-netcore-microservices\/\" \/>\n<meta property=\"og:site_name\" content=\"white duck\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/whiteduckgmbh\" \/>\n<meta property=\"article:published_time\" content=\"2020-10-20T09:11:10+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2021-09-21T13:52:51+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/whiteduck.de\/wp-content\/uploads\/guillaume-bolduc-uBe2mknURG4-unsplash-scaled.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"2560\" \/>\n\t<meta property=\"og:image:height\" content=\"1852\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Nico Meisenzahl\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@whiteduck_gmbh\" \/>\n<meta name=\"twitter:site\" content=\"@whiteduck_gmbh\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Nico Meisenzahl\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/whiteduck.de\\\/en\\\/containerisierung-von-netcore-microservices\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/whiteduck.de\\\/en\\\/containerisierung-von-netcore-microservices\\\/\"},\"author\":{\"name\":\"Nico Meisenzahl\",\"@id\":\"https:\\\/\\\/whiteduck.de\\\/en\\\/#\\\/schema\\\/person\\\/c26beb86db4a71e77e24854ed07eda69\"},\"headline\":\"Containerisierung von .NET Core Microservices &#8211; Tipps &#038; Tricks\",\"datePublished\":\"2020-10-20T09:11:10+00:00\",\"dateModified\":\"2021-09-21T13:52:51+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/whiteduck.de\\\/en\\\/containerisierung-von-netcore-microservices\\\/\"},\"wordCount\":1694,\"image\":{\"@id\":\"https:\\\/\\\/whiteduck.de\\\/en\\\/containerisierung-von-netcore-microservices\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/whiteduck.de\\\/wp-content\\\/uploads\\\/guillaume-bolduc-uBe2mknURG4-unsplash-scaled.jpg\",\"keywords\":[\".NET Core\",\".NET Core Microservices\",\"Azure IoT Edge\",\"Build image\",\"Container\",\"Docker\",\"GitHub\",\"Microservices\"],\"articleSection\":[\"Cloud Native\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/whiteduck.de\\\/en\\\/containerisierung-von-netcore-microservices\\\/\",\"url\":\"https:\\\/\\\/whiteduck.de\\\/en\\\/containerisierung-von-netcore-microservices\\\/\",\"name\":\"Containerisierung von .NET Core Microservices - Tipps & Tricks - white duck\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/whiteduck.de\\\/en\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/whiteduck.de\\\/en\\\/containerisierung-von-netcore-microservices\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/whiteduck.de\\\/en\\\/containerisierung-von-netcore-microservices\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/whiteduck.de\\\/wp-content\\\/uploads\\\/guillaume-bolduc-uBe2mknURG4-unsplash-scaled.jpg\",\"datePublished\":\"2020-10-20T09:11:10+00:00\",\"dateModified\":\"2021-09-21T13:52:51+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/whiteduck.de\\\/en\\\/#\\\/schema\\\/person\\\/c26beb86db4a71e77e24854ed07eda69\"},\"description\":\"Lesen Sie \u00fcber Best Practices f\u00fcr ein produktionsreifes Container-Image auf der Grundlage von Container- und .NET Core Anwendungen.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/whiteduck.de\\\/en\\\/containerisierung-von-netcore-microservices\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/whiteduck.de\\\/en\\\/containerisierung-von-netcore-microservices\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/whiteduck.de\\\/en\\\/containerisierung-von-netcore-microservices\\\/#primaryimage\",\"url\":\"https:\\\/\\\/whiteduck.de\\\/wp-content\\\/uploads\\\/guillaume-bolduc-uBe2mknURG4-unsplash-scaled.jpg\",\"contentUrl\":\"https:\\\/\\\/whiteduck.de\\\/wp-content\\\/uploads\\\/guillaume-bolduc-uBe2mknURG4-unsplash-scaled.jpg\",\"width\":2560,\"height\":1852,\"caption\":\"containers photo\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/whiteduck.de\\\/en\\\/containerisierung-von-netcore-microservices\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Startseite\",\"item\":\"https:\\\/\\\/whiteduck.de\\\/en\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Containerisierung von .NET Core Microservices &#8211; Tipps &#038; Tricks\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/whiteduck.de\\\/en\\\/#website\",\"url\":\"https:\\\/\\\/whiteduck.de\\\/en\\\/\",\"name\":\"white duck\",\"description\":\"Your Partner for Microsoft Azure &amp; AI\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/whiteduck.de\\\/en\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/whiteduck.de\\\/en\\\/#\\\/schema\\\/person\\\/c26beb86db4a71e77e24854ed07eda69\",\"name\":\"Nico Meisenzahl\",\"description\":\"Nico Meisenzahl works as Senior Cloud &amp; DevOps Consultant at white duck. As an elected Microsoft MVP, Docker Community Leader and GitLab Hero, his current passion is for topics around Cloud-Native and Kubernetes. Nico is a frequent speaker at conferences, user group events and Meetups in Europe and the United States.\",\"sameAs\":[\"https:\\\/\\\/meisenzahl.org\",\"https:\\\/\\\/www.linkedin.com\\\/in\\\/nicomeisenzahl\\\/\"],\"url\":\"https:\\\/\\\/whiteduck.de\\\/en\\\/author\\\/nmeisenzahl\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Containerisierung von .NET Core Microservices - Tipps & Tricks - white duck","description":"Lesen Sie \u00fcber Best Practices f\u00fcr ein produktionsreifes Container-Image auf der Grundlage von Container- und .NET Core Anwendungen.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/whiteduck.de\/en\/containerisierung-von-netcore-microservices\/","og_locale":"en_US","og_type":"article","og_title":"Containerisierung von .NET Core Microservices - Tipps & Tricks - white duck","og_description":"Lesen Sie \u00fcber Best Practices f\u00fcr ein produktionsreifes Container-Image auf der Grundlage von Container- und .NET Core Anwendungen.","og_url":"https:\/\/whiteduck.de\/en\/containerisierung-von-netcore-microservices\/","og_site_name":"white duck","article_publisher":"https:\/\/www.facebook.com\/whiteduckgmbh","article_published_time":"2020-10-20T09:11:10+00:00","article_modified_time":"2021-09-21T13:52:51+00:00","og_image":[{"width":2560,"height":1852,"url":"https:\/\/whiteduck.de\/wp-content\/uploads\/guillaume-bolduc-uBe2mknURG4-unsplash-scaled.jpg","type":"image\/jpeg"}],"author":"Nico Meisenzahl","twitter_card":"summary_large_image","twitter_creator":"@whiteduck_gmbh","twitter_site":"@whiteduck_gmbh","twitter_misc":{"Written by":"Nico Meisenzahl","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/whiteduck.de\/en\/containerisierung-von-netcore-microservices\/#article","isPartOf":{"@id":"https:\/\/whiteduck.de\/en\/containerisierung-von-netcore-microservices\/"},"author":{"name":"Nico Meisenzahl","@id":"https:\/\/whiteduck.de\/en\/#\/schema\/person\/c26beb86db4a71e77e24854ed07eda69"},"headline":"Containerisierung von .NET Core Microservices &#8211; Tipps &#038; Tricks","datePublished":"2020-10-20T09:11:10+00:00","dateModified":"2021-09-21T13:52:51+00:00","mainEntityOfPage":{"@id":"https:\/\/whiteduck.de\/en\/containerisierung-von-netcore-microservices\/"},"wordCount":1694,"image":{"@id":"https:\/\/whiteduck.de\/en\/containerisierung-von-netcore-microservices\/#primaryimage"},"thumbnailUrl":"https:\/\/whiteduck.de\/wp-content\/uploads\/guillaume-bolduc-uBe2mknURG4-unsplash-scaled.jpg","keywords":[".NET Core",".NET Core Microservices","Azure IoT Edge","Build image","Container","Docker","GitHub","Microservices"],"articleSection":["Cloud Native"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/whiteduck.de\/en\/containerisierung-von-netcore-microservices\/","url":"https:\/\/whiteduck.de\/en\/containerisierung-von-netcore-microservices\/","name":"Containerisierung von .NET Core Microservices - Tipps & Tricks - white duck","isPartOf":{"@id":"https:\/\/whiteduck.de\/en\/#website"},"primaryImageOfPage":{"@id":"https:\/\/whiteduck.de\/en\/containerisierung-von-netcore-microservices\/#primaryimage"},"image":{"@id":"https:\/\/whiteduck.de\/en\/containerisierung-von-netcore-microservices\/#primaryimage"},"thumbnailUrl":"https:\/\/whiteduck.de\/wp-content\/uploads\/guillaume-bolduc-uBe2mknURG4-unsplash-scaled.jpg","datePublished":"2020-10-20T09:11:10+00:00","dateModified":"2021-09-21T13:52:51+00:00","author":{"@id":"https:\/\/whiteduck.de\/en\/#\/schema\/person\/c26beb86db4a71e77e24854ed07eda69"},"description":"Lesen Sie \u00fcber Best Practices f\u00fcr ein produktionsreifes Container-Image auf der Grundlage von Container- und .NET Core Anwendungen.","breadcrumb":{"@id":"https:\/\/whiteduck.de\/en\/containerisierung-von-netcore-microservices\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/whiteduck.de\/en\/containerisierung-von-netcore-microservices\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/whiteduck.de\/en\/containerisierung-von-netcore-microservices\/#primaryimage","url":"https:\/\/whiteduck.de\/wp-content\/uploads\/guillaume-bolduc-uBe2mknURG4-unsplash-scaled.jpg","contentUrl":"https:\/\/whiteduck.de\/wp-content\/uploads\/guillaume-bolduc-uBe2mknURG4-unsplash-scaled.jpg","width":2560,"height":1852,"caption":"containers photo"},{"@type":"BreadcrumbList","@id":"https:\/\/whiteduck.de\/en\/containerisierung-von-netcore-microservices\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Startseite","item":"https:\/\/whiteduck.de\/en\/"},{"@type":"ListItem","position":2,"name":"Containerisierung von .NET Core Microservices &#8211; Tipps &#038; Tricks"}]},{"@type":"WebSite","@id":"https:\/\/whiteduck.de\/en\/#website","url":"https:\/\/whiteduck.de\/en\/","name":"white duck","description":"Your Partner for Microsoft Azure &amp; AI","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/whiteduck.de\/en\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/whiteduck.de\/en\/#\/schema\/person\/c26beb86db4a71e77e24854ed07eda69","name":"Nico Meisenzahl","description":"Nico Meisenzahl works as Senior Cloud &amp; DevOps Consultant at white duck. As an elected Microsoft MVP, Docker Community Leader and GitLab Hero, his current passion is for topics around Cloud-Native and Kubernetes. Nico is a frequent speaker at conferences, user group events and Meetups in Europe and the United States.","sameAs":["https:\/\/meisenzahl.org","https:\/\/www.linkedin.com\/in\/nicomeisenzahl\/"],"url":"https:\/\/whiteduck.de\/en\/author\/nmeisenzahl\/"}]}},"_links":{"self":[{"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/posts\/7710","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/users\/8"}],"replies":[{"embeddable":true,"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/comments?post=7710"}],"version-history":[{"count":0,"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/posts\/7710\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/media\/7713"}],"wp:attachment":[{"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/media?parent=7710"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/categories?post=7710"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/whiteduck.de\/en\/wp-json\/wp\/v2\/tags?post=7710"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}