Wenn Sie Docker verwenden, kommt es häufig vor, dass Sie Daten, die nicht im Container, sondern im Volume gespeichert sind, sichern oder zu einem anderen Volume für Tests kopieren müssen.

Man könnte einfach den Befehl docker cp verwenden, aber dieser Befehl unterstützt nur das Kopieren zwischen Dateisystemen von Containern und dem Host und hat keinen direkten Zugriff auf die von Docker verwalteten Volumes.

In diesem Artikel stelle ich die richtige Methode zum Kopieren von Docker-Volumes vor und konzentriere mich darauf, ‘warum’ wir diesen Ansatz verwenden sollten. Wenn Sie dieses Prinzip verstehen, können Sie es bei Bedarf anwenden, ohne die Befehle auswendig zu lernen.

Das Schlüsselprinzip ist einfach.

Die sicherste und 'Docker-orientierte' Methode zur Manipulation von Docker-Volumes besteht darin, einen 'temporären Container' zu verwenden, der auf das Volume zugreifen kann.


1. Kopieren eines bestehenden Volumes in ein neues Volume (Volume-to-Volume)



Dies ist das häufigste Szenario. Sie möchten möglicherweise das laufende db_data Volume in das Test-Volume db_data_test kopieren.

🤔 WARUM: Warum einen temporären Container verwenden?

Docker-Volumes werden irgendwo im Host-Dateisystem gespeichert (z.B. /var/lib/docker/volumes/...), aber der Docker-Daemon verwaltet diesen Pfad. Es wird nicht empfohlen, diesen Pfad direkt zuzugreifen und den Befehl cp zu verwenden, da dies zu Berechtigungsproblemen oder Dateninkonsistenzen führen kann.

Stattdessen führen wir einen temporären Container aus, der zwei Volumes gleichzeitig mountet.

  1. Der Container mountet das Quellvolume (source_volume) an den /from Pfad.

  2. Der Container mountet das Zielvolume (new_volume) an den /to Pfad.

  3. Sobald der Container läuft, führt er einen einfachen Linux-Befehl aus, um alle Daten von /from nach /to zu kopieren (cp oder tar).

  4. Nachdem der Befehl abgeschlossen ist, wird der Container automatisch zerstört (--rm Option).

Dieser Container dient lediglich als 'Werkzeug' zum Kopieren von Daten.

🚀 WIE: Beispielbefehl

Hier ist ein Beispiel für das Kopieren von Daten vom source_data Volume in das target_data Volume.

  1. Erstellen eines Test-Volumes (optional)
docker volume create source_data
docker volume create target_data
# (Es wird angenommen, dass im source_data Daten vorhanden sind.)
  1. Kopieren mit einem temporären Container
docker run --rm \
       -v source_data:/from \
       -v target_data:/to \
       alpine \
       sh -c "cp -a /from/. /to/"

💡 Erklärung des Befehls

  • docker run --rm: Das --rm Flag bedeutet, dass der Container sofort gelöscht wird, nachdem er seine Aufgabe abgeschlossen hat. Dies ist für temporäre Aufgaben unerlässlich.

  • -v source_data:/from: Mountet das source_data Volume im /from Verzeichnis des Containers.

  • -v target_data:/to: Mountet das target_data Volume im /to Verzeichnis des Containers.

  • alpine: Verwendet das sehr kleine Linux-Image alpine, das grundlegende Utilities wie cp und sh enthält.

  • sh -c "...": Das ist der Befehl, der ausgeführt wird, wenn der alpine-Container gestartet wird.

  • cp -a /from/. /to/:

    • -a (archive): Dieses Flag ist entscheidend. Es sorgt dafür, dass alle Eigenschaften, einschließlich Besitz, Berechtigungen, Zeitstempel usw., beibehalten werden, anstatt nur zu kopieren (cp -r). Dies ist besonders wichtig beim Umgang mit sensiblen Daten wie Datenbankdateien.

    • /from/.: Dies bezieht sich auf alle Inhalte im Verzeichnis /from (einschließlich versteckter Dateien) und nicht auf das Verzeichnis selbst.


2. Kopieren von Volumendaten in das Host-Dateisystem (Backup)

Verwenden Sie dies, wenn Sie Daten aus einem Volume in ein bestimmtes Verzeichnis Ihrer lokalen Maschine oder Ihres Servers als .tar-Datei sichern möchten.

🤔 WARUM: Wie funktioniert das?

Das Prinzip ist das gleiche wie beim ersten Punkt. Nur das Ziel hat sich von 'Docker-Volume' in 'Host-Verzeichnis' geändert.

Docker unterstützt die Bind-Mount-Funktion, um ein bestimmtes Verzeichnis des Hosts im Container zu mounten.

  1. Der Container mountet das Quellvolume (source_volume) an den /data Pfad.

  2. Der Container mountet das bestimmte Verzeichnis des Hosts ($(pwd)/backup) an den /backup Pfad.

  3. Der Container kopiert (oder komprimiert) den Inhalt von /data in das /backup Verzeichnis.

  4. Diese Operation erfolgt innerhalb des Containers, aber da /backup mit dem tatsächlichen Host-Verzeichnis verbunden ist, bleiben die Ergebnisse im Host zurück.

🚀 WIE: Beispielbefehl

Hier kopiert die Daten des source_data Volumes in das backup Verzeichnis an der aktuellen Position ($(pwd)).

# Erstellen Sie ein Verzeichnis auf dem Host, in dem gesichert werden soll
mkdir -p $(pwd)/backup

docker run --rm \
       -v source_data:/data:ro \
       -v $(pwd)/backup:/backup \
       alpine \
       cp -a /data/. /backup/

💡 Erklärung des Befehls

  • -v source_data:/data:ro: Das :ro (Read-Only) Flag wurde hinzugefügt. Da das Backup nur gelesen werden muss, ist es besser, es schreibgeschützt zu mounten, um versehentliche Änderungen am Quellvolume zu vermeiden.

  • -v $(pwd)/backup:/backup: Im Gegensatz zu source_data (dem Volume-Namen) zeigt alles, was mit / beginnt oder $(pwd) enthält (aktuellen Pfad), auf Host-Verzeichnisse.


3. Wichtige Kopiertipps (Tipps)



Tipp 1: Effizienteres Kopieren mit tar (komprimiertes Backup)

Die Verwendung von tar anstelle von cp bietet mehrere Vorteile. Es ist besonders nützlich, wenn Sie Daten als Archivdatei (.tar.gz) in einem Schritt sichern möchten.

Volume-to-Volume (mit tar)

Es kann schneller sein als cp und ist besonders effizient, wenn es viele Dateien gibt.

docker run --rm \
       -v source_data:/from \
       -v target_data:/to \
       alpine \
       sh -c "cd /from && tar -cf - . | (cd /to && tar -xf -)"
  • cd /from && tar -cf - .: Wechselt in das /from Verzeichnis und packt den Inhalt des aktuellen Verzeichnisses (.) in tar, der nicht in eine Datei, sondern in den Standardausgang (-) gesendet wird.

  • | (cd /to && tar -xf -): Nimmt den Standardausgang über die Pipe (|) und entpackt tar im /to Verzeichnis (x).

Volume-to-Host (komprimiertes Backup)

Komprimiert den Inhalt des source_data Volumes in die backup.tar.gz Datei und speichert sie auf dem Host.

docker run --rm \
       -v source_data:/data:ro \
       -v $(pwd):/backup \
       alpine \
       tar -czf /backup/backup.tar.gz -C /data .
  • tar -czf /backup/backup.tar.gz ...: c (erstellen), z (gzip-Kompression), f (als Datei) macht die Datei /backup/backup.tar.gz.

  • -C /data .: Dieser Teil ist wichtig. Zuerst wird in das /data Verzeichnis gewechselt, bevor alles darin (.) komprimiert wird. Auf diese Weise wird der Pfad /data nicht in die tar-Datei aufgenommen.

Tipp 2: Wiederherstellung von Host-Dateien ins Volume

Die Wiederherstellung folgt dem gleichen Prinzips wie das Backup. Sie müssen lediglich die Richtung von cp umkehren.

# Wiederherstellung der Daten aus dem $(pwd)/backup Verzeichnis in das new_data Volume
docker run --rm \
       -v new_data:/data \
       -v $(pwd)/backup:/backup:ro \
       alpine \
       cp -a /backup/. /data/

Zusammenfassung

Der Schlüssel zum Umgang mit Docker-Volumes ist die Denkweise, dass „Container als Werkzeuge verwendet werden“. Anstatt direkt auf Volume-Dateien auf dem Host zuzugreifen, führen Sie einen temporären Container mit den erforderlichen Volumes und Verzeichnissen aus, um sicher cp oder tar Kommandos auszuführen.

Wenn Sie sich nur an dieses Prinzip erinnern, können Sie in jeder Situation Volumendaten frei kopieren, sichern und wiederherstellen.