docker compose up vs docker compose run - der Unterschied
docker compose up vs docker compose run - der Unterschied
up und run klingen ähnlich, verfolgen aber grundlegend verschiedene Ziele — der falsche Befehl in einem Migrations-Script kostet Zeit und Nerven.
docker compose up
Startet alle Services und hält sie am Laufen:
docker compose up # Vordergrund, Logs in Terminal
docker compose up -d # Hintergrund (detached)
docker compose up app db # Nur bestimmte Services
docker compose up --build # Images vorher neu bauen
docker compose up --force-recreate # Container neu erstellen, auch wenn unverändert
- Startet alle Services mit ihren Abhängigkeiten
- Bleibt dauerhaft aktiv
- Hält
depends_on-Reihenfolge ein - Zeigt aggregierte Logs aller Services
docker compose run
Führt einen einmaligen Befehl in einem neuen Container aus:
docker compose run app python manage.py migrate
docker compose run app bash
docker compose run --rm app python seed.py
- Startet einen neuen Container für den Service
- Startet automatisch
depends_on-Abhängigkeiten - Endet, wenn der Befehl fertig ist
--rm: Container nach Abschluss automatisch löschen
Vergleich auf einen Blick
| | up | run |
|---|---|---|
| Ziel | Alle Services dauerhaft starten | Einmaligen Befehl ausführen |
| Endet automatisch | Nein | Ja (wenn Befehl fertig) |
| Startet Abhängigkeiten | Ja | Ja |
| Mehrere Services | Ja | Nein (ein Service) |
| Typischer Einsatz | Produktions-/Dev-Start | Migrationen, Skripte, Debugging |
Nützliche run-Flags
# Container nach Ausführung löschen (fast immer sinnvoll)
docker compose run --rm app python migrate.py
# Abhängigkeiten nicht starten (wenn DB schon läuft)
docker compose run --no-deps app python check.py
# Umgebungsvariable überschreiben
docker compose run -e APP_ENV=test app python test.py
# Port mappen (run mappt keine ports: aus der Compose-Definition)
docker compose run -p 8080:8080 app
# Interaktive Shell
docker compose run --rm app bash
# Anderen Benutzer
docker compose run --user root app sh
run vs. exec
Drei Befehle, drei verschiedene Szenarien:
# Neuen Container für einmaligen Befehl starten
docker compose run --rm app python migrate.py
# Befehl in bereits laufendem Container ausführen
docker compose exec app python status.py
# Interaktive Shell in laufendem Container
docker compose exec -it app bash
| | run | exec |
|---|---|---|
| Container muss laufen | Nein | Ja |
| Startet neuen Container | Ja | Nein |
| Für Einmalaufgaben | Ja | Nein |
| Für Debugging laufender Container | Nein | Ja |
Typisches Migrations-Pattern
# DB starten und warten
docker compose up -d db
docker compose run --rm app python wait-for-db.py
# Migration ausführen
docker compose run --rm app python manage.py migrate
# App starten
docker compose up -d app
Oder in einem Schritt mit depends_on und healthcheck — dann übernimmt Compose das Warten:
docker compose run --rm app python manage.py migrate # DB startet automatisch als Abhängigkeit
docker compose up -d
Ports und run
run mappt keine Ports aus dem ports:-Block der Compose-Definition. Das ist eine häufige Falle:
# Port explizit angeben wenn nötig
docker compose run -p 8080:8080 app # Nicht der ports:-Block aus compose.yml
run ist das richtige Werkzeug für alles, was einmal läuft und dann fertig ist — Migrationen, Datei-Generierung, Seed-Skripte, Tests. up ist für Dienste, die dauerhaft verfügbar sein sollen.