docker-compose fuer Webapps
Mehrere Services orchestrieren: docker-compose fuer Webapp + Datenbank + Cache. Der Standard fuer lokale Entwicklung und kleine Produktions-Setups.
Inhaltsverzeichnis
docker-compose fuer Webapps
Ein einzelner Container ist selten alles, was du brauchst. Echte Apps haben eine Webapp + Datenbank + Cache + โฆ - und diese zusammen zu starten ist mit docker compose ein Zweizeiler.
Was ist Compose?
docker compose ist ein Tool, das mehrere Container per YAML-Datei definiert und gemeinsam verwaltet. Eine Befehlszeile wie:
docker compose up
โฆ startet deine ganze App-Landschaft: Webserver, DB, Cache, Queue.
Die erste compose.yaml
Ein einfacher Node.js-Server + PostgreSQL + Redis:
compose.yaml:
services:
web:
build: .
ports:
- "3000:3000"
environment:
DATABASE_URL: postgres://app:secret@db:5432/app_db
REDIS_URL: redis://cache:6379
depends_on:
- db
- cache
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: secret
POSTGRES_DB: app_db
volumes:
- db-data:/var/lib/postgresql/data
ports:
- "5432:5432"
cache:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
db-data:
Starten:
docker compose up
Drei Container starten, vernetzen sich, die App ist unter http://localhost:3000 erreichbar.
Die wichtigsten Kommandos
docker compose up # startet alles (zeigt Logs)
docker compose up -d # detached (Hintergrund)
docker compose down # stoppt und loescht alle Container
docker compose down -v # + Volumes loeschen
docker compose ps # welche Services laufen
docker compose logs # Logs aller Services
docker compose logs -f web # nur web, live
docker compose exec web bash # Shell in web-Container
docker compose restart web # nur web neustarten
docker compose pull # aktuelle Images ziehen
docker compose build # Eigene Images neu bauen
Die YAML-Sektionen
services:
Das Herzstueck - jeder Block ist ein Container.
services:
name-des-service:
image: nginx:alpine
# ODER
build: ./pfad-zum-dockerfile
# ODER
build:
context: .
dockerfile: Dockerfile.prod
ports:
Port-Mapping wie bei docker run -p:
ports:
- "3000:3000" # Host:Container
- "127.0.0.1:5432:5432" # nur an Localhost binden
environment:
environment:
NODE_ENV: production
DATABASE_URL: postgres://...
Oder als Liste:
environment:
- NODE_ENV=production
- DATABASE_URL=postgres://...
volumes:
Volumes auf Service-Ebene:
volumes:
- ./app:/app # Bind mount
- db-data:/var/lib/postgres # Named volume
Und Volumes auf Top-Ebene deklarieren:
volumes:
db-data:
depends_on:
Reihenfolge beim Start:
depends_on:
- db
- cache
Wichtig: depends_on wartet nur auf Container-Start, nicht auf โbereitโ - Postgres startet schnell, aber bis es Anfragen annimmt, dauert es ein paar Sekunden. Besser ist ein Healthcheck:
services:
db:
image: postgres:16-alpine
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app"]
interval: 5s
retries: 5
web:
build: .
depends_on:
db:
condition: service_healthy
Jetzt wartet web wirklich, bis DB erreichbar ist.
Networking in Compose
Automatisches Netzwerk
Compose erstellt automatisch ein Netzwerk - alle Services sehen sich ueber den Service-Namen:
environment:
DATABASE_URL: postgres://app:secret@db:5432/app_db
^^^
Service-Name statt localhost/IP
Das ist einer der grossen Vorteile von Compose.
Eigene Netzwerke
services:
web:
networks:
- frontend
- backend
db:
networks:
- backend
networks:
frontend:
backend:
So kann web die DB erreichen, aber andere Frontend-Dienste nicht.
Bind Mounts fuer Live-Reload
In der Entwicklung willst du Code-Aenderungen sofort sehen:
services:
web:
build: .
ports:
- "3000:3000"
volumes:
- ./src:/app/src # Live-Code-Sync
- /app/node_modules # node_modules im Container lassen
environment:
NODE_ENV: development
command: npm run dev
Der Trick: ./src:/app/src synchronisiert deinen Code. /app/node_modules ohne Bind-Mount verhindert, dass dein lokales node_modules drueber geschoben wird.
Env-Files
Secrets und Env-Variablen gehoeren nicht in die compose.yaml eingecheckt:
.env:
POSTGRES_PASSWORD=mein-geheimes-passwort
API_KEY=sk-...
compose.yaml:
services:
web:
env_file:
- .env
db:
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
Die ${VARIABLE}-Syntax liest aus .env zur Startzeit.
Ein produktiver Stack
Beispiel: Next.js App + PostgreSQL + Redis + Adminer
services:
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
DATABASE_URL: postgres://app:${DB_PASSWORD}@db:5432/app
REDIS_URL: redis://cache:6379
depends_on:
db:
condition: service_healthy
restart: unless-stopped
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: app
volumes:
- db-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app"]
interval: 5s
retries: 5
restart: unless-stopped
cache:
image: redis:7-alpine
volumes:
- cache-data:/data
restart: unless-stopped
adminer:
image: adminer:latest
ports:
- "8080:8080"
depends_on:
- db
volumes:
db-data:
cache-data:
Starten:
docker compose up -d
Du hast jetzt:
- App unter
http://localhost:3000 - DB-GUI (Adminer) unter
http://localhost:8080 - PostgreSQL und Redis im Hintergrund
Mehrere Umgebungen: Dev und Prod
Du kannst Overrides nutzen. Basis-Datei + env-spezifische Overrides:
compose.yaml (Basis):
services:
app:
build: .
ports: ["3000:3000"]
compose.override.yaml (Dev, automatisch geladen):
services:
app:
volumes:
- ./src:/app/src
environment:
NODE_ENV: development
command: npm run dev
compose.prod.yaml:
services:
app:
restart: always
environment:
NODE_ENV: production
Prod starten:
docker compose -f compose.yaml -f compose.prod.yaml up -d
Scale - mehrere Instanzen
docker compose up -d --scale web=3
Startet drei web-Container. Wichtig: Die Ports muessen dann dynamisch sein, oder ein Loadbalancer davor.
Resource-Limits
services:
app:
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
Wichtig fuer Produktion - verhindert, dass eine App den ganzen Server beansprucht.
Production-Hinweise
Compose ist fuer:
- Lokale Entwicklung
- Demo-Setups
- Kleine Produktions-Deployments (Single-Host)
Fuer grosses Produktion-Scale (viele Server, Auto-Scaling) nutzt du Kubernetes oder Plattformen wie Google Cloud Run, AWS ECS, Fly.io.
Zusammenfassung
compose.yamldefiniert mehrere Services deklarativdocker compose up/downstartet/stoppt alles- Services sehen sich ueber Namen im internen Netzwerk
- Healthchecks +
condition: service_healthysichern Start-Reihenfolge - Volumes fuer Daten, env_file fuer Secrets
- Override-Dateien fuer Dev vs. Prod
Damit hast du die Werkzeuge, um echte Multi-Service-Apps lokal zu entwickeln und klein zu deployen. Im weiteren Kurs vertiefen wir Docker-Registries, Deployment zu Cloud-Runtimes und den Einstieg in Kubernetes.