DevOps & Cloud

Docker Container Leitfaden: Dockerfile, Compose & Multi-Stage Builds

12 Min. Lesezeit15. März 2026
Docker rehberiDocker tutorialDockerfileDocker ComposeMulti-stage buildDocker konteynerKonteynerleştirmeDocker deploymentDocker .NETDocker production

Docker beseitigt Inkonsistenzen zwischen Entwicklungs-, Test- und Produktionsumgebungen, indem Anwendungen in isolierten Containern verpackt werden. Mit Dockerfile definieren Sie Anwendungsimages, Docker Compose orchestriert mehrere Dienste und Multi-Stage Builds erzeugen produktionsreife, optimierte Images.

Dockerfile: Grundlagen der Image-Erstellung

Ein Dockerfile ist eine Anweisungsdatei, die definiert, wie ein Docker-Image erstellt wird. Jeder Befehl erzeugt eine Schicht, und Docker speichert diese Schichten im Cache.

dockerfile
# Optimiertes Dockerfile fuer .NET 8 API
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 8080

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src

# Projektdateien zuerst kopieren (Cache-Optimierung)
COPY ["src/MyApi/MyApi.csproj", "src/MyApi/"]
COPY ["src/MyApi.Domain/MyApi.Domain.csproj", "src/MyApi.Domain/"]
COPY ["src/MyApi.Infrastructure/MyApi.Infrastructure.csproj", "src/MyApi.Infrastructure/"]
RUN dotnet restore "src/MyApi/MyApi.csproj"

# Quellcode kopieren und bauen
COPY . .
WORKDIR "/src/src/MyApi"
RUN dotnet build "MyApi.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "MyApi.csproj" -c Release -o /app/publish \
    --no-restore \
    -p:PublishTrimmed=false \
    -p:PublishReadyToRun=true

# Finale Phase - nur Runtime
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
USER $APP_UID
ENTRYPOINT ["dotnet", "MyApi.dll"]

Vorteile von Multi-Stage Builds

  • Build-Phase: Enthaelt SDK und alle Entwicklungstools (~800MB)
  • Finale Phase: Nur Runtime und kompilierte Anwendung (~200MB)
  • Sicherheit: Build-Tools sind im Produktionsimage nicht vorhanden

.dockerignore: Unnoetige Dateien ausschliessen

Die .dockerignore-Datei definiert Dateien, die nicht in den Docker-Build-Kontext aufgenommen werden sollen. Eine korrekt konfigurierte .dockerignore verkuerzt sowohl die Build-Zeit als auch verhindert das Einfliessen sensibler Daten in das Image.

dockerignore
# .dockerignore
**/bin
**/obj
**/node_modules
**/.git
**/.env
**/.env.*
**/Dockerfile*
*.md
.vs
.vscode
**/.DS_Store
**/coverage
**/*.log

Ohne .dockerignore-Datei nimmt Docker alle Projektdateien in den Build-Kontext auf. Grosse Verzeichnisse wie .git und node_modules verlaengern die Build-Zeit unnoetig. Das Ausschliessen von .env-Dateien ist aus Sicherheitsgruenden in Produktionsumgebungen besonders wichtig.

Docker Compose: Multi-Service-Verwaltung

Docker Compose ermoeglicht die Definition und Verwaltung mehrerer Dienste mit einer einzigen YAML-Datei.

yaml
version: '3.8'

services:
  api:
    build:
      context: .
      dockerfile: src/MyApi/Dockerfile
    ports:
      - "5000:8080"
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ConnectionStrings__DefaultConnection=Host=postgres;Database=myapp;Username=postgres;Password=postgres
    depends_on:
      postgres:
        condition: service_healthy
    networks:
      - app-network

  postgres:
    image: postgres:16-alpine
    ports:
      - "5432:5432"
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
    volumes:
      - postgres-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5
    networks:
      - app-network

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    command: redis-server --appendonly yes --maxmemory 256mb
    networks:
      - app-network

volumes:
  postgres-data:

networks:
  app-network:
    driver: bridge

Best Practices

Image-Groessenoptimierung

  • Alpine-basierte Images verwenden (z.B. node:20-alpine)
  • .dockerignore zum Ausschliessen unnuetiger Dateien nutzen
  • Schichtreihenfolge: Haeufig aendernde Dateien ans Ende des Dockerfiles setzen

Sicherheitspraktiken

  • Nicht-Root-Benutzer: Container niemals als Root ausfuehren
  • Spezifische Tags: Statt latest immer spezifische Versions-Tags verwenden
  • Image-Scanning: Sicherheitsluecken mit Trivy oder Snyk scannen

Sicherheitsscanning mit Trivy

Das Scannen von Docker-Images vor dem Produktionseinsatz ist ein kritischer Schritt:

bash
# Image mit Trivy scannen
trivy image myapi:latest

# Nur CRITICAL und HIGH Schweregrade anzeigen
trivy image --severity CRITICAL,HIGH myapi:latest

# In der CI/CD-Pipeline - Build bei Schwachstellen abbrechen
trivy image --exit-code 1 --severity CRITICAL myapi:latest

Gesundheitspruefungen

dockerfile
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
  CMD curl -f http://localhost:8080/health || exit 1

Health Checks ermoeglichen Docker die Ueberwachung der Container-Gesundheit. In Kombination mit depends_on in Docker Compose werden Startprobleme vermieden, indem auf die Bereitschaft abhaengiger Dienste gewartet wird.

Docker-Netzwerkverwaltung

Docker-Netzwerke verwalten die Kommunikation zwischen Containern:

  • Bridge: Standardmodus, isolierte Kommunikation auf demselben Host
  • Host: Container nutzt das Host-Netzwerk direkt
  • Overlay: Kommunikation zwischen mehreren Hosts im Swarm-Modus
bash
# Benutzerdefiniertes Bridge-Netzwerk erstellen
docker network create --driver bridge --subnet 172.20.0.0/16 app-network

# Container mit Netzwerk verbinden
docker run -d --name api --network app-network myapi:latest

# Konnektivitaet testen
docker exec api ping -c 3 postgres

Benutzerdefinierte Bridge-Netzwerke unterstuetzen im Gegensatz zur Standard-Bridge automatisch DNS-basierte Diensterkennung, sodass Container sich gegenseitig ueber Namen statt IP-Adressen erreichen koennen.

Docker-Volume-Verwaltung

Volumes garantieren Datenpersistenz ueber den Container-Lebenszyklus hinaus:

bash
# Named Volume erstellen
docker volume create postgres-data

# Container mit Volume starten
docker run -d --name db \
  -v postgres-data:/var/lib/postgresql/data \
  postgres:16-alpine

# Volume-Backup
docker run --rm -v postgres-data:/source -v $(pwd):/backup \
  alpine tar czf /backup/postgres-backup.tar.gz -C /source .

In Entwicklungsumgebungen werden Bind-Mounts fuer die Quellcode-Freigabe verwendet, waehrend in der Produktion Named Volumes bevorzugt werden.

Praktische Tipps

  1. Dev/Prod-Paritaet: Separate Compose-Dateien fuer Entwicklung und Produktion
  2. Log-Verwaltung: Container-Logs nach stdout/stderr schreiben
  3. Ressourcenlimits: Container-Ressourcen mit --memory und --cpus begrenzen
  4. CI/CD-Integration: Docker-Images in der CI-Pipeline bauen und in eine Registry pushen
  5. Layer-Caching: BuildKit-Cache in CI verwenden, um Build-Zeiten zu verkuerzen

Docker ist ein unverzichtbarer Bestandteil des modernen Softwareentwicklungsprozesses. Korrekt konfigurierte Dockerfile- und Compose-Dateien erhoehen sowohl Ihre Entwicklungsgeschwindigkeit als auch die Zuverlaessigkeit Ihrer Deployments.

Verwandte Artikel

Haben Sie ein Flutter-Projekt?

Ich entwickle hochleistungsfähige Flutter-Anwendungen für iOS, Android und Web.

Kontakt aufnehmen