Design wechseln

Docker-Container startet und beendet sich sofort? Vollständige Troubleshooting-Anleitung (inkl. Exit-Codes 137/1)

Easton editorial illustration: bottleneck pressure gauge

Gerade wollte ich den Rechner zum Feierabend ausschalten, als mein Handy vibrierte – Alarm in der Produktionsumgebung. Ein Blick aufs Display: Alle vier Kernservices waren im Exited-Status. Terminal auf, docker ps eingegeben. Leer. Komplett leer.

Das Gefühl ist wie beim Öffnen des Kühlschranks für ein Getränk – und der Kühlschrank ist völlig leer. Panik.

Ehrlich gesagt war mein erster Gedanke: „Schluss, das Wochenende ist gelaufen.” Aber nach kurzer Ruhe wurde mir klar: Container-Startfehler sind kein Neuland. Diesmal kam das Problem nur plötzlicher und mit größerer Wirkung.

Nach über zwei Stunden Fehlersuche stellte sich heraus, dass die Ursache simpel war – ein falscher Pfad in einer Service-Konfigurationsdatei, wodurch die Datenbankverbindung scheiterte und der Container sofort beendet wurde. Mit einem systematischen Troubleshooting-Workflow wäre das Problem vermutlich in zehn Minuten gelöst gewesen.

Dieser Artikel ist meine Zusammenfassung aus unzähligen Fehlversuchen: eine Anleitung zur Fehlerbehebung bei fehlgeschlagenen Container-Starts. Ob Exit Code 1, 137 oder ein anderer Code – diese Methode hilft Ihnen, die Ursache schnell zu finden.

Container-Lebenszyklus und Exit-Codes verstehen

Bevor wir mit der Fehlersuche beginnen, klären wir eine Grundfrage: Warum beendet sich ein Container?

Das Wesen eines Containers: Lebenszyklus eines Prozesses

Ein Docker-Container ist im Grunde ein isolierter Prozess. Läuft der Prozess, läuft der Container; beendet sich der Prozess, ist der Container beendet.

Stellen Sie sich vor, Sie starten einen Web-Service-Container. Der Hauptprozess darin ist vielleicht nginx oder node – solange er läuft, erscheint der Container in docker ps. Beendet sich der Hauptprozess – normal, durch Absturz oder durch das System – wechselt der Container sofort in den Exited-Status.

Deshalb zeigt docker ps manchmal nichts an; erst mit -a sehen Sie auch beendete Container.

Exit-Code-Referenz: Was die Zahlen bedeuten

Bei jedem Container-Exit speichert Docker einen Exit-Code. Die Zahl wirkt kryptisch, erzählt aber, was passiert ist.

Exit Code 0: Alles in Ordnung, Aufgabe abgeschlossen.
Beispiel: Ein Datenimport-Skript läuft durch und beendet sich – Exit Code 0. Kein Fehler, der Container hat seine Aufgabe erledigt.

Exit Code 1: Die Anwendung selbst ist fehlgeschlagen.
Der häufigste Fehlercode. Mögliche Ursachen: falsche Konfiguration, fehlende Abhängigkeit oder Bug im Code – die Anwendung im Container ist abgestürzt.

Ich erinnere mich an ein MySQL-Deployment mit permanentem Exit Code 1. Nach langem Log-Studium stellte sich heraus: In der Konfigurationsdatei hatte ich aus Versehen ein Gleichheitszeichen durch einen Doppelpunkt ersetzt. MySQL startete, erkannte den Syntaxfehler und beendete sich sofort.

Exit Code 137: Speichermangel oder erzwungene Beendigung.
Dieser Code macht mir am meisten Sorgen. 137 bedeutet meist:

  1. Der Container hat zu viel Speicher verbraucht – der Linux-OOM Killer (Out-of-Memory Killer) hat den Prozess beendet
  2. Jemand (oder das System) hat docker kill oder kill -9 ausgeführt

Wie unterscheiden? Mit docker inspect das Feld OOMKilled prüfen. Bei true liegt ein Speicherproblem vor; bei false eher eine manuelle Beendigung.

Exit Code 127: Befehl nicht gefunden.
Typisch bei falschem Pfad in CMD oder ENTRYPOINT im Dockerfile, oder wenn die ausführbare Datei im Image fehlt.

Exit Code 139: Segmentation Fault.
Tritt meist bei C/C++-Programmen auf – Zugriff auf ungültigen Speicher. Bei normalen Anwendungen selten.

Muster bei Exit-Codes

Exit-Codes folgen einer Logik:

  • 0: Normaler Exit, kein Problem
  • 1–128: Fehler der Anwendung selbst (Anwendungs- oder Konfigurationsfehler)
  • 129–255: Externe Eingriffe (Signal-Unterbrechung, Beendigung durch das System)

Mit diesem Wissen können Sie den Exit-Code grob einordnen und die Fehlersuche gezielt starten.

Vier-Schritte-Methode zur schnellen Fehlerfindung

Sie kennen jetzt die Bedeutung der Exit-Codes. Aber das allein reicht nicht – Sie brauchen einen klaren Ablauf.

Ich habe eine Vier-Schritte-Methode entwickelt, die etwa 90 % der Container-Startfehler abdeckt. Wenn Sie diesem Ablauf folgen, wirken die Probleme weniger undurchsichtig.

Schritt 1: Container-Status bestätigen

Bevor Sie in die Logs schauen: Bestätigen Sie, dass der Container existiert und beendet ist.

docker ps -a

Dieser Befehl listet alle Container, auch beendete. Achten Sie auf:

CONTAINER ID: Eindeutige Kennung für alle folgenden Befehle. Die ersten Zeichen reichen – Docker matcht automatisch.

Spalte STATUS: Hier liegt der Schlüssel. Laufende Container zeigen Up X minutes, beendete Exited (Exit-Code) X minutes ago.

Beispiel:

CONTAINER ID   IMAGE         STATUS
a1b2c3d4e5f6   mysql:8.0     Exited (1) 2 minutes ago

Exit-Code 1 deutet auf Anwendungsebene hin; 137 eher auf Speicherprobleme.

Erstellungs- und Exit-Zeit beachten. Beendet sich der Container weniger als eine Sekunde nach dem Start, liegt meist ein Problem mit Startbefehl oder Konfiguration vor. Läuft er eine Weile und bricht dann ab, eher Ressourcenmangel oder ausgefallene Abhängigkeiten.

Schritt 2: Container-Logs prüfen

Der wichtigste Schritt. Vor dem Exit hinterlässt der Container meist Spuren – in den Logs.

Grundlegende Anzeige:

docker logs <container_id>

Zeigt stdout und stderr. Oft sehen Sie direkt Fehlermeldungen wie Permission denied, No such file or directory oder Connection refused.

Echtzeit-Verfolgung (für den Startvorgang):

docker logs -f <container_id>

Mit -f folgen Sie neuen Logzeilen wie bei tail -f. Bei bereits beendeten Containern weniger nützlich – eher beim erneuten Startversuch.

Nur die letzten Zeilen:

docker logs --tail 100 <container_id>

Bei langen Logs reichen oft die letzten 100 Zeilen – dort steht meist der entscheidende Hinweis.

Mit Zeitstempel:

docker logs -t <container_id>

-t fügt jedem Logeintrag einen Zeitstempel hinzu – hilfreich für die zeitliche Einordnung.

Fehler filtern:

docker logs <container_id> 2>&1 | grep -i error

Bei vielen Logzeilen: nur Einträge mit „error” anzeigen – schneller Fokus auf das Wesentliche.

Schritt 3: Container-Konfiguration prüfen

Manchmal reichen die Logs nicht – dann tiefer in Konfiguration und Zustand schauen.

Vollständige Konfiguration:

docker inspect <container_id>

Gibt umfangreiches JSON aus: Konfiguration, Umgebungsvariablen, Mounts, Netzwerk und mehr. Viel Information, aber sehr hilfreich.

Gezielt einzelne Felder abfragen:

Exit-Code anzeigen:

docker inspect --format '{{.State.ExitCode}}' <container_id>

OOM-Kill prüfen:

docker inspect --format '{{.State.OOMKilled}}' <container_id>

Bei Ausgabe true ist Speichermangel bestätigt.

Umgebungsvariablen anzeigen:

docker inspect --format '{{.Config.Env}}' <container_id>

Häufige Fehlerquelle: falsche DB-Verbindungsstrings, API-Keys usw.

Mount-Pfade anzeigen:

docker inspect --format '{{.Mounts}}' <container_id>

Prüfen, ob Konfigurations- und Datenverzeichnisse korrekt gemountet sind.

Log-Dateipfad anzeigen:

docker inspect --format='{{.LogPath}}' <container_id>

Falls docker logs nicht hilft, Log-Datei direkt auf dem Host lesen.

Schritt 4: Interaktiver Start zur Verifikation

Wenn die ersten drei Schritte nicht reichen: selbst in den Container schauen.

Interaktiver Start:

War der ursprüngliche Befehl:

docker run -d my-app

ersetzen Sie -d durch -it für Vordergrund-Ausführung:

docker run -it my-app

So sehen Sie alle Ausgaben während des Starts direkt auf dem Bildschirm.

Manuell in den Container wechseln:

Startet und beendet sich der Container sofort, mit Shell interaktiv starten:

docker run -it my-app /bin/bash

oder:

docker run -it my-app /bin/sh

Im Container können Sie:

  • Konfigurationsdateien prüfen: ls /etc/app/config.yaml
  • Konfigurationssyntax testen: z. B. bei MySQL mysqld --verbose --help
  • Startbefehl manuell ausführen und Fehler beobachten
  • Abhängigkeiten testen: ping database, telnet redis 6379

Besonders geeignet für Pfad-, Berechtigungs- und Abhängigkeitsprobleme.

Klingt nach vielen Schritten – in der Praxis löst Schritt 2 (Logs) die meisten Fälle. Nur bei hartnäckigen Problemen lohnt sich der vollständige Durchlauf.

Fünf typische Fehlerszenarien und Lösungen

Nach der Methode folgen die häufigsten Praxisfälle – fünf Kategorien, die den Großteil der Alltagsprobleme abdecken.

Szenario 1: Fehlerhafte Konfiguration oder fehlender Pfad

Typische Anzeichen:

  • Exit Code 1
  • Logs mit No such file or directory, config file not found, syntax error o. Ä.

Praxisbeispiel:

Bei einem Node.js-Deployment startete der Container nicht. Im Log stand:

Error: ENOENT: no such file or directory, open '/app/config/prod.json'

Ursache: Im docker run war der Mount-Pfad falsch:

-v /home/user/config:/app/conf  # hier conf statt config

Die Anwendung erwartete /app/config – ein Buchstabe Unterschied, und der Start scheiterte.

Troubleshooting:

  1. docker inspect --format '{{.Mounts}}' – Mount-Pfade prüfen
  2. Im Container mit ls prüfen, ob die Datei am erwarteten Ort liegt
  3. Bei Syntaxfehlern in Konfigurationsdateien zeigt die Anwendung meist die betroffene Zeile im Log

Lösungen:

Falscher Mount-Pfad:

# Falsch
docker run -v /host/path:/wrong/path my-app

# Richtig
docker run -v /host/path:/app/config my-app

Syntaxfehler in Konfigurationsdateien:

  • YAML: Online-Tools oder yamllint
  • JSON: mit jq validieren: jq . config.json
  • MySQL: im Container mysqld --verbose --help ausführen

Szenario 2: Speichermangel (OOM Killed)

Typische Anzeichen:

  • Exit Code 137
  • docker inspect --format '{{.State.OOMKilled}}' liefert true
  • Logs mit Cannot allocate memory, Out of memory o. Ä.

Praxisbeispiel:

Eine Java-Anwendung lief lokal einwandfrei, auf dem Testserver startete sie ständig neu. Im Log:

OpenJDK 64-Bit Server VM warning: INFO: os::commit_memory failed; error='Cannot allocate memory' (errno=12)

Docker Desktop war auf 512 MB begrenzt – die Java-App benötigte beim Start etwa 600 MB.

Troubleshooting:

# OOM bestätigen
docker inspect --format '{{.State.OOMKilled}}' <container_id>

# Host-Speicher prüfen
free -h

# Speichernutzung des Containers
docker stats <container_id>

Lösungen:

Speicherlimit erhöhen:

docker run -m 1g my-app  # max. 1 GB
docker run -m 512m --memory-swap 1g my-app  # inkl. Swap

Bei Docker Desktop:

  • macOS: Docker Desktop → Preferences → Resources → Memory
  • Windows: Docker Desktop → Settings → Resources → Memory

Anwendung optimieren:

  • Java: JVM-Heap begrenzen: java -Xmx512m -jar app.jar
  • Node.js: node --max-old-space-size=512 app.js
  • Code auf Speicherlecks prüfen

Produktionsempfehlung:

  • Speicherlimit passend zum tatsächlichen Bedarf setzen
  • --memory-reservation als Soft-Limit
  • Speichertrend überwachen und rechtzeitig skalieren

Szenario 3: Portkonflikt

Typische Anzeichen:

  • Exit Code 1
  • Logs mit port is already allocated, address already in use, bind: address already in use

Praxisbeispiel:

Montagmorgen: docker-compose up, Nginx-Container startet nicht:

Error starting userland proxy: listen tcp4 0.0.0.0:80: bind: address already in use

Freitag war ein lokaler Nginx-Test offen geblieben – Port 80 belegt, neuer Container konnte nicht starten.

Troubleshooting:

Portbelegung prüfen (Linux/macOS):

lsof -i :8080
netstat -tuln | grep 8080

Portbelegung prüfen (Windows):

netstat -ano | findstr 8080

Port-Mappings anderer Container:

docker ps --format "table {{.Names}}\t{{.Ports}}"

Lösungen:

Option 1: Anderes Host-Port-Mapping

# Ursprünglich
docker run -p 8080:8080 my-app

# Anderen Port wählen
docker run -p 8081:8080 my-app

Option 2: Blockierenden Prozess beenden

# Prozess-ID ermitteln
lsof -i :8080

# Prozess beenden
kill -9 <PID>

Option 3: Konfliktierenden Container stoppen

docker stop <conflicting_container>

Hinweis: Bei --network=host nutzt der Container das Host-Netzwerk direkt – Portkonflikte sind häufiger. Container-Ports dürfen dann nicht mit Host-Ports kollidieren.

Szenario 4: Unzureichende Berechtigungen

Typische Anzeichen:

  • Exit Code 1
  • Logs mit Permission denied, Operation not permitted, chown: changing ownership failed

Praxisbeispiel:

MongoDB-Container mit gemountetem Datenverzeichnis auf dem Host:

chown: changing ownership of '/data/db': Permission denied

Das Host-Verzeichnis gehörte root; MongoDB im Container lief als User mongodb (UID 999) ohne Schreibrechte.

Troubleshooting:

Host-Verzeichnisberechtigungen:

ls -la /host/data/path

User im Container:

docker run -it my-app /bin/bash
whoami
id

SELinux prüfen (CentOS/RHEL):

getenforce

Lösungen:

Option 1: Host-Verzeichnisberechtigungen anpassen

# Alle Rechte (unsicher, nur Entwicklung)
chmod 777 /host/data/path

# Sicherer: Owner anpassen
chown -R 999:999 /host/data/path  # 999 = UID im Container

Option 2: Privileged Mode (vorsichtig)

docker run --privileged=true my-app

Gibt dem Container fast alle Host-Rechte – Sicherheitsrisiko, in Produktion nicht empfohlen.

Option 3: User explizit setzen

docker run --user 1000:1000 my-app  # UID/GID vom Host

Option 4: SELinux

# Option 1: Z-Label (Host-Dateilabel anpassen)
docker run -v /host/path:/container/path:Z my-app

# Option 2: z-Label (geteiltes Label)
docker run -v /host/path:/container/path:z my-app

# Option 3: SELinux temporär deaktivieren (Produktion nicht empfohlen)
setenforce 0

Szenario 5: Abhängiger Dienst nicht bereit

Typische Anzeichen:

  • Exit Code 1
  • Logs mit DB-Verbindungsfehlern, Redis-Timeout
  • Connection refused, ECONNREFUSED, could not connect to server

Praxisbeispiel:

Microservices per docker-compose – App-Container hängt von MySQL ab. Beide starten fast gleichzeitig, App schlägt fehl:

Error: connect ECONNREFUSED 172.18.0.2:3306

MySQL-Container lief, aber der Dienst initialisierte noch – die App startete zu früh, Verbindung fehlgeschlagen, Exit.

Troubleshooting:

Abhängige Dienste prüfen:

docker ps  # laufen die benötigten Container?

Netzwerk testen:

docker exec my-app ping database
docker exec my-app telnet database 3306
docker exec my-app nc -zv database 3306

Docker-Netzwerk:

docker network ls
docker network inspect <network_name>

Lösungen:

Option 1: Healthcheck und depends_on in docker-compose

version: '3.8'
services:
  database:
    image: mysql:8.0
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5

  app:
    image: my-app
    depends_on:
      database:
        condition: service_healthy  # warten bis DB healthy

Option 2: Retry-Logik in der Anwendung

// Node.js-Beispiel
async function connectWithRetry(maxRetries = 5) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      await db.connect();
      console.log('Database connected');
      return;
    } catch (err) {
      console.log(`Connection failed, retrying... (${i+1}/${maxRetries})`);
      await new Promise(resolve => setTimeout(resolve, 5000));
    }
  }
  throw new Error('Failed to connect to database');
}

Option 3: Warte-Skript vor dem Start

Z. B. wait-for-it.sh im Dockerfile:

# Im Dockerfile
COPY wait-for-it.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/wait-for-it.sh

# Beim Start
CMD ["wait-for-it.sh", "database:3306", "--", "node", "app.js"]

Option 4: Restart-Policy

docker run --restart=on-failure:3 my-app  # max. 3 Neustarts

In docker-compose:

services:
  app:
    restart: on-failure

Kombinierbar: Healthcheck + Retry in der App + Restart-Policy.

Präventive Maßnahmen und Best Practices

Bisher ging es um Reparatur nach dem Fehler. Mit der richtigen Konfiguration von Anfang an vermeiden oder überstehen viele Probleme automatisch.

Healthcheck (HEALTHCHECK) konfigurieren

Healthchecks prüfen regelmäßig, ob der Container wirklich funktioniert – nicht nur, ob der Prozess noch läuft.

Im Dockerfile:

FROM nginx:alpine

# Alle 30 s prüfen, Timeout 3 s, 3 Fehlschläge = unhealthy
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
  CMD curl -f http://localhost/ || exit 1

Web-Service – HTTP-Endpunkt:

HEALTHCHECK --interval=30s --timeout=5s --start-period=40s \
  CMD curl -f http://localhost:8080/health || exit 1

Datenbank – spezifische Befehle:

# MySQL
HEALTHCHECK CMD mysqladmin ping -h localhost || exit 1

# PostgreSQL
HEALTHCHECK CMD pg_isready -U postgres || exit 1

# Redis
HEALTHCHECK CMD redis-cli ping || exit 1

Vorteile:

  • Kubernetes/Swarm starten oder verschieben Container basierend auf Health-Status
  • docker-compose depends_on wartet auf echte Bereitschaft
  • Monitoring kann auf Health-Status alarmieren

Health-Status anzeigen:

docker ps  # STATUS-Spalte zeigt health
docker inspect --format='{{.State.Health.Status}}' <container_id>

Restart-Policy setzen

Restart-Policies ermöglichen automatische Wiederherstellung – ohne nächtlichen manuellen Eingriff.

Vier Strategien:

no (Standard): Kein automatischer Neustart

docker run --restart=no my-app

Für Einmal-Jobs.

on-failure[:max-retries]: Nur bei abnormaler Beendigung

docker run --restart=on-failure:5 my-app  # max. 5 Versuche

Nur bei Exit-Code ≠ 0.

always: Immer neu starten

docker run --restart=always my-app

Für dauerhaft laufende Dienste. Startet auch nach Docker-Daemon-Neustart – auch nach manuellem docker stop.

unless-stopped: Immer neu starten, außer manuell gestoppt

docker run --restart=unless-stopped my-app

Wie always, aber nach manuellem docker stop kein Auto-Start beim Daemon-Neustart. Meine bevorzugte Strategie.

Wichtig:

  1. 10-Sekunden-Regel: Restart-Policy greift erst, wenn der Container mindestens 10 Sekunden lief – Schutz vor Endlosschleifen bei Konfigurationsfehlern.
  2. Endlos-Restart-Falle: Bei Portkonflikt o. Ä. wachsen Logs explosionsartig – Log-Rotation mitdenken.

Policy für laufende Container ändern:

docker update --restart=unless-stopped <container_id>

In docker-compose:

services:
  web:
    image: nginx
    restart: unless-stopped  # Produktion empfohlen

  worker:
    image: my-worker
    restart: on-failure

Log-Management: Speicherplatz schonen

Docker speichert Container-Logs standardmäßig als JSON-Dateien – über Monate können das Dutzende GB werden. Ich habe Produktionsserver erlebt, die wegen voller Docker-Logs ausfielen.

Log-Rotation (empfohlen):
/etc/docker/daemon.json anlegen oder bearbeiten:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

Docker neu starten:

sudo systemctl restart docker

Pro Container maximal ca. 30 MB Logs (10 MB × 3), alte Dateien werden gelöscht.

Pro Container:

docker run --log-opt max-size=10m --log-opt max-file=3 my-app

In docker-compose:

services:
  app:
    image: my-app
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

Weitere Treiber:

  • syslog: System-Log
  • journald: systemd journal
  • fluentd: zentralisierte Log-Verwaltung
  • none: keine Logs (nicht empfohlen)

Log-Pfad und Größe:

docker inspect --format='{{.LogPath}}' <container_id>
du -h $(docker inspect --format='{{.LogPath}}' <container_id>)

Monitoring und Alarme: Probleme früh erkennen

Nicht erst reagieren, wenn Container bereits down sind – Monitoring verhindert viele Incidents.

Basis: docker stats

docker stats  # alle Container in Echtzeit
docker stats <container_id>  # einzelner Container

CPU, Speicher, Netzwerk- und Disk-I/O. Steigt Speicher dauerhaft, mögliches Leck – früh handeln.

Produktion: Prometheus + Grafana

# docker-compose.yml
services:
  prometheus:
    image: prom/prometheus
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - "9090:9090"

  grafana:
    image: grafana/grafana
    ports:
      - "3000:3000"

  cadvisor:  # Container-Metriken
    image: google/cadvisor
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:ro
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro
    ports:
      - "8080:8080"

Alarmregeln für Speicher > 80 %, häufige Neustarts usw.

Einfach: Cron-Skript

#!/bin/bash
# check-containers.sh

EXITED=$(docker ps -a -f "status=exited" --format "{{.Names}}")

if [ -n "$EXITED" ]; then
  echo "Warning: The following containers are exited:"
  echo "$EXITED"
  # E-Mail oder Push-Benachrichtigung
fi

Crontab alle 5 Minuten:

*/5 * * * * /path/to/check-containers.sh

Checkliste für Produktionsumgebungen

Referenz-Konfiguration für stabile Container:

version: '3.8'
services:
  web:
    image: my-web-app:latest

    # Restart-Policy
    restart: unless-stopped

    # Ressourcenlimits
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 1G
        reservations:
          memory: 512M

    # Healthcheck
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost/health"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 40s

    # Log-Management
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

    # Umgebungsvariablen (Secrets für sensible Daten)
    environment:
      - NODE_ENV=production

    # Port-Mapping
    ports:
      - "8080:8080"

    # Abhängigkeiten
    depends_on:
      database:
        condition: service_healthy

  database:
    image: postgres:14
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5
    volumes:
      - db-data:/var/lib/postgresql/data
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

volumes:
  db-data:

Mit dieser Konfiguration: automatischer Neustart, Ressourcenlimits, kontrollierte Logs, Monitoring – deutlich ruhiger schlafen.

Fazit

Docker-Container-Startfehler sind kein Grund zur Panik – fehlende Systematik schon.

Kernpunkte:

Exit-Codes verstehen: 137 → Speicher; 1 → Konfiguration oder Abhängigkeiten. Exit-Codes sind Hinweise von Docker.

Vier-Schritte-Methode:

  1. Container-Status (docker ps -a)
  2. Logs (docker logs)
  3. Konfiguration (docker inspect)
  4. Interaktive Verifikation (docker run -it)

Über 90 % der Fälle lösen sich in Schritt 2.

Fünf typische Szenarien: Konfigurationsfehler, Speichermangel, Portkonflikt, Berechtigungen, Abhängigkeiten nicht bereit.

Prävention: Healthchecks, Restart-Policy, Log-Rotation, Monitoring – Stabilität und automatische Erholung.

Schnell-Checkliste zum Speichern:

Docker-Container-Startfehler – Checkliste

□ Schritt 1: docker ps -a – Status und Exit-Code
□ Schritt 2: docker logs <container_id> – detaillierte Logs
□ Schritt 3: docker inspect <container_id> – Konfiguration
□ Schritt 4: docker run -it <image> – interaktive Verifikation

Schnelle Zuordnung:
- Exit Code 1 + „No such file" → Mount-Pfade und Konfiguration
- Exit Code 1 + „port already allocated" → Portkonflikt
- Exit Code 1 + „Permission denied" → Berechtigungen und SELinux
- Exit Code 1 + „Connection refused" → Abhängige Dienste
- Exit Code 137 + OOMKilled=true → Speicherlimit erhöhen
- Exit Code 127 → CMD/ENTRYPOINT-Pfad prüfen

Prävention:
□ HEALTHCHECK konfigurieren
□ restart-Policy (empfohlen: unless-stopped)
□ Log-Rotation (max-size + max-file)
□ Ressourcenlimits (-m Speicher)
□ Monitoring (docker stats oder Prometheus)

Wenn dieser Artikel geholfen hat: bookmarken und beim nächsten Container-Problem parat halten. Besondere Fälle gerne in den Kommentaren teilen – vielleicht hilft es anderen.

Mögen Ihre Container dauerhaft Up and Running bleiben – und Sie keinen Freitagabend-Alarm mehr wegen abgestürzter Container bekommen!

Vollständiger Troubleshooting-Workflow bei fehlgeschlagenen Docker-Container-Starts

Systematische Fehlerbehebung mit Erklärung der Exit-Codes 137/1, Vier-Schritte-Methode und Lösungen für fünf typische Fehlerszenarien

⏱️ Estimated time: 30 min

  1. 1

    Step 1: Exit-Codes und Schweregrad des Problems verstehen

    Bedeutung der Exit-Codes:
    • Exit Code 0: Normaler Exit, Aufgabe abgeschlossen
    • Exit Code 1: Anwendungsfehler, Startbefehl fehlgeschlagen (am häufigsten)
    • Exit Code 137: OOM Killer, Speichermangel
    • Exit Code 127: Befehl nicht gefunden
    • Exit Code 139: Segmentation Fault (C/C++-Programme)

    Schweregrad:
    • In der Produktion waren alle Container der vier Kernservices im Exited-Status
    • Container beenden sich sofort nach dem Start – systematische Fehlerbehebung erforderlich

    Schnelle Zuordnung:
    • Exit Code 1 + No such file → Mount-Pfade und Konfigurationsdateien prüfen
    • Exit Code 1 + port already allocated → Portkonflikt prüfen
    • Exit Code 1 + Permission denied → Dateiberechtigungen und SELinux prüfen
    • Exit Code 1 + Connection refused → Prüfen, ob abhängige Dienste bereit sind
    • Exit Code 137 + OOMKilled=true → Speicherlimit erhöhen
  2. 2

    Step 2: Vier-Schritte-Methode

    Vier-Schritte-Methode:

    Schritt 1: Container-Status und Exit-Code prüfen
    • docker ps -a – Status und Exit-Code anzeigen
    • Spalten State und Exit Code beachten

    Schritt 2: Detaillierte Logs prüfen
    • docker logs <container_id> – vollständige Logs
    • docker logs --tail 50 <container_id> – letzte 50 Zeilen
    • docker logs -f <container_id> – Logs in Echtzeit verfolgen

    Schritt 3: Konfiguration prüfen
    • docker inspect <container_id> – Konfiguration anzeigen
    • Felder Cmd, Entrypoint, Env usw. prüfen

    Schritt 4: Interaktive Verifikation
    • docker run -it <image> – interaktiv testen
    • Startbefehl manuell ausführen und Fehlermeldungen beobachten
  3. 3

    Step 3: Fünf typische Fehlerszenarien und Lösungen

    Fünf typische Fehlerszenarien:

    Szenario 1: Falscher Startbefehl
    • CMD/ENTRYPOINT falsch konfiguriert
    • Lösung: Startbefehl korrigieren, Pfade und Parameter prüfen

    Szenario 2: Fehlerhafte Konfigurationsdatei
    • Falscher Pfad, falsches Format
    • Lösung: Konfigurationsdatei korrigieren, Pfade und Format validieren

    Szenario 3: Abhängiger Dienst nicht bereit
    • Datenbank nicht gestartet
    • Lösung: Auf Bereitschaft warten (depends_on + healthcheck)

    Szenario 4: Speichermangel
    • OOM Killer beendet Prozess
    • Lösung: Speicherlimit erhöhen (--memory) oder Speichernutzung optimieren

    Szenario 5: Portkonflikt
    • Port bereits belegt
    • Lösung: Port-Mapping ändern (-p 8081:80) oder blockierenden Prozess beenden

    Best Practices:
    • Healthchecks in docker-compose konfigurieren
    • depends_on + healthcheck für abhängige Dienste
    • Angemessene Ressourcenlimits setzen (Speicher, CPU)

FAQ

Warum beendet sich ein Docker-Container sofort nach dem Start?
Häufige Ursachen für sofortigen Exit:

Bedeutung der Exit-Codes:
• Exit Code 1: Anwendungsfehler, Startbefehl fehlgeschlagen (am häufigsten)
• Exit Code 137: OOM Killer, Speichermangel
• Exit Code 0: Normaler Exit, Aufgabe abgeschlossen

Schnelle Zuordnung:
• Exit Code 1 + No such file → Mount-Pfade und Konfigurationsdateien prüfen
• Exit Code 1 + port already allocated → Portkonflikt prüfen
• Exit Code 1 + Permission denied → Dateiberechtigungen und SELinux prüfen
• Exit Code 1 + Connection refused → Prüfen, ob abhängige Dienste bereit sind
• Exit Code 137 + OOMKilled=true → Speicherlimit erhöhen

Troubleshooting: Vier-Schritte-Methode (Logs prüfen → Exit-Code prüfen → Startbefehl prüfen → Ressourcenlimits prüfen)
Wie behebt man fehlgeschlagene Docker-Container-Starts?
Vier-Schritte-Methode:
1) Container-Logs prüfen: docker logs container-name
2) Exit-Code prüfen: docker ps -a
3) Startbefehl prüfen: docker inspect container-name
4) Ressourcenlimits prüfen: docker stats

Detaillierte Schritte:
• Schritt 1: docker ps -a – Status und Exit-Code anzeigen
• Schritt 2: docker logs <container_id> – detaillierte Logs
• Schritt 3: docker inspect <container_id> – Konfiguration prüfen
• Schritt 4: docker run -it <image> – interaktive Verifikation
Was ist der Unterschied zwischen Exit Code 1 und Exit Code 137?
Bedeutung der Exit-Codes:
• Exit Code 1: Anwendungsfehler, Startbefehl fehlgeschlagen
• Exit Code 137: OOM Killer, Speichermangel
• Exit Code 0: Normaler Exit
• Andere Exit-Codes: je nach Anwendung

Häufige Ursachen für Exit Code 1:
• Falscher Startbefehl (CMD/ENTRYPOINT falsch konfiguriert)
• Fehlerhafte Konfigurationsdatei (falscher Pfad, falsches Format)
• Abhängiger Dienst nicht bereit (Datenbank nicht gestartet)
• Portkonflikt (Port bereits belegt)

Häufige Ursachen für Exit Code 137:
• Speichermangel (OOM Killer)
• Speicherlimit erhöhen (--memory)
Wie löst man typische Probleme bei fehlgeschlagenen Container-Starts?
Fünf typische Fehlerszenarien:
1) Falscher Startbefehl (CMD/ENTRYPOINT falsch konfiguriert)
2) Fehlerhafte Konfigurationsdatei (falscher Pfad, falsches Format)
3) Abhängiger Dienst nicht bereit (Datenbank nicht gestartet)
4) Speichermangel (OOM Killer)
5) Portkonflikt (Port bereits belegt)

Lösungen:
• Startbefehl korrigieren
• Konfigurationsdatei korrigieren
• Auf Bereitschaft abhängiger Dienste warten (depends_on + healthcheck)
• Speicherlimit erhöhen (--memory)
• Port-Mapping ändern (-p 8081:80)
• Healthchecks in docker-compose konfigurieren

14 Min. Lesezeit · Veröffentlicht am: 18. Dez. 2025 · Aktualisiert am: 14. Juli 2026

Kommentare

Melde dich mit GitHub an, um einen Kommentar zu hinterlassen

Easton BlogEaston Blog