← Zurück zum Wissensbereich

Docker Compose für KMU: Praktischer Einstieg

Docker Container sind großartig – aber was, wenn Ihre Applikation aus mehreren Containern besteht? WordPress + MySQL + Redis? GitLab + PostgreSQL + Runner? Hier kommt Docker Compose ins Spiel: Definieren Sie komplette Multi-Container-Umgebungen in einer einzigen YAML-Datei und starten Sie alles mit einem Befehl.

Was ist Docker Compose?

Docker Compose ist ein Tool zur Definition und Verwaltung von Multi-Container Docker-Applikationen. Statt jeden Container einzeln mit docker run zu starten, definieren Sie alle Services in einer docker-compose.yml Datei.

Vorteile von Docker Compose:

🎯 Wann Docker Compose verwenden?

Ideal für: Entwicklungsumgebungen, Test-Stacks, kleinere Produktions-Deployments (1-5 Server).

Nicht ideal für: Hochverfügbare Cluster (>10 Server) → Kubernetes ist besser.

Docker Compose Installation

Linux (Ubuntu/Debian):

# Docker Compose V2 (Plugin) - empfohlen
sudo apt-get update
sudo apt-get install docker-compose-plugin

# Verify Installation
docker compose version

macOS & Windows:

Docker Compose ist in Docker Desktop enthalten (automatisch installiert).

docker-compose.yml Grundstruktur

Eine docker-compose.yml Datei definiert Services (Container), Networks und Volumes.

version: '3.8'  # Compose-Datei-Version

services:
  web:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ./html:/usr/share/nginx/html
  
  database:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: geheim123
    volumes:
      - db_data:/var/lib/mysql

volumes:
  db_data:

Wichtige Schlüsselwörter:

Beispiel 1: WordPress mit MySQL

Der Klassiker: WordPress benötigt einen Webserver (PHP) + Datenbank (MySQL).

docker-compose.yml:

version: '3.8'

services:
  # MySQL-Datenbank
  db:
    image: mysql:8.0
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: rootPasswort123
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wpuser
      MYSQL_PASSWORD: wpPasswort456
    volumes:
      - db_data:/var/lib/mysql
    networks:
      - wordpress_network

  # WordPress
  wordpress:
    image: wordpress:latest
    restart: always
    depends_on:
      - db
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wpuser
      WORDPRESS_DB_PASSWORD: wpPasswort456
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - wordpress_data:/var/www/html
    networks:
      - wordpress_network

volumes:
  db_data:
  wordpress_data:

networks:
  wordpress_network:

Starten:

# Im gleichen Verzeichnis wie docker-compose.yml
docker compose up -d

# Logs anzeigen
docker compose logs -f

# Öffne Browser: http://localhost:8080

Stoppen & Aufräumen:

# Stoppen (Container bleiben, Volumes bleiben)
docker compose stop

# Stoppen + Container löschen (Volumes bleiben)
docker compose down

# Alles löschen (inkl. Volumes)
docker compose down -v

Beispiel 2: LEMP-Stack (Linux, Nginx, MySQL, PHP)

Klassischer Webserver-Stack für PHP-Applikationen.

version: '3.8'

services:
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./app:/var/www/html
    depends_on:
      - php
    networks:
      - lemp

  php:
    image: php:8.2-fpm
    volumes:
      - ./app:/var/www/html
    networks:
      - lemp

  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: root123
      MYSQL_DATABASE: appdb
    volumes:
      - mysql_data:/var/lib/mysql
    networks:
      - lemp

volumes:
  mysql_data:

networks:
  lemp:

Beispiel 3: GitLab + PostgreSQL + Redis

Enterprise-Setup: GitLab benötigt Datenbank (PostgreSQL) und Cache (Redis).

version: '3.8'

services:
  gitlab:
    image: gitlab/gitlab-ce:latest
    hostname: gitlab.example.com
    ports:
      - "80:80"
      - "443:443"
      - "22:22"
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://gitlab.example.com'
        gitlab_rails['db_adapter'] = 'postgresql'
        gitlab_rails['db_host'] = 'postgres'
        gitlab_rails['db_database'] = 'gitlab'
        gitlab_rails['db_username'] = 'gitlab'
        gitlab_rails['db_password'] = 'gitlab123'
        redis['bind'] = 'redis'
    volumes:
      - gitlab_config:/etc/gitlab
      - gitlab_logs:/var/log/gitlab
      - gitlab_data:/var/opt/gitlab
    depends_on:
      - postgres
      - redis
    networks:
      - gitlab_network

  postgres:
    image: postgres:14
    environment:
      POSTGRES_DB: gitlab
      POSTGRES_USER: gitlab
      POSTGRES_PASSWORD: gitlab123
    volumes:
      - postgres_data:/var/lib/postgresql/data
    networks:
      - gitlab_network

  redis:
    image: redis:alpine
    networks:
      - gitlab_network

volumes:
  gitlab_config:
  gitlab_logs:
  gitlab_data:
  postgres_data:

networks:
  gitlab_network:

Wichtige Docker Compose Befehle

Befehl Beschreibung
docker compose up Startet alle Services (foreground)
docker compose up -d Startet alle Services (detached/background)
docker compose down Stoppt & löscht alle Container
docker compose down -v Stoppt, löscht Container + Volumes
docker compose logs Zeigt Logs aller Services
docker compose logs -f service_name Live-Logs eines Services
docker compose ps Liste laufender Container
docker compose exec service_name bash Shell in laufenden Container öffnen
docker compose restart Startet alle Services neu
docker compose pull Aktualisiert alle Images

Environment-Variablen & .env-Datei

Hardcodierte Passwörter in docker-compose.yml? Schlechte Idee! Nutzen Sie .env-Dateien.

.env-Datei erstellen:

# .env
MYSQL_ROOT_PASSWORD=superGeheim123
MYSQL_DATABASE=wordpress
MYSQL_USER=wpuser
MYSQL_PASSWORD=wpPasswort456

docker-compose.yml mit Variablen:

version: '3.8'

services:
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}

Wichtig: .env zu .gitignore hinzufügen (niemals Passwörter in Git committen!)

Volumes: Daten persistent halten

Container sind ephemeral (flüchtig) – beim Löschen sind Daten weg. Volumes lösen dieses Problem.

Zwei Arten von Volumes:

1. Named Volumes (empfohlen):

volumes:
  - db_data:/var/lib/mysql

Docker verwaltet Volume automatisch (Speicherort: /var/lib/docker/volumes/)

2. Bind Mounts (für Entwicklung):

volumes:
  - ./my-app:/var/www/html

Lokales Verzeichnis wird direkt in Container gemountet (Änderungen sofort sichtbar).

Volume-Kommandos:

# Alle Volumes anzeigen
docker volume ls

# Volume inspizieren
docker volume inspect PROJECT_db_data

# Volume löschen (nur wenn nicht in Nutzung)
docker volume rm PROJECT_db_data

Networks: Container-Kommunikation

Docker Compose erstellt automatisch ein privates Netzwerk für alle Services. Container können sich per Service-Namen erreichen.

Beispiel: WordPress → MySQL

# WordPress-Container kann MySQL via Hostname "db" erreichen
WORDPRESS_DB_HOST: db:3306

db ist der Service-Name in docker-compose.yml → Docker-DNS löst ihn automatisch zur Container-IP auf.

Eigene Netzwerke definieren:

networks:
  frontend:
  backend:

services:
  web:
    networks:
      - frontend
  
  api:
    networks:
      - frontend
      - backend
  
  database:
    networks:
      - backend

Use Case: web kann api erreichen, aber nicht database (Security!)

Production-Ready Compose: Best Practices

1. Health Checks definieren:

services:
  web:
    image: nginx:latest
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

2. Resource Limits setzen:

services:
  web:
    image: nginx:latest
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
        reservations:
          memory: 256M

3. Restart Policies:

services:
  web:
    image: nginx:latest
    restart: unless-stopped  # Startet immer neu (außer manuell gestoppt)

Restart-Optionen:

4. Logging konfigurieren:

services:
  web:
    image: nginx:latest
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

Multi-Environment Setup (Dev vs. Prod)

Gleicher Stack, unterschiedliche Configs? Nutzen Sie mehrere Compose-Dateien.

docker-compose.yml (Basis):

version: '3.8'

services:
  web:
    image: nginx:latest
    volumes:
      - ./app:/usr/share/nginx/html

docker-compose.override.yml (Dev):

version: '3.8'

services:
  web:
    ports:
      - "8080:80"
    environment:
      - DEBUG=true

docker-compose.prod.yml (Production):

version: '3.8'

services:
  web:
    ports:
      - "80:80"
    restart: unless-stopped
    environment:
      - DEBUG=false

Starten:

# Dev (automatisch: docker-compose.yml + docker-compose.override.yml)
docker compose up -d

# Production
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

Docker Compose vs. Kubernetes: Wann was?

Kriterium Docker Compose Kubernetes
Komplexität Niedrig (YAML-Datei) Hoch (Manifests, Deployments, Services, Ingress)
Setup-Zeit 5-15 Minuten 2-5 Tage (für Cluster-Setup)
Geeignet für 1-5 Server, Dev/Test, KMU 10+ Server, High-Availability, Enterprise
Auto-Scaling Nein Ja (Horizontal Pod Autoscaler)
Self-Healing Eingeschränkt (restart policy) Ja (automatisches Re-Scheduling)
Kosten Niedrig (Standard-Server) Hoch (Managed K8s oder Cluster-Verwaltung)

💡 Unsere Empfehlung

Für KMU (< 5 Server): Docker Compose ist ausreichend und deutlich einfacher.

Für Wachstum (5-10 Server): Docker Swarm (native Clustering, einfacher als Kubernetes).

Für Enterprise (> 10 Server): Kubernetes (wenn das Team die Komplexität managen kann).

Troubleshooting: Häufige Probleme

❌ Problem: "Port already in use"

Error: Bind for 0.0.0.0:80 failed: port is already allocated

Lösung: Port 80 ist bereits belegt. Ändere Port-Mapping:

ports:
  - "8080:80"  # Statt 80:80

❌ Problem: Container startet, aber nicht erreichbar

Diagnose:

# Container-Status prüfen
docker compose ps

# Logs anzeigen
docker compose logs service_name

# In Container einloggen
docker compose exec service_name sh

❌ Problem: Datenbank-Verbindung fehlgeschlagen

Häufigste Ursache: App startet vor Datenbank.

Lösung: depends_on + Health Check:

services:
  app:
    depends_on:
      db:
        condition: service_healthy
  
  db:
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5

Checkliste: Production-Ready Docker Compose

✅ Vor Produktions-Deployment:

  • Alle Passwörter in .env-Datei (nicht in docker-compose.yml)
  • Restart Policy: unless-stopped für alle Services
  • Health Checks für kritische Services
  • Resource Limits (CPU/Memory) gesetzt
  • Volumes für alle Daten (nicht im Container speichern!)
  • Logging konfiguriert (max-size, max-file)
  • Backup-Strategie für Volumes (täglich/wöchentlich)
  • Monitoring (Prometheus + Grafana oder Uptime-Monitor)
  • Firewall-Regeln (nur notwendige Ports öffnen)
  • SSL-Terminierung (Reverse Proxy: nginx, Traefik, Caddy)

Fazit: Docker Compose für pragmatische Deployments

Docker Compose ist das ideale Tool für KMU: Einfach, schnell, pragmatisch. Mit einer YAML-Datei definieren Sie komplette Applikations-Stacks – kein Kubernetes-Overhead, keine steile Lernkurve.

Die wichtigsten Takeaways:

🐳 Brauchen Sie Hilfe bei Docker & Container-Orchestrierung?

Wir unterstützen Sie bei: Docker Compose Setup, Multi-Container-Architekturen, Migration zu Docker, Kubernetes-Evaluierung, Monitoring & Backups.

Kostenlose Docker-Beratung anfragen