S

super-dev — full-stack

@super-dev.app · Full-stack · ★ offen für Aufträge
12,8k Abonnenten·47 Videos·Aktiv seit 2017

Full-Stack-Entwickler .NET / Angular mit DevOps-Erfahrung auf Azure Cloud. Auch zu Hause mit Flutter + Firebase. Ich entwickle Produkte, deploye sie und überwache sie.

Zurück zu den Artikeln
DEVOPS
DEVOPS

Multi-Stage Docker-Images für .NET + Angular

Artikel 5 von 6 — Azure DevOps von Grund auf
Prerender, Container Apps, Secrets, CI/CD, Docker, Observability: auf Azure deployen, ohne Server und ohne Schmerzen.

Das .NET-SDK und node_modules in das Image zu packen, das man in Produktion deployt, bedeutet, 800 MB an Werkzeugen auszuliefern, die zur Laufzeit niemals gebraucht werden. Der Multi-Stage-Build trennt, was kompiliert, von dem, was läuft: Man erhält ein winziges finales Image, das nur das enthält, was die Runtime unbedingt benötigt.

Das Prinzip: kompilieren, dann verwerfen

Ein Multi-Stage- Dockerfile deklariert mehrere FROM -Anweisungen. Jedes FROM öffnet einen isolierten Stage; nur der letzte Stage wird zum ausgelieferten Image. Die Artefakte werden selektiv vom Build-Stage in den Runtime-Stage kopiert — alles andere, SDK, Quellcode, Caches, wird verworfen.

Bash
1# Stage 1 : build de l'API .NET
2FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
3WORKDIR /src
4COPY *.csproj ./
5RUN dotnet restore
6COPY . ./
7RUN dotnet publish -c Release -o /app/publish
8
9# Stage 2 : runtime seul (pas de SDK)
10FROM mcr.microsoft.com/dotnet/aspnet:9.0-noble-chiseled AS final
11WORKDIR /app
12COPY --from=build /app/publish ./
13ENV ASPNETCORE_URLS=http://+:8080
14EXPOSE 8080
15ENTRYPOINT ["dotnet", "Api.dll"]

Layer-Cache: Reihenfolge, um nicht alles neu zu bauen

Docker legt jede Anweisung im Cache ab und invalidiert ihn, sobald eine vorgelagerte Schicht sich ändert. Daher die goldene Regel: Abhängigkeitsdateien vor dem Quellcode kopieren . Mit COPY *.csproj gefolgt von dotnet restore bevor der Rest kopiert wird, wird das restore nur bei einer Änderung der .csproj -Datei erneut ausgeführt — nicht bei jeder Änderung einer C#-Datei. Gleiche Logik auf Angular-Seite mit package.json und npm ci vor dem COPY der Quellen: Eine Codeänderung invalidiert niemals die Dependency-Installation, was die Build-Zeiten um das Zehnfache reduziert.

Ein winziges finales Image

Die Wahl des Runtime-Basis-Images macht den entscheidenden Unterschied. Die chiseled -Images von Microsoft ( aspnet:9.0-noble-chiseled ) entfernen Shell, Paketmanager und überflüssige Binärdateien: reduzierte Angriffsfläche, Images oft unter 110 MB, Ausführung standardmäßig als Non-Root-Benutzer. Für den Angular-Frontend-Service übernimmt nginx alpine die Rolle des finalen Stage.

Bash
1# Build Angular puis service par nginx
2FROM node:22-alpine AS web
3WORKDIR /app
4COPY package*.json ./
5RUN npm ci
6COPY . ./
7RUN npm run build
8
9FROM nginx:1.27-alpine AS final
10COPY --from=web /app/dist/browser /usr/share/nginx/html
11COPY nginx.conf /etc/nginx/conf.d/default.conf

Der Angular-Build erzeugt ausschließlich statische Dateien: Kein Node-Runtime wird in der Produktion benötigt. Der dist/browser -Ordner wird in das nginx-Root kopiert, und ein try_files $uri /index.html in der Konfiguration sorgt für den SPA-Fallback .

Lokal mit Compose orchestrieren

Um API und Frontend gemeinsam während der Entwicklung zu betreiben, verbindet eine docker-compose.yml beide Services und ihr Netzwerk:

YAML
1services:
2 api:
3 build: ./api
4 ports:
5 - "8080:8080"
6 web:
7 build: ./web
8 ports:
9 - "4200:80"
10 depends_on:
11 - api

Die Dokumentation zu Multi-Stage-Builds beschreibt zielgerichtete Builds ( --target build ) und das Teilen von Stages — nützlich, um einen Testschritt in der CI-Pipeline zu isolieren.

Ein Produktions-Image sollte nur enthalten, was auch ausgeführt wird. Multi-Stage macht diese Disziplin kostenlos: Das SDK bleibt im Build-Stage, niemals in dem, was Sie deployen .
super-dev — portfolio.app
// Weiter in DEVOPS
>_
Eine CI/CD-Pipeline GitHub Actions → Azure, von Grund auf
8 min • 1,9k Aufrufe
Observability in .NET mit OpenTelemetry
8 min • 1,6k Aufrufe