Docker-Grundlagen: Container für Anwendungen und Dienste

Docker hat die Art, wie Software deployed wird, fundamental verändert: Anwendungen laufen in Containern – isoliert, reproduzierbar und überall gleich. Dieser Artikel erklärt die Konzepte, die wichtigsten Befehle und zeigt, wie man einen eigenen Container baut und betreibt.

Was ist ein Container? (Und was nicht?)

Ein Container ist kein virtueller Rechner. Er teilt sich den Linux-Kernel mit dem Host, isoliert aber Prozesse, Dateisystem, Netzwerk und Ressourcen. Vorteile:

  • Reproduzierbar: Das Image enthält alles – Code, Laufzeit, Bibliotheken, Konfiguration. „Läuft bei mir" entfällt.
  • Leichtgewichtig: Container starten in Sekunden und verbrauchen kaum Overhead.
  • Isoliert: Eine Anwendung kann nicht versehentlich den Host oder andere Container stören.

Grundbegriffe: Ein Image ist die Blaupause (read-only), ein Container die laufende Instanz daraus. Images werden in Registries gehandelt – Docker Hub ist die bekannteste.

Die wichtigsten Befehle

docker pull nginx              # Image holen
docker run -d -p 8080:80 --name web nginx   # Container starten (detached)
docker ps                      # laufende Container
docker ps -a                   # alle Container (auch gestoppte)
docker logs web                # Logs ansehen
docker exec -it web bash       # Shell im Container
docker stop web && docker rm web
docker images                  # lokale Images
docker system df               # Speicherverbrauch

Erklärung von docker run -d -p 8080:80 --name web nginx: -d läuft im Hintergrund, -p 8080:80 mappt Host-Port 8080 auf Container-Port 80, --name vergibt einen sprechenden Namen.

Ein eigenes Image bauen: Dockerfile

Ein Dockerfile beschreibt den Bau schrittweise. Beispiel für eine kleine Python-API:

# 1. Basis-Image (schlank, mit Python 3.12)
FROM python:3.12-slim

# 2. Arbeitsverzeichnis
WORKDIR /app

# 3. Erst Abhängigkeiten kopieren (Layer-Caching!)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 4. Dann den Code
COPY app.py .

# 5. Benutzer ohne root (Sicherheit!)
RUN useradd -m appuser
USER appuser

# 6. Port und Startbefehl
EXPOSE 8000
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]

Bauen und starten:

docker build -t meine-api .
docker run -d -p 8000:8000 --name api meine-api

Praktische Tipps: Die Reihenfolge der COPY-Befehle ist entscheidend fürs Caching – Abhängigkeiten ändern sich seltener als Code. Jeder RUN/COPY-Schritt erzeugt einen Layer; weniger, dafür sinnvolle Schritte halten Images schlank.

Volumes: Daten bleiben erhalten

Container sind ephemer – beim Löschen verschwinden ihre Daten. Für persistente Daten (Datenbanken, Uploads) nutzt man Volumes:

# Benanntes Volume (von Docker verwaltet)
docker volume create dbdata
docker run -d -v dbdata:/var/lib/mysql --name mariadb mariadb:11

# Bind-Mount (Host-Verzeichnis direkt einbinden)
docker run -d -v /srv/web:/usr/share/nginx/html:ro nginx

Backup-Regel: Volumes gehören in jedes Backup-Konzept – siehe Backup-Strategien.

Netzwerke: Container miteinander verbinden

Container sollten über benutzerdefinierte Netzwerke kommunizieren, nicht über Ports auf dem Host:

docker network create appnet
docker run -d --network appnet --name db mariadb:11
docker run -d --network appnet --name api meine-api
# API erreicht db über den Namen "db" (Docker-DNS)

Nur Dienste, die von außen erreichbar sein sollen, bekommen -p-Portmappings. Interner Verkehr bleibt im Netzwerk – das ist die saubere, sichere Variante.

docker-compose: Mehrere Container als Einheit

Für zusammengesetzte Anwendungen (Web + DB + Cache) ist Docker Compose Standard. Datei compose.yaml:

services:
  web:
    build: .
    ports:
      - "8080:80"
    depends_on:
      - db
  db:
    image: mariadb:11
    environment:
      MARIADB_ROOT_PASSWORD: beispiel
    volumes:
      - dbdata:/var/lib/mysql

volumes:
  dbdata:

Starten mit docker compose up -d, Logs mit docker compose logs -f, Stoppen mit docker compose down. Ein Projekt – ein Befehl – reproduzierbare Umgebung für Entwicklung und Produktion.

Images aktualisieren und alte entfernen

Images veralten – Sicherheitsupdates erscheinen für Basis-Images regelmäßig. Der Workflow:

# Neuestes Basis-Image holen und neu bauen
docker pull python:3.12-slim
docker build --pull -t meine-api .

# Container mit neuem Image ersetzen (ohne Ausfall: zwei Container im Wechsel)
docker run -d --name api-neu -p 8000:8000 meine-api
docker stop api && docker rm api
docker rename api-neu api

Regelmäßig aufräumen:

docker image prune -a    # unbenutzte Images löschen
docker container prune   # gestoppte Container löschen
docker system df         # Speicherverbrauch prüfen

Wer mehrere Hosts betreibt, sollte ein privates Registry nutzen (z.B. registry:2 als Container) und Images zentral verwalten – statt sie per docker save/load zu kopieren.

Container-Logs sinnvoll auswerten

Container schreiben nach stdout/stderr – Docker sammelt das:

docker logs --tail 100 api          # letzte 100 Zeilen
docker logs -f api                  # live verfolgen
docker logs --since 1h api          # letzte Stunde
docker inspect api | grep -i log    # Log-Konfiguration ansehen

Für Dienste, die in Container laufen, ist die Log-Rotation wichtig: --log-opt max-size=10m --log-opt max-file=3 beim Start begrenzt die Log-Größe. Zentralisierte Log-Auswertung (z.B. über den Docker-JSON-Log-Treiber oder einen Log-Shipper) gehört zu jeder ernsthaften Infrastruktur – mehr in Monitoring in der Systemadministration.

Pitfalls aus der Praxis

  • Als root laufen lassen: Immer USER im Dockerfile setzen und --user beim Lauf nutzen, wenn möglich.
  • Keine Limits: --memory 512m --cpus 1 verhindern, dass ein Container den Host lahmlegt.
  • Veraltete Images: Regelmäßig docker image prune und Basis-Images aktualisieren – Sicherheitslücken leben in alten Layern.
  • Secrets im Image: Nie Passwörter ins Dockerfile schreiben; Umgebungsvariablen oder Secret-Manager nutzen.
  • Logs ohne Rotation: Docker-Logdateien können riesig werden; Logrotate oder Treiber-Limits konfigurieren.

Fazit

Container sind 2026 der Standard für Deployment – ob ein einzelner Dienst oder eine komplette Plattform. Docker + Compose decken den Einstieg und den Alltag ab; wer orchestrieren muss (mehrere Hosts, Skalierung, Self-Healing), steigt später auf Kubernetes oder eine Managed-Plattform um. Dass Container auf dem Host sauber laufen, dafür sorgt die Systemadministration – siehe Systemd und Systemadministration.

Verwandte Artikel: Systemadministration · Python für Einsteiger · TCP/IP-Grundlagen