Docker
Kurz: Eine Plattform zum Verpacken von Anwendungen in isolierte, portable Container.
Genauer: Ein Container bündelt eine Anwendung mit allen Abhängigkeiten (Bibliotheken, Laufzeitumgebung) in einem Paket, das auf jedem System mit Docker identisch läuft — löst das “bei mir läuft’s aber”-Problem. Anders als eine virtuelle Maschine teilen sich Container den Kernel des Host-Betriebssystems, was sie deutlich leichtgewichtiger macht.
Im Detail
Entstehung
Docker erschien 2013 und traf einen Nerv: Vorher gab es zwar schon Container-Technologie im Linux-Kernel (LXC, cgroups, Namespaces existierten teils seit 2007), aber keine einheitliche, einfach zu bedienende Werkzeugkette darum herum. Docker machte aus einer Nischentechnologie für Kernel-Experten ein Werkzeug, das jeder Entwickler mit wenigen Befehlen nutzen konnte, und definierte mit dem Dockerfile- und Image-Format einen De-facto-Standard, den heute auch konkurrierende Laufzeitumgebungen wie Podman oder containerd unterstützen.
Dockerfile, Image, Container
FROM node:20-alpine
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --production
COPY . .
EXPOSE 3000
CMD ["npm", "start"]Ein Dockerfile beschreibt deklarativ und Schicht für Schicht (“Layer”), wie ein Image aufgebaut wird — jede Zeile erzeugt eine eigene, cachebare Schicht. Das erklärt auch die übliche Reihenfolge im Beispiel: package.json wird VOR dem restlichen Code kopiert, damit npm ci nur dann erneut läuft (und damit den Build verlangsamt), wenn sich tatsächlich Abhängigkeiten geändert haben — ändert sich nur der Anwendungscode, kann Docker die teure Install-Schicht aus dem Cache wiederverwenden. docker build erzeugt aus dem Dockerfile ein Image (ein unveränderliches, versioniertes Abbild aller Schichten), docker run startet daraus einen oder mehrere laufende Container.
Warum Container leichtgewichtiger sind als VMs
Eine virtuelle Maschine emuliert komplette Hardware inklusive eigenem Betriebssystem-Kernel — jede VM bringt ihr eigenes vollständiges OS mit, was mehrere Gigabyte und spürbaren Boot-Aufwand kostet. Ein Container teilt sich dagegen den Kernel des Host-Systems und isoliert nur Prozesse, Dateisystem und Netzwerk auf Betriebssystemebene über Linux-Kernel-Features: Namespaces (jeder Container sieht nur seine eigenen Prozesse/Netzwerkschnittstellen/Dateisysteme) und cgroups (begrenzen, wie viel CPU/RAM ein Container verbrauchen darf). Dadurch starten Container in Sekundenbruchteilen statt Minuten, brauchen oft nur Megabyte statt Gigabyte und lassen sich zu Dutzenden auf einer einzigen Maschine betreiben.
Mehrere Container: docker-compose und Orchestrierung
# docker-compose.yml
services:
app:
build: .
ports: ["3000:3000"]
depends_on: [db]
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: geheimIn der Praxis läuft selten nur ein einzelner Container: docker-compose startet mehrere zusammengehörige Container (Anwendung, Datenbank, Cache, Reverse Proxy) mit einer einzigen Konfigurationsdatei und richtet automatisch ein gemeinsames Netzwerk zwischen ihnen ein, sodass sie sich über ihre Service-Namen erreichen können (db statt einer IP-Adresse). Für den produktiven Betrieb vieler Container über mehrere physische Maschinen hinweg (automatisches Neustarten ausgefallener Container, Lastverteilung, Skalierung) übernimmt meist Kubernetes die Orchestrierung — deutlich komplexer als Compose, aber für große, hochverfügbare Systeme der Industriestandard.
Images teilen: Registries
Ein gebautes Image lässt sich in eine Registry hochladen (docker push), meist Docker Hub oder ein privater Anbieter — von dort kann jede andere Maschine es herunterladen (docker pull) und identisch starten. Das ist der Kern des “bei mir läuft’s aber”-Problems, das Docker löst: Statt Code auf verschiedene Umgebungen zu verteilen und zu hoffen, dass sie identisch konfiguriert sind, verteilt man ein fertiges, in sich geschlossenes Image, das überall exakt gleich läuft.
Siehe auch: Paket, Linux, CI/CD-Pipeline