Skip to content

Docker-Containerisierung

Vorwort

"Es laeuft auf meinem Rechner" ist die klassische Ausrede von Entwicklern - Docker laesst diese Ausrede verschwinden. Containerisierungstechnologie verpackt eine Anwendung mit all ihren Abhaengigkeiten in eine standardisierte Einheit, die konsistent in jeder Umgebung laeuft. Sie ist das Fundament der modernen Softwarebereitstellung.

Was wirst du in diesem Artikel lernen?

Nach diesem Kapitel wirst du Folgendes koennen:

  • Kernkonzepte: Die drei Kernkonzepte Image, Container und Registry verstehen
  • Architektur-Vergleich: Den wesentlichen Unterschied zwischen Containern und virtuellen Maschinen begreifen
  • Praktische Faehigkeiten: Dockerfile-Erstellung und haeufige Befehle beherrschen
  • Orchestrierungs-Grundlagen: Multi-Service-Anwendungen mit Docker Compose verwalten
  • Best Practices: Image-Optimierung, Sicherheitsverstaerkung und produktionsreife Praktiken kennenlernen
KapitelInhaltKernkonzepte
Kapitel 1Warum Container?Umgebungskonsistenz, Ressourceneffizienz, standardisierte Bereitstellung
Kapitel 2KernkonzepteImage, Container, Registry, Dockerfile
Kapitel 3Docker-LebenszyklusSchreiben, Bauen, Pushen, Ausfuehren, Verwalten
Kapitel 4Docker ComposeMulti-Service-Orchestrierung, Netzwerk, Volumes
Kapitel 5Best PracticesImage-Optimierung, Sicherheit, Multi-Stage-Build

1. Warum Container?

Vor der Containerisierung musste man zum Bereitstellen einer Anwendung auf dem Server manuell die Laufzeitumgebung installieren, Umgebungsvariablen konfigurieren und Abhaengigkeitskonflikte loesen. Unterschiede zwischen Umgebungen (Entwicklung, Test, Produktion) waren eine Brutstaette fuer Bugs.

Virtual Machines vs Containers
Switch between both virtualization models to compare their architecture
App A / App B / App C
App A + Bins/Libs
App B + Bins/Libs
App C + Bins/Libs
Docker Engine
Host OS
Physical hardware
Startup speedSeconds
Resource usageShared host OS kernel (MB scale)
IsolationProcess-level isolation
DensityHundreds of containers per host
Image sizeMB scale

Welche Probleme loesen Container?

ProblemTraditioneller AnsatzContainer-Ansatz
Inkonsistente Umgebungen"Bei mir laeufts"Alle Abhaengigkeiten verpacken, ueberall konsistent
AbhaengigkeitskonflikteApp A braucht Node 14, App B braucht Node 18Jeder Container hat eine isolierte Umgebung
RessourcenverschwendungJede VM ein komplettes BetriebssystemKernel geteilt, MB-grosser Overhead
Langsames DeploymentManuelle Installation und Konfigurationdocker run - ein Befehl genuegt
Schwierige SkalierungNeue VM, Umgebung einrichten, deployenNeuen Container in Sekunden starten

Die Essenz von Containern

Container sind keine leichtgewichtigen virtuellen Maschinen. Ihre Essenz sind isolierte Prozesse. Der Linux-Kernel realisiert Containerisierung durch zwei Mechanismen:

  • Namespaces: Isolieren die Sichtweise von Prozessen (PID, Netzwerk, Dateisystem etc.)
  • Cgroups: Beschraenken die Ressourcennutzung von Prozessen (CPU, Speicher, I/O)

Prozesse in einem Container unterscheiden sich nicht wesentlich von gewoehnlichen Prozessen auf dem Host - sie sind nur in einen "Raum eingesperrt, von dem aus man nichts draussen sehen kann".


2. Kernkonzepte

Die Docker-Welt dreht sich um drei Kernkonzepte: Image, Container und Registry.

KonzeptAnalogieBeschreibung
Image (Image)Klasse / VorlageSchreibgeschuetzte Anwendungsvorlage mit Code, Laufzeit, Bibliotheken, Konfiguration
Container (Container)Instanz / ObjektLaufende Instanz eines Images, les- und schreibbar, eigenstaendiger Lebenszyklus
Registry (Registry)App StoreDienst zum Speichern und Verteilen von Images (Docker Hub, ACR, ECR)
DockerfileRezept / BauplanTextdatei, die definiert, wie ein Image erstellt wird
Volume (Volume)Externe FestplattePersistente Daten, die beim Loeschen des Containers nicht verloren gehen

Der mehrschichtige Aufbau von Images

Docker-Images bestehen aus mehreren schreibgeschuetzten Schichten (Layers). Jede Dockerfile-Anweisung erstellt eine Schicht:

┌─────────────────────────┐
│  CMD ["node", "app.js"] │  <- Startbefehl-Schicht
├─────────────────────────┤
│  COPY . /app            │  <- Anwendungscode-Schicht (haeufige Aenderungen)
├─────────────────────────┤
│  RUN npm install        │  <- Abhaengigkeits-Schicht (gelegentliche Aenderungen)
├─────────────────────────┤
│  FROM node:18-alpine    │  <- Basis-Image-Schicht (selten Aenderungen)
└─────────────────────────┘

Warum ist die Schichtung wichtig?

Docker cacht jede Schicht. Wenn sich eine Schicht nicht geaendert hat, wird der Cache beim Bauen direkt wiederverwendet. Daher sollte im Dockerfile wenig haeufig geaenderte Anweisungen weiter oben stehen (wie Abhaengigkeits-Installation) und haeufig geaenderte weiter unten (wie Code kopieren). So koennen die meisten Builds den Cache nutzen und sind deutlich schneller.


3. Docker-Lebenszyklus

Von der Dockerfile-Erstellung bis zum laufenden Container ist der Docker-Workflow eine klar strukturierte Pipeline.

Docker Lifecycle
Click each stage to inspect the details
📝
Write a Dockerfile
🔨
Build the image
☁️
Push to registry
▶️
Run the container
⚙️
Manage containers
Write a Dockerfile
A Dockerfile is the recipe for building an image. It starts from a base image and defines how to assemble the application environment step by step. Each instruction creates an image layer that Docker can cache for later builds.
Common commands
FROM node:18-alpineChoose the base image
WORKDIR /appSet the working directory
COPY package*.json ./Copy dependency files for cache reuse
RUN npm installInstall dependencies
COPY . .Copy application code
EXPOSE 3000Declare the port
CMD ["node", "server.js"]Start command

Dockerfile-Befehlsreferenz

BefehlFunktionBeispiel
FROMBasis-Image festlegenFROM node:18-alpine
WORKDIRArbeitsverzeichnis setzenWORKDIR /app
COPYDateien ins Image kopierenCOPY package.json ./
RUNBefehl beim Bauen ausfuehrenRUN npm install
ENVUmgebungsvariable setzenENV NODE_ENV=production
EXPOSEPort erklaeren (nur Dokumentation)EXPOSE 3000
CMDContainer-StartbefehlCMD ["node", "app.js"]
ENTRYPOINTContainer-Einstiegspunkt (schwer zu ueberschreiben)ENTRYPOINT ["nginx"]

4. Docker Compose: Multi-Service-Orchestrierung

Echte Projekte bestehen selten aus nur einem Container. Eine Webanwendung benoetigt moeglicherweise: Anwendungsserver + Datenbank + Redis + Nginx. Docker Compose definiert und verwaltet mehrere Container ueber eine einzige YAML-Datei.

docker-compose.yml Beispiel

yaml
version: '3.8'
services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - DB_HOST=db
      - REDIS_HOST=redis
    depends_on:
      - db
      - redis

  db:
    image: postgres:15-alpine
    volumes:
      - db-data:/var/lib/postgresql/data
    environment:
      - POSTGRES_PASSWORD=secret

  redis:
    image: redis:7-alpine

volumes:
  db-data:

Kernkonzepte von Compose

KonzeptBeschreibungBeispiel
servicesDefiniert die einzelnen Container-Diensteapp, db, redis
volumesPersistente Datenvolumesdb-data fuer Datenbankdateien
networksBenutzerdefiniertes Netzwerk (automatisch erstellt)Services kommunizieren ueber Servicenamen
depends_onStartreihenfolge-Abhaengigkeitenapp haengt von db und redis ab
environmentUmgebungsvariablenDatenbankpasswort, Verbindungsadresse

Service Discovery

In Docker Compose ist der Servicename gleichzeitig der Hostname. Der app-Container kann die Datenbank direkt ueber db:5432 und Redis ueber redis:6379 ansprechen, ohne die IP-Adresse zu kennen. Das ist dem integrierten DNS von Docker zu verdanken.


5. Best Practices

5.1 Multi-Stage-Build (Mehrstufiger Build)

Der Multi-Stage-Build ist ein leistungsstarkes Werkzeug zur Optimierung der Image-Groesse. In der Build-Phase werden alle Werkzeuge und Abhaengigkeiten installiert, im finalen Stage werden nur die fuer die Laufzeit benoetigten Dateien beibehalten.

dockerfile
# Build-Phase
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Laufzeit-Phase
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/server.js"]

5.2 Image-Optimierungs-Checkliste

OptimierungVorgehenEffekt
Kleines Basis-Image waehlenalpine statt ubuntuImage von ~200 MB auf ~50 MB reduziert
RUN-Befehle zusammenfassenMehrere Befehle mit && verbindenWeniger Image-Schichten
.dockerignore verwendennode_modules, .git etc. ausschliessenSchnelleres Bauen, kleinerer Kontext
Multi-Stage-BuildBuild- und Laufzeitumgebung trennenKeine Build-Tools im finalen Image
Versionsnummern fixierennode:18.17-alpine statt node:latestReproduzierbare Builds

5.3 Sicherheitsmassnahmen

MassnahmeBeschreibung
Nicht als Root ausfuehrenUSER node fuer nicht-Root-Benutzer
Schwachstellen scannendocker scout oder Trivy zum Image-Scanning
Minimale BerechtigungenNur notwendige Pakete installieren, keine Debug-Tools
Keine hartcodierten SecretsUmgebungsvariablen oder Docker Secrets verwenden
Basis-Images regelmaessig aktualisierenSicherheitsluecken zeitnah schliessen

Zusammenfassung

Docker-Containerisierung ist die Infrastruktur der modernen Softwarebereitstellung - sie zu verstehen ist fuer jeden Entwickler unerlaesslich.

Die wichtigsten Punkte dieses Kapitels:

  1. Container vs. VM: Container teilen sich den Host-Kernel, sind leichter und schneller, aber die Isolierung ist etwas schwaecher als bei VMs
  2. Die drei Kernkomponenten: Image (Vorlage), Container (Instanz), Registry (Verteilung)
  3. Dockerfile: Schichtweiser Aufbau, Cache nutzen, seltener geaenderte Anweisungen nach oben
  4. Docker Compose: Multi-Service-Anwendung per YAML definieren, Servicename als Hostname
  5. Produktionspraktiken: Multi-Stage-Build fuer kleinere Images, Alpine-Basis-Image, nicht als Root ausfuehren

Weiterfuehrende Literatur