SSD Nodes Learn Hosting plans →
Anleitungen Matt ConnorVon Matt Connor · Aktualisiert 2026-08-25

Docker Compose: Bind Mount oder Named Volume?

Erfahren Sie, wann Bind Mounts für Konfigurationen und Named Volumes für Daten sinnvoll sind, welche Rechtefehler auftreten und wie Sie Volumes prüfen, sichern und migrieren.

Bind mount oder Named Volume: die kurze Antwort

Docker-Compose-Volumes gibt es in zwei Varianten. Die Wahl hängt davon ab, wer die Dateien verwaltet. Verwenden Sie ein Bind Mount für Dateien, die Sie selbst schreiben und lesen, zum Beispiel Konfigurationen, Templates und statische Websites. Verwenden Sie ein Named Volume für Daten, die der Anwendung gehören, zum Beispiel Datenbankdateien, Suchindizes und hochgeladene Medien. Ein Bind Mount verweist auf einen Pfad auf dem Host, den Sie in einem Editor öffnen können. Ein Named Volume ist Speicher, den Docker für Sie erstellt und verwaltet. Sie greifen über Docker darauf zu.

Beide Varianten stehen unter demselben Schlüssel volumes: innerhalb eines Dienstes. Deshalb werden sie häufig verwechselt. Der Unterschied liegt in der linken Seite des Doppelpunkts. Beginnt die linke Seite mit . oder /, handelt es sich um einen Host-Pfad und damit um ein Bind Mount. Alles andere ist ein Name und damit ein Named Volume. Dieser Name muss zusätzlich im Block volumes: auf oberster Ebene deklariert werden.

Die beiden Syntaxvarianten in einer Compose-Datei

services:
  db:
    image: postgres:17
    environment:
      POSTGRES_PASSWORD: changeme
    volumes:
      - pgdata:/var/lib/postgresql/data
  web:
    image: nginx:1.27
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./site:/usr/share/nginx/html:ro

volumes:
  pgdata:

pgdata:/var/lib/postgresql/data ist ein benanntes Volume. ./nginx.conf:/etc/nginx/nginx.conf ist ein Bind-Mount, und :ro bindet es schreibgeschützt ein. Das ist der richtige Standard für Konfigurationsdateien, die ein Container niemals überschreiben sollte. Wenn der Eintrag volumes: auf oberster Ebene fehlt, bricht Compose mit service "db" refers to undefined volume pgdata ab.

Starten Sie die Umgebung und listen Sie auf, was Docker erstellt hat:

docker compose up -d
docker volume ls

Das Volume heißt nicht pgdata. Es heißt <project>_pgdata, wobei der Projektname standardmäßig dem Namen des Verzeichnisses entspricht, in dem die Compose-Datei liegt. Ein Verzeichnis namens myapp ergibt myapp_pgdata. Das ist wichtig, weil eine Umbenennung des Verzeichnisses ein neues, leeres Volume erzeugt. Die Anwendung sieht dann so aus, als hätte sie ihre Daten verloren. Das ist nicht der Fall: Das alte Volume wird weiterhin von docker volume ls aufgelistet. Legen Sie den Namen mit name: in der Compose-Datei fest oder setzen Sie COMPOSE_PROJECT_NAME, wenn das Verzeichnis verschoben werden könnte. Einstellungen dieser Art gehören zu Ihren übrigen Compose-Umgebungsdateien und Secrets.

Warum Berechtigungsfehler nur bei Bind-Mounts auftreten

Das ist der wichtigste praktische Unterschied. Er ergibt sich aus einer Regel: Ein benannter Volume, der bei der ersten Verwendung leer ist, wird aus dem Image befüllt. Ein Bind-Mount wird niemals auf diese Weise befüllt.

Wenn Docker einen leeren benannten Volume über ein Verzeichnis mountet, das im Image bereits Inhalte enthält, kopiert Docker diese Inhalte in den Volume. Dabei bleiben Eigentümer und Berechtigungen erhalten, die im Image festgelegt sind. Das offizielle Postgres-Image enthält /var/lib/postgresql/data, das dem eigenen Benutzer postgres gehört. Der Volume gehört dadurch derselben numerischen ID, und die Datenbank startet.

Ein Bind-Mount verhält sich umgekehrt. Der Inhalt auf dem Host ist der Inhalt, den der Container sieht, einschließlich der Eigentümer. Der Inhalt des Images an diesem Pfad ist nicht sichtbar. Wenn das Hostverzeichnis nicht vorhanden ist, erstellt der Docker-Daemon es. Der Daemon läuft als root, daher erhalten Sie ein Verzeichnis, das root:root gehört. Ein Containerprozess, der als Nicht-root-Benutzer läuft, kann dann nicht darin schreiben:

PermissionError: [Errno 13] Permission denied: '/data/app.db'

Die Lösung besteht darin, die numerischen IDs abzugleichen. Der Eigentümer eines Bind-Mounts wird anhand der numerischen Benutzer-ID verglichen, nicht anhand des Namens, weil der Container ein eigenes /etc/passwd hat. Ein Benutzer namens app im Container hat auf dem Host keine Bedeutung. Uid 1000 bedeutet auf beiden Seiten uid 1000.

id -u
mkdir -p ./data
docker compose exec web id
sudo chown -R 1000:1000 ./data

docker compose exec web id gibt die uid aus, unter der der Containerprozess tatsächlich läuft. Passen Sie das Hostverzeichnis an diese Nummer an, oder legen Sie mit user: "1000:1000" im Dienst fest, dass der Container unter Ihrer Nummer läuft. user: festzulegen ist für eine selbst entwickelte Anwendung sauberer. Das Hostverzeichnis mit chown zu ändern ist bei einem Image, das Sie nicht selbst erstellt haben, sicherer. Einige Images starten zunächst einen Entrypoint als root, geben anschließend Berechtigungen ab und erwarten darunter bestimmte Eigentümer.

Zwei weitere Stolperfallen sollten Sie kennen. Auf Fedora, RHEL und anderen Systemen mit aktiviertem SELinux (security-enhanced Linux) wird ein Bind-Mount verweigert, bis er neu gelabelt wurde. Fügen Sie daher :z für einen Pfad hinzu, der zwischen Containern geteilt wird, oder :Z für einen Pfad, den nur ein Container verwenden soll. Die Schreibweise lautet - ./data:/data:Z. Ein Bind-Mount für eine einzelne Datei statt für ein Verzeichnis schlägt außerdem fehl, wenn ein Editor die Datei ersetzt, anstatt sie direkt zu überschreiben. Der Mount folgt dem ursprünglichen Inode. Der Container sieht dann weiterhin den alten Inhalt, bis Sie ihn neu starten. Mounten Sie das übergeordnete Verzeichnis, wenn die Datei häufig bearbeitet wird.

Leistung: Wo der Unterschied tatsächlich besteht

Auf einem Linux-Server durchlaufen beide Varianten denselben Kernel-Pfad. Der Durchsatzunterschied ist daher so gering, dass Sie die Auswahl nicht davon abhängig machen sollten. Named Volumes mit dem Standardtreiber local liegen wie der restliche Docker-Datenbestand im selben Dateisystem unter /var/lib/docker/volumes/. Ein Bind-Mount liegt dagegen an dem von Ihnen angegebenen Speicherort.

Der Unterschied zeigt sich bei Docker Desktop für macOS und Windows. Dort laufen Container innerhalb einer virtuellen Maschine. Ein Bind-Mount überträgt Daten vom Host-Dateisystem über eine Dateifreigabeschicht in diese virtuelle Maschine. Arbeitslasten mit vielen kleinen Dateioperationen, beispielsweise ein Node.js-Abhängigkeitsbaum oder ein Cache eines PHP-Frameworks, werden dadurch spürbar langsamer. Named Volumes bleiben innerhalb der virtuellen Maschine und verursachen diesen zusätzlichen Aufwand nicht. Deshalb binden viele Compose-Dateien für die Entwicklung das Quellverzeichnis ein, deklarieren aber für node_modules ein Named Volume.

Der andere tatsächliche Unterschied betrifft den Speicherort der Daten. Ein Bind-Mount nach /mnt/backup legt die Daten auf diesem Datenträger ab. Ein Named Volume wird auf dem Dateisystem gespeichert, das /var/lib/docker enthält. Auf einem VPS ist das normalerweise der Root-Datenträger. Eine Datenbank, die innerhalb eines Named Volumes wächst, füllt denselben Datenträger, auf dem auch Ihre System-Logs liegen. Prüfen Sie dies, bevor daraus ein Incident wird:

docker system df -v
df -h /var/lib/docker

docker system df -v listet alle Volumes mit ihrer Größe auf und markiert diejenigen, auf die kein Container mehr verweist.

Inspecting a named volume

Ein benanntes Volume ist keine Blackbox. Fragen Sie Docker nach seinem Speicherort:

docker volume inspect myapp_pgdata

Das Feld Mountpoint enthält einen tatsächlichen Pfad auf dem Host, normalerweise /var/lib/docker/volumes/myapp_pgdata/_data. Sie können ihn mit sudo ls auslesen. Das ist für eine schnelle Prüfung hilfreich. Sie sollten diesen Pfad jedoch nicht als Ort zum Bearbeiten von Dateien behandeln. Wenn Sie dort als root schreiben, tritt das oben beschriebene Problem mit den Besitzrechten erneut auf. Außerdem ist der Pfad ein Detail des local-Treibers, das andere Volume-Treiber nicht gemeinsam haben.

Die sichere Methode für den Zugriff auf den Inhalt ist ein kurzlebiger Container, der das Volume einbindet:

docker run --rm -v myapp_pgdata:/vol alpine ls -la /vol

Das funktioniert mit jedem Treiber. Der Container sieht dieselben Berechtigungen wie der eigentliche Container. Durch --rm bleiben keine Dateien oder anderen Änderungen zurück.

Jeden Typ sichern

Ein Bind-Mount ist ein gewöhnliches Verzeichnis. Jedes dateibasierte Backup-Tool kann es daher bereits sichern. Geben Sie den Host-Pfad als Quelle für das Backup an. Damit ist die Sicherung abgeschlossen. Für ein benanntes Volume ist ein zusätzlicher Schritt erforderlich, weil das Tool auf dessen Inhalt zugreifen muss. Binden Sie das Volume und ein Host-Verzeichnis in denselben kurzlebigen Container ein. Schreiben Sie anschließend ein Archiv:

docker run --rm \
  -v myapp_pgdata:/data:ro \
  -v "$PWD":/backup \
  alpine tar czf /backup/pgdata.tar.gz -C /data .

Stellen Sie die Daten wieder her, indem Sie sie in ein neues Volume zurückschreiben:

docker volume create myapp_pgdata_restored
docker run --rm \
  -v myapp_pgdata_restored:/data \
  -v "$PWD":/backup \
  alpine tar xzf /backup/pgdata.tar.gz -C /data

tar bewahrt die numerischen Eigentümer-IDs auf, wenn der Befehl als root im Container ausgeführt wird. Dadurch bleibt das wiederhergestellte Volume für die Anwendung verwendbar.

Für beide Typen gilt eine wichtige Warnung. Wenn Sie die Dateien einer laufenden Datenbank kopieren, enthält das Archiv einen sich während des Kopiervorgangs ändernden Datenbestand. Bei der Wiederherstellung kann dadurch ein beschädigter Zustand entstehen. Stoppen Sie den Dienst zuerst. Alternativ können Sie die Daten mit dem eigenen Tool der Datenbank exportieren, wie in docker compose exec -T db pg_dump -U postgres appdb > appdb.sql gezeigt. Dadurch entsteht eine einfache Datei, die Sie anschließend zusammen mit Ihren Compose-Dateien in eine normale verschlüsselte restic-Backup-Routine aufnehmen können.

Bind-Mount zu einem benannten Volume migrieren

Der Vorgang ist ein Kopieren, kein Umbenennen, und dauert etwa eine Minute.

docker compose down
docker volume create myapp_pgdata
docker run --rm \
  -v "$PWD/data":/from \
  -v myapp_pgdata:/to \
  alpine sh -c 'cp -a /from/. /to/'

cp -a behält Eigentümer, Berechtigungen und Zeitstempel bei. Der Container-Benutzer, der das alte Verzeichnis lesen konnte, kann daher auch das neue Volume lesen. Ändern Sie anschließend den Dienst so, dass er pgdata:/var/lib/postgresql/data verwendet, fügen Sie pgdata zum übergeordneten volumes:-Block hinzu, führen Sie docker compose up -d aus und prüfen Sie die Anwendungslogs, bevor Sie das alte Verzeichnis löschen. In die andere Richtung verwenden Sie denselben Befehl, wobei /from und /to vertauscht werden.

Beachten Sie beim Testen einen Punkt. docker compose down lässt benannte Volumes unverändert. docker compose down -v löscht dagegen jedes benannte Volume, das im Projekt deklariert ist. Dieser Vorgang kann nicht rückgängig gemacht werden. Ein Bind-Mount bleibt in beiden Fällen erhalten, weil Docker dieses Verzeichnis nie verwaltet hat. Wenn die Lifecycle-Befehle für Sie noch neu sind, erklärt der Grundlagenleitfaden zu Docker Compose für einen VPS deren Verwendung.

Auswahl für jeden Dienst

Fragen Sie, wer die Datei schreibt. Konfigurationen, die Sie in einem Texteditor bearbeiten und in Git einchecken, gehören in einen Bind-Mount, der unter :ro eingehängt wird. So bleiben sie sichtbar und versioniert. Anwendungsdaten, die Sie niemals manuell öffnen, gehören in ein benanntes Volume. Docker setzt die Berechtigungen dort korrekt, und die Daten hängen nicht von einem Hostpfad ab.

Der Mischfall sind Mediendateien. Eine Fotobibliothek wird von der Anwendung geschrieben, aber auch von Ihnen verwaltet. Außerdem ist sie oft groß genug, dass Sie dafür einen bestimmten Datenträger verwenden möchten. Binden Sie sie in einen Pfad auf diesem Datenträger ein, und legen Sie den Eigentümer einmalig bewusst fest. Dieses Muster hat sich bei den meisten Self-Hosting-Stacks etabliert: benannte Volumes für Datenbanken und Caches, Bind-Mounts für die Konfiguration und für das große Verzeichnis, das Ihnen wichtig ist. Ein Support-Desk wie Chatwoot auf einem VPS passt genau in dieses Muster: Postgres liegt in einem benannten Volume, die hochgeladenen Anhänge liegen in einem Pfad, den Sie in einer Backup-Konfiguration angeben können.

FAQ

Was ist der Unterschied zwischen einem Bind-Mount und einem benannten Volume?

Ein Bind-Mount bindet einen Pfad auf dem Host in den Container ein. Beide Seiten sehen dadurch dasselbe Verzeichnis, und Sie können es mit normalen Werkzeugen bearbeiten. Ein benanntes Volume ist Speicher, den Docker erstellt und verwaltet. Es wird über seinen Namen referenziert und im volumes:-Block auf oberster Ebene deklariert. Der praktische Unterschied betrifft die Zuständigkeit: Verwenden Sie Bind-Mounts für Konfigurationsdateien, die Sie pflegen, und benannte Volumes für Daten, die die Anwendung verwaltet.

Warum erhalte ich bei einem Bind-Mount "permission denied", aber nicht bei einem benannten Volume?

Ein leeres benanntes Volume wird mit den Dateien aus dem Image initialisiert. Es übernimmt dadurch die im Image festgelegten Besitzrechte, sodass der Container-Benutzer darauf schreiben kann. Ein Bind-Mount zeigt das Host-Verzeichnis genau so an, wie es auf dem Host vorliegt. Wenn Docker dieses Verzeichnis erstellen musste, gehört es root. Führen Sie docker compose exec <service> id aus, um die numerische ID des Container-Benutzers anzuzeigen. Setzen Sie anschließend mit sudo chown -R <uid>:<gid> den Besitzer des Host-Verzeichnisses oder konfigurieren Sie user: "1000:1000" für den Dienst.

Wo speichert Docker benannte Volumes auf der Festplatte?

Mit dem standardmäßigen local-Treiber liegen sie unter /var/lib/docker/volumes/<volume>/_data. docker volume inspect <volume> gibt den exakten Mountpoint aus. Lesen Sie diesen Pfad, wenn Sie etwas prüfen müssen. Schreiben Sie dort jedoch nur über einen Container, weil eine Bearbeitung als root auf dem Host die Besitzrechte auf eine Weise ändert, die der Container nicht erwartet.

Wie sichere ich ein benanntes Volume?

Starten Sie einen kurzlebigen Container, in den sowohl das Volume als auch ein Host-Verzeichnis eingebunden sind. Archivieren Sie die Daten anschließend mit docker run --rm -v myvol:/data:ro -v "$PWD":/backup alpine tar czf /backup/myvol.tar.gz -C /data . von einem Verzeichnis in das andere. Erstellen Sie bei einer Datenbank stattdessen mit dem eigenen Werkzeug der Datenbank einen Dump. Eine Dateikopie während laufender Schreibvorgänge kann in einem beschädigten Zustand wiederhergestellt werden.

Löscht docker compose down meine Volumes?

docker compose down entfernt Container und Netzwerke, lässt benannte Volumes jedoch bestehen. docker compose down -v löscht zusätzlich jedes benannte Volume, das im Projekt deklariert ist, dauerhaft. Bind-Mounts werden von keinem der beiden Befehle entfernt, weil das Verzeichnis dem Host und nicht Docker gehört.