SSD Nodes Learn 8GB RAM — $66/Jahr
Anleitungen Matt ConnorVon Matt Connor · Aktualisiert 2026-08-01

Docker Compose: Bind-Mount oder benanntes Volume?

Erfahren Sie, wann Bind-Mounts oder benannte Volumes passen, welche Dateirechte Probleme machen und wie Sie Docker-Daten prüfen, sichern und migrieren.

Bind-Mount oder benanntes Volume: die kurze Antwort

Docker-Compose-Volumes gibt es in zwei Varianten. Die Wahl hängt davon ab, wer die Dateien verwaltet. Verwenden Sie einen Bind-Mount für Dateien, die Sie selbst schreiben und lesen, zum Beispiel Konfigurationen, Vorlagen und statische Websites. Verwenden Sie ein benanntes 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 benanntes Volume ist Speicher, den Docker für Sie erstellt und verwaltet. Sie greifen über Docker darauf zu.

Beide werden unter demselben Schlüssel volumes: innerhalb eines Dienstes angegeben. Deshalb werden sie häufig verwechselt. Der Unterschied liegt in der linken Seite des Doppelpunkts. Eine linke Seite, die mit . oder / beginnt, ist ein Hostpfad. Daher handelt es sich um einen Bind-Mount. Alles andere ist ein Name. Daher handelt es sich um ein benanntes Volume. Dieser Name muss außerdem 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 eine Konfiguration, die ein Container niemals überschreiben soll. Wenn der übergeordnete Eintrag volumes: fehlt, beendet sich Compose mit service "db" refers to undefined volume pgdata.

Starten Sie die Anwendung 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, das die Compose-Datei enthält. Ein Verzeichnis mit dem Namen myapp ergibt myapp_pgdata. Das ist wichtig, weil das Umbenennen des Verzeichnisses ein neues, leeres Volume erzeugt und es so aussieht, als hätte die Anwendung 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 möglicherweise verschoben wird. Einstellungen dieser Art gehören zusammen mit Ihren anderen Compose-Umgebungsdateien und Secrets verwaltet.

Warum Berechtigungsfehler nur bei Bind-Mounts auftreten

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

Wenn Docker ein leeres benanntes Volume über ein Verzeichnis mountet, das im Image bereits Inhalte enthält, kopiert Docker diese Inhalte in das Volume. Dabei bleiben die Eigentümer und Berechtigungen erhalten, die im Image festgelegt sind. Das offizielle Postgres-Image liefert /var/lib/postgresql/data aus, das dem eigenen Benutzer postgres gehört. Daher gehört das Volume anschließend derselben numerischen ID, und die Datenbank startet.

Ein Bind-Mount funktioniert umgekehrt. Der Container sieht genau die Inhalte des Hosts, einschließlich der Eigentümer. Die Inhalte des Images an diesem Pfad sind verborgen. Wenn das Hostverzeichnis nicht existiert, 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 Benutzer ohne root-Rechte läuft, kann dann nicht hineinschreiben:

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

Die Lösung besteht darin, die numerischen Werte anzugleichen. Bei einem Bind-Mount werden Eigentümer anhand der numerischen Benutzer-ID verglichen, nicht anhand des Namens, weil der Container über ein eigenes /etc/passwd verfügt. 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 Anwendung, die Sie selbst geschrieben haben, die sauberere Lösung. Das Hostverzeichnis mit chown zu ändern ist bei einem Image, das Sie nicht selbst geschrieben haben, sicherer. Manche Images starten den Entrypoint als root, geben anschließend Berechtigungen ab und erwarten darunter bestimmte Eigentümer.

Zwei weitere Fallstricke sollten Sie kennen. Unter Fedora, RHEL und anderen Systemen mit aktiviertem SELinux (Security-Enhanced Linux) wird ein Bind-Mount verweigert, bis er neu gekennzeichnet wurde. Fügen Sie daher :z für einen Pfad hinzu, der von mehreren Containern gemeinsam verwendet wird, oder :Z für einen Pfad, den nur ein Container verwenden soll. Die Schreibweise lautet - ./data:/data:Z. Ein Bind-Mount einer einzelnen Datei statt eines Verzeichnisses funktioniert außerdem nicht mehr, wenn ein Editor die Datei ersetzt, statt sie direkt zu überschreiben. Der Grund ist, dass der Mount dem ursprünglichen Inode folgt. Der Container sieht dann weiterhin die alten Inhalte, bis Sie ihn neu starten. Mounten Sie das übergeordnete Verzeichnis, wenn die Datei häufig bearbeitet wird.

Performance: Wo der Unterschied tatsächlich besteht

Auf einem Linux-Server verwenden beide Varianten denselben Kernel-Pfad. Der Durchsatzunterschied ist daher so gering, dass Sie die Entscheidung nicht davon abhängig machen sollten. Named Volumes mit dem Standardtreiber local befinden sich unter /var/lib/docker/volumes/ auf demselben Dateisystem wie der übrige Docker-Bestand. Ein Bind-Mount befindet sich dort, wohin Sie ihn verweisen.

Der Unterschied zeigt sich bei Docker Desktop unter macOS und Windows. Dort laufen Container in einer virtuellen Maschine. Ein Bind-Mount überquert dort die Grenze zwischen dem Dateisystem des Hosts und der virtuellen Maschine über eine Dateifreigabeschicht. Workloads mit vielen kleinen Dateioperationen, etwa ein Node.js-Abhängigkeitsbaum oder ein PHP-Framework-Cache, werden dadurch merklich langsamer. Named Volumes bleiben innerhalb der virtuellen Maschine und unterliegen diesem Aufwand nicht. Deshalb binden so viele Entwicklungs-Compose-Dateien das Quellverzeichnis ein, deklarieren aber ein Named Volume für node_modules.

Der andere tatsächliche Unterschied betrifft den Speicherort der Daten. Ein Bind-Mount nach /mnt/backup speichert die Daten auf diesem Datenträger. 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, belegt denselben Datenträger wie Ihre Systemprotokolle. Prüfen Sie dies, bevor ein Vorfall entsteht:

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

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

Ein benanntes Volume untersuchen

Ein benanntes Volume ist keine Blackbox. Fragen Sie Docker, wo es sich befindet:

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 nützlich. Behandeln Sie ihn nicht als Ort zum Bearbeiten von Dateien. Wenn Sie dort als root schreiben, tritt das oben beschriebene Problem mit den Eigentümern erneut auf. Außerdem ist der Pfad ein Detail des Treibers local, das andere Volume-Treiber nicht gemeinsam haben.

Die sichere Methode, den Inhalt zu prüfen, 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 Rückstände zurück.

Jede Art sichern

Ein Bind-Mount ist ein gewöhnliches Verzeichnis. Jedes dateibasierte Sicherungsprogramm verarbeitet ihn daher bereits. Geben Sie den Host-Pfad als Sicherungsquelle an. Damit ist die Sicherung abgeschlossen. Für ein benanntes Volume ist ein zusätzlicher Schritt erforderlich, weil das Programm 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 das Volume wieder her, indem Sie die Schritte in umgekehrter Richtung in ein neues Volume ausführen:

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 Besitzrechte, wenn der Befehl im Container als root ausgeführt wird. Dadurch bleibt das wiederhergestellte Volume für die Anwendung verwendbar.

Für beide Arten gilt eine Warnung. Wenn Sie die Dateien einer laufenden Datenbank kopieren, sichern Sie den Zustand eines sich verändernden Systems. Die Wiederherstellung kann dann in einem beschädigten Zustand enden. Stoppen Sie den Dienst zuerst. Alternativ können Sie die Datenbank mit ihrem eigenen Werkzeug exportieren, wie in docker compose exec -T db pg_dump -U postgres appdb > appdb.sql. Dadurch entsteht eine einfache Datei, die Sie anschließend zusammen mit Ihren Compose-Dateien in eine normale verschlüsselte restic-Sicherungsroutine aufnehmen können.

Eine Bind-Mount-Bindung 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 bewahrt Eigentümer, Berechtigungen und Zeitstempel. Dadurch kann der Containerbenutzer, der das alte Verzeichnis lesen konnte, weiterhin das neue Volume lesen. Ändern Sie anschließend den Dienst so, dass er pgdata:/var/lib/postgresql/data verwendet, fügen Sie pgdata zum obersten 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 das Projekt deklariert, und dieser Vorgang kann nicht rückgängig gemacht werden. Eine Bind-Mount-Bindung bleibt bei beiden Befehlen erhalten, weil Docker dieses Verzeichnis nie verwaltet hat. Wenn die Befehle für die Verwaltung des Lebenszyklus noch neu für Sie sind, führt Sie der Grundlagenleitfaden zu Docker Compose für einen VPS durch diese Befehle.

Auswahl für jeden Dienst

Fragen Sie, welcher Prozess die Datei schreibt. Konfigurationen, die Sie in einem Texteditor bearbeiten und in git committen, gehören in einen Bind-Mount, der unter :ro eingehängt wird. So bleiben sie sichtbar und versioniert. Anwendungsdaten, die Sie nie manuell öffnen, gehören in ein benanntes Volume. Docker setzt die Berechtigungen dort korrekt, und die Daten hängen nicht von einem Pfad auf dem Host ab.

Der gemischte Fall sind Mediendateien. Eine Fotobibliothek wird von der Anwendung geschrieben, aber auch von Ihnen verwaltet. Außerdem ist sie oft groß genug, um einen bestimmten Datenträger zu erfordern. Binden Sie sie in einen Pfad auf diesem Datenträger ein, und legen Sie den Eigentümer einmal bewusst fest. Dieses Muster verwenden die meisten selbst gehosteten Stacks: benannte Volumes für Datenbanken und Caches, Bind-Mounts für die Konfiguration und für das große Verzeichnis, das Sie benötigen.

FAQ

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

Ein Bind-Mount ordnet einen Pfad auf dem Host in den Container ein. Dadurch sehen beide Seiten 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 Block volumes: auf der obersten Ebene deklariert. Der praktische Unterschied betrifft die Zuständigkeit: Verwenden Sie Bind-Mounts für Konfigurationen, die Sie verwalten, und benannte Volumes für Daten, die die Anwendung verwaltet.

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

Ein leeres benanntes Volume wird aus dem Image initialisiert. Daher übernimmt es die vom Image festgelegten Besitzrechte, und der Container-Benutzer kann darin schreiben. Ein Bind-Mount zeigt das Host-Verzeichnis genau so, wie es auf dem Host vorhanden ist. Wenn Docker dieses Verzeichnis erstellen musste, gehört es root. Führen Sie docker compose exec <service> id aus, um die numerische ID des vom Container verwendeten Benutzers anzuzeigen. Setzen Sie anschließend sudo chown -R <uid>:<gid> für das Host-Verzeichnis ein, oder legen Sie user: "1000:1000" für den Service fest.

Wo speichert Docker benannte Volumes auf dem Datenträger?

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

Wie sichere ich ein benanntes Volume?

Führen Sie einen kurzlebigen Container aus, in den sowohl das Volume als auch ein Host-Verzeichnis eingebunden sind. Archivieren Sie anschließend mit docker run --rm -v myvol:/data:ro -v "$PWD":/backup alpine tar czf /backup/myvol.tar.gz -C /data . von einem Ort zum anderen. Erstellen Sie bei einer Datenbank stattdessen mit dem eigenen Werkzeug der Datenbank einen Dump. Eine Kopie von Dateien, während Schreibvorgänge laufen, kann bei der Wiederherstellung einen beschädigten Zustand erzeugen.

Löscht docker compose down meine Volumes?

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