Der Satz "Auf meiner Maschine läuft es" war gestern eine Ausrede. Docker hat ihn zur Garantie gemacht. Indem Ihre Anwendung zusammen mit ihrer gesamten Laufzeitumgebung – Betriebssystembibliotheken, Sprachlaufzeit, Abhängigkeiten, Konfigurationsdateien – verpackt wird, stellt Docker sicher, dass die Anwendung identisch auf Ihrem Laptop, dem Rechner Ihres Kollegen, einem CI-Server und in der Produktion läuft.

Container vs. Virtuelle Maschinen

Virtuelle Maschinen führen ein vollständiges Betriebssystem auf einem Hypervisor aus. Jede VM hat ihren eigenen Kernel, ihr eigenes Dateisystem und ihren eigenen Speicherbereich. Eine einzelne VM kann schon über 2 GB RAM verbrauchen, bevor Ihre Anwendung überhaupt gestartet ist.

Container teilen sich den Kernel des Host-Betriebssystems. Sie isolieren das Dateisystem, das Netzwerk und die Prozesse der Anwendung mithilfe von Linux-Namespaces und cgroups – jedoch ohne den Overhead eines vollständigen Betriebssystems. Ein Container startet typischerweise in unter einer Sekunde und verbraucht Megabyte statt Gigabyte.

Kernkonzepte

  • Image: Eine schreibgeschützte Vorlage, die den Anwendungscode, die Laufzeitumgebung, Bibliotheken und Abhängigkeiten enthält. Stellen Sie es sich wie einen Schnappschuss vor.
  • Container: Eine laufende Instanz eines Images. Sie können Container starten, stoppen und löschen, ohne das zugrunde liegende Image zu beeinträchtigen.
  • Dockerfile: Eine Textdatei mit schrittweisen Anweisungen zum Erstellen eines Images.
  • Registry: Ein Repository zum Speichern und Verteilen von Images. Docker Hub ist die standardmäßige öffentliche Registry.

Ein Dockerfile schreiben

Node.js Dockerfile
# Verwende das offizielle Node.js LTS als Basis-Image
FROM node:20-alpine

# Arbeitsverzeichnis im Container festlegen
WORKDIR /app

# Abhängigkeitsmanifeste zuerst kopieren (für Layer-Caching)
COPY package*.json ./

# Abhängigkeiten installieren
RUN npm ci --only=production

# Anwendungscode kopieren
COPY . .

# Den Port der Anwendung freigeben
EXPOSE 3000

# Den Befehl zum Starten der App definieren
CMD ["node", "server.js"]

Wichtige Docker-Befehle

Am häufigsten verwendete Befehle
# Ein Image aus einem Dockerfile bauen
docker build -t mein-app:1.0 .

# Einen Container aus einem Image ausführen
docker run -d -p 3000:3000 --name mein-app mein-app:1.0

# Laufende Container auflisten
docker ps

# Container-Logs anzeigen
docker logs mein-app

# Einen Container stoppen und entfernen
docker stop mein-app && docker rm mein-app

# Lokale Images auflisten
docker images

# Ein Image entfernen
docker rmi mein-app:1.0

Docker Compose für Multi-Service-Anwendungen

Die meisten Webanwendungen benötigen mehr als einen Dienst – einen Anwendungsserver, eine Datenbank, vielleicht einen Cache oder eine Message Queue. Docker Compose ermöglicht es Ihnen, all diese Dienste mit einer einzigen YAML-Datei zu definieren und gemeinsam auszuführen.

docker-compose.yml
version: "3.9"
services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgres://user:pass@db:5432/mydb
    depends_on:
      - db
      - redis

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: mydb
    volumes:
      - pgdata:/var/lib/postgresql/data

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

volumes:
  pgdata:
Docker Compose Befehle
# Alle Dienste starten (im Hintergrund)
docker compose up -d

# Logs aller Dienste anzeigen
docker compose logs -f

# Alle Container stoppen und entfernen
docker compose down

# Images nach Code-Änderungen neu bauen
docker compose up --build -d

Best Practices für die Produktion

  • Verwenden Sie Multi-Stage-Builds, um die finalen Images klein zu halten. Bauen Sie in einem Schritt und kopieren Sie nur das Ergebnis in eine minimale Laufzeitstufe.
  • Verwenden Sie .dockerignore, um node_modules, .git und andere unnötige Dateien aus dem Build-Kontext auszuschließen.
  • Fixieren Sie Basis-Image-Versionen – verwenden Sie node:20.11-alpine anstelle von node:latest für reproduzierbare Builds.
  • Führen Sie Container als Nicht-Root-Benutzer aus, um die Sicherheit zu erhöhen.
  • Nutzen Sie Layer-Caching – kopieren Sie package.json und führen Sie npm install aus, bevor Sie den Quellcode kopieren, damit die Abhängigkeiten gecacht werden.
  • Verwenden Sie Health Checks, damit Orchestratoren (Docker Swarm, Kubernetes) wissen, wann Ihre Anwendung bereit ist.

Probieren Sie unsere kostenlosen Entwicklertools

Minifizieren, verschönern und formatieren Sie Ihren Code sofort in Ihrem Browser.