Docker für Entwickler: Images, Container und Compose
Du hast Code geschrieben, der auf deinem Rechner funktioniert, aber wenn ein Teammitglied versucht, ihn auszuführen, stößt er auf fehlende Abhängigkeiten, Versionskonflikte oder obskure Fehler. Docker löst dies, indem es deine Anwendung und ihre Umgebung in eine einzige, portable Einheit packt. In dieser Anleitung lernst du die Docker-Grundlagen: Images, Container und Compose, mit praktischen Schritten, um eine einfache Web-App zu containerisieren.
Was ist Docker?
Docker ist eine Plattform zum Erstellen, Ausführen und Teilen von Anwendungen in Containern. Ein Container ist ein leichtgewichtiges, eigenständiges ausführbares Paket, das alles enthält, was zum Ausführen von Software benötigt wird: Code, Laufzeitumgebung, Systemtools, Bibliotheken und Einstellungen. Container isolieren Anwendungen voneinander und vom Host-System und gewährleisten so Konsistenz über Entwicklung, Test und Produktion hinweg.
Images vs. Container: Die Blaupause und die laufende Instanz
Ein Image ist eine schreibgeschützte Vorlage, die einen Container definiert. Es ist wie eine Klasse in der objektorientierten Programmierung. Ein Container ist eine ausführbare Instanz eines Images, wie ein Objekt. Du kannst viele Container aus demselben Image erstellen.
Images werden aus einem Dockerfile erstellt, einer Textdatei mit Anweisungen. Container werden mit docker run gestartet.
Hauptunterschiede
| Image | Container |
|---|---|
| Schreibgeschützte Vorlage | Ausführbare Instanz |
Erstellt mit docker build | Gestartet mit docker run |
| In Registry gespeichert (z.B. Docker Hub) | Läuft auf dem Host |
| Geschichtetes Dateisystem | Beschreibbare Schicht obenauf |
Dein erstes Image erstellen
Lass uns eine einfache Node.js-App containerisieren. Erstelle eine Datei namens Dockerfile:
# Use an official Node.js runtime as a parent image
FROM node:18-alpine
# Set the working directory
WORKDIR /app
# Copy package.json and install dependencies
COPY package*.json ./
RUN npm install
# Copy the rest of the application
COPY . .
# Expose the port the app runs on
EXPOSE 3000
# Define the command to run the app
CMD ["node", "server.js"]
Erstelle das Image mit einem Tag:
docker build -t my-node-app .
Das -t-Flag benennt und taggt das Image. Der . am Ende gibt den Build-Kontext an (aktuelles Verzeichnis).
Container ausführen
Starte einen Container aus deinem Image:
docker run -p 3000:3000 -d --name my-app my-node-app
-p 3000:3000: Mappt Port 3000 auf dem Host auf Port 3000 im Container.-d: Führt den Container im Detached-Modus aus (im Hintergrund).--name my-app: Weist dem Container einen Namen zur einfachen Referenz zu.
Überprüfe laufende Container mit docker ps. Stoppe den Container mit docker stop my-app.
Daten mit Volumes verwalten
Container sind ephemer; Daten darin gehen verloren, wenn der Container entfernt wird. Um Daten zu persistieren, verwende Volumes. Zum Beispiel, um Datenbankdaten zu persistieren:
docker run -v my-db-data:/var/lib/mysql -d mysql:8
Dies erstellt ein benanntes Volume my-db-data, das Container-Neustarts und -Entfernungen überlebt.
Multi-Container-Apps mit Docker Compose vereinfachen
Echte Anwendungen benötigen oft mehrere Dienste: einen Webserver, eine Datenbank, einen Cache usw. Docker Compose ermöglicht es dir, Multi-Container-Apps mit einer einzigen YAML-Datei zu definieren und auszuführen.
Erstelle eine docker-compose.yml:
version: '3.8'
services:
web:
build: .
ports:
- "3000:3000"
depends_on:
- db
environment:
- DATABASE_URL=postgres://user:pass@db:5432/mydb
db:
image: postgres:15
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=pass
- POSTGRES_DB=mydb
volumes:
postgres_data:
Führe alles aus mit:
docker compose up -d
Compose erstellt das Web-Image, startet die Datenbank und verbindet sie in einem gemeinsamen Netzwerk. Das depends_on stellt sicher, dass die Datenbank vor dem Web-Service startet.
Wichtige Docker-Befehle
docker ps -a: Listet alle Container auf (einschließlich gestoppter).docker images: Listet Images auf.docker logs my-app: Zeigt Container-Logs an.docker exec -it my-app sh: Öffnet eine Shell in einem laufenden Container.docker compose down: Stoppt und entfernt Container, Netzwerke und Volumes, die in der Compose-Datei definiert sind.
Best Practices für die Entwicklung
- Verwende .dockerignore, um Dateien (z.B. node_modules) vom Build-Kontext auszuschließen, was Builds beschleunigt.
- Nutze Multi-Stage-Builds, um Produktions-Images klein zu halten. Zum Beispiel: Baue deine App in einer Stage und kopiere nur die notwendigen Artefakte in ein schlankes Runtime-Image.
- Pinne Versionen in deinem Dockerfile (z.B.
node:18-alpinestattnode:latest) für Reproduzierbarkeit. - Führe als Non-Root-Benutzer aus aus Sicherheitsgründen. Füge
USER nodenach dem Kopieren der Dateien hinzu.
FAQ
Was ist der Unterschied zwischen einem Docker-Image und einem Container?
Ein Image ist eine schreibgeschützte Vorlage, die die Anwendung und ihre Umgebung definiert. Ein Container ist eine laufende Instanz dieses Images. Du kannst mehrere Container aus demselben Image erstellen.
Wie persistiere ich Daten in Docker?
Verwende Volumes. Benannte Volumes (z.B. docker run -v my-vol:/data) werden außerhalb des Dateisystems des Containers gespeichert und überleben Container-Neustarts und -Entfernungen.
Wann sollte ich Docker Compose verwenden?
Verwende Compose, wenn deine Anwendung aus mehreren Diensten besteht (z.B. Web + Datenbank), die zusammen ausgeführt werden müssen. Es vereinfacht die Orchestrierung für Entwicklung und Tests.
Bereit, dein nächstes Projekt zu containerisieren? Beginne mit dem Schreiben eines einfachen Dockerfiles und führe deinen ersten Container aus. Für weitere Entwicklertools schau dir TryQuickToolBox's JSON Formatter an, um API-Antworten zu validieren, während du deine containerisierten Dienste testest.