Docker-Volumes vs. Bind-Mounts: Wo deine Daten wirklich liegen
Named Volumes oder Bind-Mount? Dieser Grundlagen-Guide erklärt den Unterschied, zeigt beide an echten Beispielen und wann du welches nimmst.
Inhaltsverzeichnis
Ein Container ist vergänglich: Löschst du ihn, sind seine Daten weg. Damit deine Datenbank, deine Nextcloud-Dateien oder deine Konfiguration ein docker compose down überleben, brauchst du Volumes. Dieser Guide klärt den oft verwirrenden Unterschied zwischen Named Volumes und Bind-Mounts.
Was bauen wir?
Kein neuer Dienst diesmal, sondern ein solides Fundament: Am Ende verstehst du, warum Container-Daten normalerweise verschwinden, kennst die zwei Wege, sie dauerhaft zu speichern, und weißt für jeden Dienst, welchen du nimmst. Alle Beispiele sind mit Docker 29 auf Debian 13 getestet und funktionieren mit jeder aktuellen Docker-Version. Dieses Wissen brauchst du für jedes App-Tutorial – dort taucht in fast jeder compose.yaml ein volumes:-Block auf.
Voraussetzungen
- Ein Server mit installiertem Docker
- Grundverständnis von Docker Compose (Services,
compose.yaml) - Ein Terminal-Zugang zum Server – reine Kommandozeilenübung, keine Web-Oberfläche
Schritt für Schritt
Schritt 1: Warum Container-Daten verschwinden
Alles, was ein Container in sein eigenes Dateisystem schreibt, lebt nur so lange wie der Container. Das ist gewollt – Container sollen austauschbar sein. Für alles, was bleiben soll (Datenbanken, Uploads, Konfiguration), musst du Docker explizit sagen, wo es außerhalb des Containers landet. Genau dafür gibt es zwei Werkzeuge: Named Volumes und Bind-Mounts.
Schritt 2: Named Volumes – von Docker verwaltet
Ein Named Volume ist ein Speicherbereich, den Docker selbst verwaltet. Du gibst ihm nur einen Namen, den Ablageort bestimmt Docker. Leg eines an:
docker volume create sk-demo-volsk-demo-volJetzt hängen wir das Volume in einen Wegwerf-Container (--rm löscht ihn danach) unter /data ein und schreiben eine Datei hinein:
docker run --rm -v sk-demo-vol:/data alpine:3 sh -c "echo hallo-von-serverkueche > /data/notiz.txt && ls -l /data"total 4
-rw-r--r-- 1 root root 23 Jul 20 22:31 notiz.txtDer Container ist längst weg – die Daten nicht. Wo liegen sie? Frag Docker:
docker volume inspect sk-demo-vol --format "{{ .Mountpoint }}"/var/lib/docker/volumes/sk-demo-vol/_dataDieser Pfad gehört Docker. Du kannst ihn als root einsehen, solltest ihn aber nicht direkt bearbeiten:
cat /var/lib/docker/volumes/sk-demo-vol/_data/notiz.txthallo-von-serverkuecheDer Beweis für Persistenz: Ein völlig neuer Container sieht dieselben Daten:
docker run --rm -v sk-demo-vol:/data alpine:3 cat /data/notiz.txthallo-von-serverkuecheMerke: Named Volumes sind der Standard für Anwendungsdaten – Datenbanken, Uploads, alles, was die App selbst verwaltet. Docker kümmert sich um Ort und Rechte, und das Volume überlebt docker compose down (nur down -v löscht es mit).
Schritt 3: Bind-Mounts – ein Ordner vom Host
Bei einem Bind-Mount hängst du einen konkreten Ordner deines Servers in den Container. Du bestimmst den Pfad, und Änderungen sind sofort auf beiden Seiten sichtbar:
mkdir -p /opt/sk-demo-bind
docker run --rm -v /opt/sk-demo-bind:/data alpine:3 sh -c "echo aus-dem-container > /data/host.txt"
ls -l /opt/sk-demo-bindtotal 4
-rw-r--r-- 1 root root 18 Jul 21 00:31 host.txtDer Container hat die Datei geschrieben, und sie liegt direkt in deinem Host-Ordner – ohne Umweg über /var/lib/docker. Das ist der Sinn von Bind-Mounts: Dateien, die du selbst bearbeiten willst. Klassische Fälle sind Konfigurationsdateien (traefik.yml, nginx.conf) oder eine compose.yaml, die eine Config einliest.
Tipp
Achtung
/, nicht /etc, keine Home-Verzeichnisse – und ganz besonders nicht /var/run/docker.sock. Wer den Docker-Socket eingehängt bekommt, kann beliebige Container starten und ist damit faktisch root auf dem ganzen Host. Mounte immer nur den einen Ordner, den der Dienst wirklich braucht.Schritt 4: Beides in der compose.yaml
In Compose sieht der Unterschied so aus. Ein Named Volume wird unten unter volumes: deklariert und oben per Name referenziert; ein Bind-Mount ist einfach ein Host-Pfad:
services:
app:
image: beispiel/app:1
volumes:
- app-daten:/var/lib/app # Named Volume (Docker-verwaltet)
- ./config.yml:/etc/app/config.yml:ro # Bind-Mount (deine Datei, read-only)
volumes:
app-daten:Das :ro am Ende macht den Bind-Mount read-only – der Container kann die Konfiguration lesen, aber nicht verändern. Für eingehängte Configs ist das eine gute Angewohnheit.
Schritt 5: Die Falle – anonyme Volumes
Lässt du bei -v den Namen weg (-v /data statt -v name:/data) oder bringt ein Image in seinem Dockerfile eine VOLUME-Anweisung mit, entsteht ein anonymes Volume mit einer zufälligen ID. So sieht der erste Fall aus:
docker run --name demo -v /data alpine:3 sh -c "echo test > /data/x.txt"Wir lassen den Container hier bewusst ohne --rm laufen – sonst würde Docker das anonyme Volume beim Beenden sofort mitlöschen. Das Problem im Alltag: Solche Volumes bleiben liegen, sammeln sich unbemerkt an, und du findest später nicht mehr heraus, welche Daten wohin gehören:
docker volume lsDRIVER VOLUME NAME
local sk-demo-vol
local 9f8c1a2b3c4d5e6f70819a0b1c2d3e4f5061a2b3c4d5e6f70819a0b1c2d3e4f50Die kryptische Zeile ist ein anonymes Volume. Den Wegwerf-Container kannst du jetzt entfernen – das anonyme Volume bleibt trotzdem liegen:
docker rm demoGib deinen Volumes immer einen Namen – dann bleibt überschaubar, was wozu gehört.
Schritt 6: Volumes verwalten
Die wichtigsten Befehle im Alltag:
docker volume ls # alle Volumes auflisten
docker volume inspect NAME # Details, u. a. Mountpoint
docker volume rm NAME # ein Volume löschen (Daten weg!)Das Aufräumen unserer Demo heben wir uns bis nach der Backup-Sektion auf – dort brauchen wir sk-demo-vol nämlich noch.
Wenn es nicht funktioniert
Der Container schreibt, aber der Bind-Mount-Ordner auf dem Host bleibt leer. Du hast einen
relativen Pfad benutzt, der woanders zeigt als gedacht, oder Docker hat den Pfad neu als leeren
Ordner angelegt. Bei docker run Bind-Mounts immer mit absolutem Pfad angeben
(/opt/app/config, nicht config). Existiert dieser Host-Pfad noch nicht, legt Docker ihn
stillschweigend als leeren Ordner an – prüfe also mit ls, dass du wirklich den richtigen erwischt
hast. In der compose.yaml sind ./-Pfade dagegen völlig in Ordnung – sie sind relativ zur
compose.yaml und damit eindeutig. Achtung außerdem: docker run -v config:/data (ohne / oder
./ davor) ist kein Bind-Mount, sondern legt ein Named Volume namens config an.
Permission denied, sobald der Container in den Mount schreiben will. Der Prozess im Container
läuft unter einer anderen UID als der Besitzer des Host-Ordners – typisch bei Bind-Mounts. Bei Named
Volumes tritt das selten auf (Docker setzt die Rechte). Bei Bind-Mounts den Ordner dem passenden
Benutzer geben (chown -R 1000:1000 /opt/app/data) oder im Image die user:-Angabe der Compose
nutzen.
Nach docker compose down sind alle Daten weg. Du hast docker compose down -v benutzt – das
-v löscht die Named Volumes mit. Für einen normalen Neustart ohne -v arbeiten. -v bewusst
nur einsetzen, wenn du wirklich bei null anfangen willst.
docker system prune hat Daten gelöscht. docker volume prune bzw. docker system prune --volumes entfernt Volumes, an denen gerade kein Container hängt. Bei docker volume prune sind
benannte Volumes standardmäßig geschützt – gelöscht werden nur anonyme Volumes; benannte
fallen erst mit --all/-a weg. (Bei docker system prune steuert -a/--all dagegen die
Images, nicht die benannten Volumes.) Ein weiteres starkes Argument fürs Benennen – ein
sk-demo-vol übersteht ein versehentliches docker volume prune, ein anonymes Volume nicht.
Trotzdem prune mit Volumes nur laufen lassen, wenn alle wichtigen Stacks aktiv sind, oder gezielt
mit docker volume rm entfernen.
Wartung & Backups
Volumes sind kein Backup – sie liegen auf derselben Festplatte wie dein Server. Fällt die aus, sind Container und Volume weg. Ein Named Volume sicherst du, indem du seinen Inhalt durch einen Wegwerf-Container in ein Archiv packst:
mkdir -p /opt/backups
docker run --rm -v sk-demo-vol:/data -v /opt/backups:/backup alpine:3 \
tar czf /backup/sk-demo-vol.tar.gz -C /data .Zurückspielen geht genauso herum – Archiv rein, ins Volume entpacken. Leg das Ziel-Volume vorher an (docker volume create sk-demo-vol) und stopp den zugehörigen Container, damit dir nichts ins offene Volume schreibt:
docker run --rm -v sk-demo-vol:/data -v /opt/backups:/backup alpine:3 \
tar xzf /backup/sk-demo-vol.tar.gz -C /dataDieses Archiv – und alle Bind-Mount-Ordner unter /opt – gehören in dein verschlüsseltes Off-Site-Backup mit Restic. Damit überlebt deine Datenbank auch einen Totalausfall des Servers.
Im Alltag lohnt sich Ordnung: Benenne Volumes sprechend (nextcloud-db, nicht db), räume anonyme Volumes gelegentlich auf und prüfe mit docker system df, wie viel Platz deine Volumes belegen – gerade bei Datenbanken und Mediendiensten wächst das über die Zeit spürbar.
Zum Schluss räumst du die Demo wieder ab – jetzt, wo Backup und alle Beispiele durch sind:
docker volume rm sk-demo-vol && rm -rf /opt/sk-demo-bind /opt/backupsFeedback per E-Mail: feedback@serverkueche.de
Das könnte dir auch schmecken

Docker-Netzwerke verstehen: bridge, internes DNS & das proxy-Netz
Warum deklariert jedes App-Rezept ein proxy-Netz? Dieser Guide erklärt Docker-Netzwerke, das interne DNS und …

Den ganzen Docker-Stack sicher aktuell halten
Update-Disziplin für deinen Docker-Stack: Versionen pinnen, mit Diun über Updates informiert werden, sicher einspielen, …

Die eigene Website mit Hugo hosten – wie die Serverküche selbst
Statische Website mit Hugo bauen und im Docker-Container hinter Traefik ausliefern – schnell, sicher, ohne Datenbank. …