Docker Grundlagen
Container-Technologie verstehen. Die Basis fuer modernes Self-Hosting.
🐳 Was ist Docker?
Docker ist eine Plattform für Container. Container sind isolierte Umgebungen, die alles enthalten was eine Anwendung braucht - Code, Bibliotheken, Konfiguration.
❌ Ohne Docker
- "Funktioniert auf meinem PC nicht"
- Abhängigkeits-Konflikte
- Unterschiedliche Versionen
- Komplizierte Installation
✅ Mit Docker
- Läuft überall gleich
- Isolierte Umgebungen
- Einfach reproduzierbar
- Ein Befehl zum Starten
Container vs VM
Container teilen sich den Kernel des Host-Systems und sind daher viel leichter als VMs. Eine VM braucht ein ganzes Betriebssystem, ein Container nur die Anwendung.
📚 Die wichtigsten Konzepte
📦 Image
Eine unveränderliche Vorlage für Container. Enthält das Betriebssystem, die Anwendung und alle Abhängigkeiten. Wird von Docker Hub oder anderen Registries heruntergeladen.
Beispiel: nginx:latest, postgres:15-alpine, node:20
🏃 Container
Eine laufende Instanz eines Images. Kann gestartet, gestoppt und gelöscht werden. Änderungen im Container gehen beim Löschen verloren (außer Volumes).
docker run nginx → Startet einen nginx Container
💾 Volume
Persistenter Speicher für Container. Daten in Volumes überleben Container-Neustarts und -Löschungen. Essentiell für Datenbanken, Uploads, Konfigurationen.
-v postgres_data:/var/lib/postgresql/data
🌐 Network
Virtuelle Netzwerke für Container. Container im gleichen Netzwerk können sich über Namen erreichen. Isoliert Container voneinander oder verbindet sie.
Container "app" erreicht "db" über: postgres://db:5432
📝 Docker Compose
Docker Compose definiert Multi-Container-Anwendungen in einer YAML-Datei. Statt vieler langer Befehle: Eine Datei, ein Befehl.
version: '3.8'
services:
# Web-Anwendung
app:
image: nginx:alpine
ports:
- "80:80" # Host:Container
volumes:
- ./html:/usr/share/nginx/html
depends_on:
- db
networks:
- app-network
# Datenbank
db:
image: postgres:15-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: user
POSTGRES_PASSWORD: geheim
volumes:
- db_data:/var/lib/postgresql/data
networks:
- app-network
volumes:
db_data: # Benanntes Volume
networks:
app-network: # Eigenes Netzwerk
driver: bridge
Compose vs docker run
Ohne Compose müsstest du jeden Container einzeln mit docker run starten
und alle Optionen als Flags übergeben. Compose macht das übersichtlicher und reproduzierbar.
⌨️ Die wichtigsten Befehle
Diese Befehle wirst du täglich nutzen.
# Container starten (im Hintergrund)
docker compose up -d
# Container stoppen
docker compose down
# Container neustarten
docker compose restart
# Status anzeigen
docker compose ps
# Logs anzeigen (live)
docker compose logs -f
# Logs eines Services
docker compose logs -f nginx
# Neue Images ziehen
docker compose pull
# Alles neu bauen und starten
docker compose up -d --build
# In Container-Shell
docker compose exec nginx /bin/sh
# Laufende Container anzeigen
docker ps
# Alle Container (auch gestoppte)
docker ps -a
# Images anzeigen
docker images
# Image herunterladen
docker pull nginx:latest
# Container stoppen
docker stop container_name
# Container löschen
docker rm container_name
# Image löschen
docker rmi image_name
# Unbenutzte Ressourcen aufräumen
docker system prune
# Speicherverbrauch
docker system df
💾 Volumes verstehen
Volumes sind essentiell für persistente Daten. Ohne Volumes gehen alle Daten beim Container-Neustart verloren!
📁 Bind Mount
Verknüpft Host-Verzeichnis mit Container.
./local/path:/container/path
📦 Named Volume
Docker verwaltet den Speicherort.
volume_name:/container/path
services:
db:
image: postgres:15
volumes:
# Named Volume (empfohlen für Datenbanken)
- db_data:/var/lib/postgresql/data
# Bind Mount (für Konfiguration)
- ./config/postgresql.conf:/etc/postgresql/postgresql.conf
# Read-only Bind Mount
- ./secrets:/run/secrets:ro
volumes:
db_data: # Muss deklariert werden
Backup nicht vergessen!
Named Volumes liegen unter /var/lib/docker/volumes/.
Sichere diese regelmäßig! Bei Bind Mounts sicherst du einfach das Host-Verzeichnis.
🌐 Netzwerke verstehen
Container im gleichen Netzwerk können sich gegenseitig über ihren Service-Namen erreichen.
┌─────────────────────────────────────────────┐
│ Docker Network: app-net │
│ │
│ ┌─────────┐ ┌─────────┐ │
│ │ app │────────▶│ db │ │
│ │ :3000 │ db:5432│ :5432 │ │
│ └─────────┘ └─────────┘ │
│ │ │
└───────│─────────────────────────────────────┘
│
▼ Port 3000 exposed
┌─────────┐
│ Host │
│ :3000 │
└─────────┘
services:
app:
image: myapp:latest
ports:
- "3000:3000" # Erreichbar von außen
environment:
# Verbindung zur DB über Service-Name!
DATABASE_URL: postgres://user:pass@db:5432/mydb
networks:
- backend
db:
image: postgres:15
# Kein "ports:" → Nur intern erreichbar
networks:
- backend
networks:
backend:
driver: bridge
Sicherheit durch Netzwerke
Datenbanken sollten keine Ports nach außen freigeben. Nur die App braucht Zugriff - und das klappt über das interne Netzwerk.
🔧 Umgebungsvariablen
Konfiguriere Container über Environment Variables statt Dateien zu ändern.
services:
app:
image: myapp:latest
environment:
# Direkt in der Compose-Datei
- NODE_ENV=production
- DEBUG=false
# Aus Host-Umgebung
- API_KEY=${API_KEY}
# Mit Default-Wert
- PORT=${PORT:-3000}
# Oder aus .env Datei
env_file:
- .env
- .env.local
# Beispiel .env Datei
POSTGRES_PASSWORD=supersecret
API_KEY=abc123
DEBUG=true
.env nicht committen!
Füge .env zu .gitignore hinzu!
Sensible Daten wie Passwörter gehören nicht ins Repository.
Nutze .env.example als Vorlage ohne echte Werte.
🔧 Troubleshooting
Wenn etwas nicht funktioniert - so findest du den Fehler.
# Container-Logs anzeigen
docker compose logs -f service_name
# In Container-Shell gehen
docker compose exec service_name /bin/sh
# oder mit bash:
docker compose exec service_name /bin/bash
# Container-Details anzeigen
docker inspect container_name
# Ressourcenverbrauch live
docker stats
# Netzwerke anzeigen
docker network ls
# Netzwerk-Details
docker network inspect network_name
# Volumes anzeigen
docker volume ls
# Aufräumen (Vorsicht!)
docker system prune -a
Container startet nicht?
→ docker compose logs service_name zeigt Fehlermeldungen
Port already in use?
→ lsof -i :PORT oder anderen Port in Compose wählen
Permission denied?
→ Volume-Berechtigungen prüfen, chown oder chmod
Kein Speicherplatz?
→ docker system prune räumt unbenutzte Images auf
💡 Best Practices
Immer Tags verwenden
nginx:1.25 statt nginx:latest - so weißt du welche Version läuft
Keine Passwörter in Compose
Nutze .env Dateien oder Docker Secrets für sensible Daten
Volumes fuer wichtige Daten
Datenbanken, Uploads, Konfigurationen - immer in Volumes speichern
Eigene Netzwerke nutzen
Isoliere Container-Gruppen in eigenen Netzwerken
Regelmaessig aufraeumen
docker system prune entfernt unbenutzte Images und Container
Haeufige Fragen
Docker vs Docker Compose - was ist der Unterschied?
Docker verwaltet einzelne Container. Docker Compose orchestriert mehrere Container als Anwendung. Für Self-Hosting nutzt du fast immer Docker Compose.
Wie update ich einen Container?
# Neues Image ziehen
docker compose pull
# Container neu starten mit neuem Image
docker compose up -d
# Optional: Alte Images aufräumen
docker image prune
Wie sichere ich Docker-Daten?
Zwei Dinge sichern:
- docker-compose.yml - In Git versionieren
- Volumes - Mit Backup-Tool (Restic, Borg) oder
docker run --rm -v volume:/data -v backup:/backup alpine tar czf /backup/data.tar.gz /data
Container startet immer neu - warum?
Prüfe die Logs mit docker compose logs -f.
Oft ist es ein Konfigurationsfehler oder fehlende Umgebungsvariable.
restart: unless-stopped sorgt dafür, dass Docker den Container immer neu startet.