Docker: Backup und Wiederherstellung

Docker-Daten liegen über verschiedene Docker-Objekte und -Dateien verteilt vor. Leider existiert kein einheitlicher Ansatz zum Erstellen von Backups der einzelnen Docker-Daten. Stattdessen kommt eine Reihe verschiedener Befehle in Kombination zum Einsatz. Wir zeigen, wie das Anlegen und Wiederherstellen von Docker-Backups funktioniert.

Nachdem wir uns mit der Frage „Was ist ein Backup?“ beschäftigt, verschiedene Backup-Strategien vorgestellt und Anlegen von Datenbank-Backups erklärt haben, befassen wir uns nun mit der Erstellung von Docker-Backups.

Cloud Backup von IONOS

Maximaler Schutz für Ihre Unternehmensdaten: Einfache Backups für Cloud-Infrastruktur, PCs und Smartphones, inklusive persönlichem Berater!

Umfassender Schutz
Einfache Wiederherstellung
Schnelle Datenspeicherung

Was gibt es beim Erstellen von Docker-Backups zu beachten?

Anders als beim Anlegen eines MySQL-Backup mit mysqldump oder eines PostgreSQL-Backup mit pg_dump gibt es kein dediziertes Docker-Backup-Tool. Ein „docker backup volume“- oder „docker backup container“-Kommando sucht man vergeblich. Stattdessen existieren verschiedene Ansätze, die einzelnen Docker-Komponenten in Backups aufzunehmen. Schauen wir uns zunächst an, von welchen Docker-Komponenten man Backups erstellen sollte.

Welche Docker-Komponenten gehören ins Backup?

Grundsätzlich gilt bei Docker wie ganz generell: Von allen Daten, die bei Verlust nicht wiederhergestellt werden können, sollten Backups erstellt werden. Im Falle von Docker gehören dazu mindestens drei Arten von Daten:

  1. Docker-Objekte: Diese werden vom Docker-Deamon verwaltet. Die dabei anfallenden Daten werden unterhalb eines speziellen Verzeichnisses abgelegt. Dabei besteht keine Eins-zu-eins-Korrespondenz der dort liegenden Dateien zu den im Docker-Container vorhandenen Daten. Wir legen Backups der folgenden Docker-Objekte an:
    • Docker-Container
    • Docker-Volumes
    • Docker-Image
  2. Docker-Build-Dateien: Diese werden vom Nutzer verwaltet und liegen in beliebigen Ordnern auf dem Host-System. Die Build-Dateien lassen sich unkompliziert kopieren und archivieren. Wir legen Backups der folgenden Docker-Build-Dateien an:
    • Docker-Compose-Projektordner
    • Dockerfiles
  3. Datenbanken innerhalb eines Containers: Diese werden aus dem Container als Dump-Dateien exportiert. Wir legen Backups von Datenbanken der folgenden Systeme an:
    • MySQL-Datenbanken
    • PostgreSQL-Datenbank

Die generelle Idee beim Anlegen von Docker-Backups besteht darin, die Daten in Archiv-Dateien auf dem Host-System zu schreiben. Im Anschluss werden die Archiv-Dateien vom lokalen System auf ein Backup-System kopiert.

Sollen Backups vieler Docker-Daten erstellt werden, lohnt es sich, den Prozess zu automatisieren. Auf GitHub finden sich ausgefeilte Skripte, die das Anlegen von Docker-Backups vereinfachen. Der Entwickler Andreas Laub beispielsweise stellt eine Reihe praktischer Docker-Backup-Tools unter Open-Source-Lizenz zur Verfügung.

Zitat

„With these script you are able to backup your docker environment. There is one for the compose project, for mysql or mariadb, for postgres SQL and for normal docker volumes.“ Quelle: https://github.com/alaub81/backup_docker_scripts

„Diese Skripte erlauben, Backups der Docker-Umgebung zu erstellen. Es gibt jeweils ein Skript für das Compose-Projekt, für MySQL oder MariaDB, für PostgreSQL und für Docker-Volumen.“ (übersetzt von IONOS)

Hinweis

Sofern Sie die Software Portainer zum Administrieren Ihrer Docker-Umgebung nutzen, sollten Sie periodisch von den Portainer-Daten ein Backup anlegen.

Wo werden Docker-Container-Daten gespeichert?

Zum Anlegen eines Backups werden Daten kopiert. Dazu müssen wir zunächst wissen, wo die Daten liegen. Im Docker-Universum dienen Docker-Volumes als Ablageorte für den Austausch zwischen Docker-Containern und Host-System bzw. zwischen mehreren Containern.

Ein Docker-Container wird aus einem schreibgeschützten Docker-Image erzeugt. Änderungen an einem laufenden Container sind flüchtig und gehen beim Entfernen des Containers verloren. Um die Daten permanent zu sichern, müssen sie aus dem laufenden Container exportiert werden.

Neben Docker-Volumes lassen sich Container-Daten auch im laufenden Container speichern. Die Daten landen in der beschreibbaren Speicherschicht des Container-Dateisystems. In den meisten Fällen ist dies suboptimal. Es ist daher wichtig, das System klug zu konfigurieren und beispielsweise ein Docker-Volume zu nutzen.

Die Frage, wo genau Container-Daten abgelegt werden, erweist sich als recht komplex. Denn es gibt nicht nur eine Art von Docker-Volume. Je nach verwendetem Volume-Typ bestehen subtile Unterschiede in Bezug auf Speicherort und Schicksal der Daten beim Entfernen des Containers. Hier eine Übersicht der hauptsächlichen Docker-Speicher-Komponenten:

Docker-Speicher-Komponente Speicherort Beim Entfernen des Containers
Beschreibbare Container-Schicht Union-Dateisystem Daten gehen verloren
Bind Mount Ordner im Host-Dateisystem Daten bleiben erhalten
Benanntes Volume Innerhalb der Docker-Umgebung Daten bleiben erhalten
Anonymes Volume Innerhalb der Docker-Umgebung Daten werden entfernt

Schritt-für-Schritt-Anleitung zum Anlegen von Docker-Backups

In den meisten Fällen wird zum Erstellen eines Docker-Backups ein sogenanntes Tarball-Archiv erzeugt. Dabei kommt der Tar-Befehl zum Einsatz. Der generelle Befehlsaufruf zum Erzeugen einer Tar-Archiv-Datei entspricht dem folgenden Muster:

tar -cvf <path/to/archive-file>.tar <path/to/file-or-folder>

Dabei gibt es einen Haken: beim Aufruf wird der gesamte Pfad des archivierten Ordners in das Archiv mitaufgenommen. Beim Wiederherstellen kann dies problematisch sein. In der Praxis findet sich daher meist ein alternativer Ansatz:

cd <path/to/file-or-folder> && tar -cvf <path/to/archive-file>.tar .

Wir wechseln zunächst in den zu archivierenden Ordner und wenden das Tar-Kommando auf den derzeitigen Ordner an. Auf der Kommandozeile wird auf den derzeitigen Ordner mit einem Punkt (.) verwiesen. Die Kombination der beiden Schritte durch den &&-Operator stellt sicher, dass das Archivieren nur ausgeführt wird, wenn das Wechseln in den Zielordner erfolgreich war.

Die beim Archivieren der Docker-Daten erzeugte .tar-Dateien liegen zunächst auf dem Host-System. Um ein tatsächliches Backup zu erstellen, werden die Archiv-Dateien im Anschluss auf ein Backup-System übertragen. Dabei handelt es sich entweder um ein externes Speichermedium oder einen Cloud-Speicher. Für die Übertragung kommen spezielle Tools wie Rsync oder S3 zum Einsatz.

Tipp

Wie Sie ein Server-Backup mit Rsync erstellen, erklären wir in unserem Detail-Artikel.

Nachfolgend eine Übersicht der beim Anlegen von Docker-Backups zum Einsatz kommenden Ansätze samt zugehöriger Befehlsmuster. In manchen Fällen gibt es mehr als einen Ansatz, ein Backup eines Docker-Objekts zu erzeugen.

Docker-Objekt Backup erzeugen Beispiel-Kommando
Docker-Container Als Docker-Image speichern docker container commit <container-id> <backup-name>
Docker-Image Als Tarball-Archiv exportieren / Auf Registry pushen docker image save --output <image-backup>.tar <image-id> / docker image push <image-id>
Docker-Volume Volume in Container mounten; im Anschluss aus dem Container heraus Tarball-Archive erzeugen docker run --rm --volumes-from <container-id> --volume <host:container> <image> bash -c "tar -cvf <volume-backup>.tar <path/to/volume/data>"
Docker Compose-Projektordner Tarball-Archiv erzeugen / Mit Git versionieren tar -cvf <compose-backup>.tar </path/to/compose-dir>
Dockerfile Datei sichern / Mit Git versionieren tar -cvf <dockerfile-backup>.tar <path/to/dockerfile>

Wir setzen für die nachfolgenden Schritte voraus, dass Backup-Dateien beim Erzeugen im Ordner /backup/ im Heimverzeichnis abgelegt werden. Wir legen den Ordner als vorbereitenden Schritt an:

mkdir -p ~/backup/

Docker-Container-Backup erstellen

In einem Docker-Container vorhandene Daten sind in schreibgeschützten Schichten eines sogenannten Union-Dateisystems gespeichert. Ein Docker-Container basiert auf einem schreibgeschützten Image und enthält neben den Schichten des Images eine zusätzliche, beschreibbare Schicht.

Um die in der beschreibbaren Schicht vorhandenen Daten permanent zu sichern, erzeugen wir ein neues Image aus dem laufenden Container. Dazu nutzen wir das „docker commit“-Kommando. Im Anschluss sichern wir den Inhalt des Images als Tarball-Archiv:

  1. Docker-Dateisystem in Image schreiben
docker container commit <container-id> <backup-name>
  1. Resultierendes Image als Tarball-Archiv-Datei exportieren
docker image save --output ~/backup/<backup-name>.tar <backup-name>

Alternativ schieben wir das resultierende Image mit dem „docker image push“-Befehl auf ein Repository:

docker image push <backup-name>
Hinweis

Mithilfe des „docker container export“-Kommandos lässt sich das Container-Dateisystem ebenfalls exportieren. Dabei werden jedoch sämtliche Schichten auf eine einzelne Schicht reduziert. Der Ansatz ist daher zum Anlegen eines Backups nicht gut geeignet.

Docker-Image-Backup anlegen

Zum Sichern eines auf dem lokalen Host verfügbaren Docker-Images nutzen wir den bereits vom Erstellen eines Docker-Container-Backups bekannten Ansatz. Wir schreiben die Image-Daten in ein Tarball-Archiv:

docker image save --output ~/backup/<image-name>.tar <image-name>

Docker-Volume-Backup anlegen

Das Anlegen eines Docker-Volume-Backups erweist sich als komplexer Prozess. Denn wir müssen unterscheiden zwischen „Bind Mounts“ und „benannten“ bzw. „anonymen“ Docker-Volumes. Der Zugriff auf ein Bind Mount ist vom Host-Dateisystem problemlos möglich. So ist es einfach, ein Tarball-Archiv des Ordners anzulegen:

cd <path/to/docker-mount/> && tar -cvf ~/backup/<volume-backup>.tar .

Anders sieht es aus, wenn man aus Docker ein Backup eines benannten oder anonymen Volumes erzeugen möchte. Denn der Zugriff auf Volumes ist nur innerhalb eines laufenden Docker-Containers möglich. Der Standard-Trick zum Archivieren der in einem Docker-Volume enthaltenen Daten besteht darin, einen Container mit Zugriff auf das Volume zu starten. Im Anschluss werden die Daten des Volumes aus dem laufenden Container heraus archiviert. Betrachten wir die einzelnen Schritte des Prozesses:

  1. Container mit Zugriff auf das Volume stoppen
docker stop <container-id>
  1. Temporären Container starten und Volume-Daten extrahieren

Der temporäre Container erhält Zugriff auf die gewünschten Volumes sowie auf den Backup-Ordner auf dem Host.

docker run --rm --volumes-from <container-id> --volume ~/backup:/backup ubuntu bash -c "cd <path/to/volume/data> && tar -cvf /backup/<volume-backup>.tar ."
  1. Container mit Zugriff auf das Volume neu starten
docker start <container-id>

Das Kommando zum Extrahieren der Volume-Daten ist komplex. Schauen wir uns die einzelnen Komponenten im Detail an:

Befehls-Komponente Erklärung
--rm Weist Docker an, den neu gestarteten Container nach dem Anlegen des Volume-Backups zu entfernen.
--volumes-from <container-id> Mountet die Volumes des angegebenen Containers im neu gestarteten Container und macht die darin befindlichen Daten zugänglich.
--volume ~/backup:/backup Erzeugt Bind Mount zwischen dem ~/backup/-Ordner auf dem Host-System und dem /backup/-Ordner innerhalb des Containers.
ubuntu Legt fest, dass der neu gestartete Container ein Ubuntu-Linux-Image laden soll.
bash -c "cd …" Erzeugt ein Tarball-Archiv der Volume-Daten innerhalb des /backup/-Ordners im neu gestarteten Container; durch die Verknüpfung dieses Ordners mit dem ~/backup/-Ordner auf dem Host-System wird die Archiv-Datei außerhalb von Docker zugänglich.

Vom Docker-Compose-Projektordner ein Backup erstellen

Um ein vollständiges Backup des Docker-Compose-Projektordners zu erstellen, erzeugen wir ein Tarball-Archiv des Ordners:

cd <path/to/docker-compose-dir> && tar -cvf ~/backup/<compose-backup>.tar .
Hinweis

Prinzipiell ist es eine gute Idee, die Datei docker-compose.yaml mit Git zu versionieren. Wichtig ist, in diesem Fall sensible Daten wie Passwörter in einer separaten .env-Datei zu speichern und diese per .gitignore von der Versionskontrolle auszunehmen.

Ein Dockerfile-Backup erstellen

Um ein vollständiges Backup eines Dockerfiles anzulegen, wechseln wir in den Ordner, der das Dockerfile enthält und legen ein Tarball-Archiv des Dockerfiles an:

cd <path/to/dockerfile-dir> && tar -cvf ~/backup/<dockerfile-backup>.tar ./Dockerfile
Hinweis

Prinzipiell ist es eine gute Idee, die Datei mit Namen „Dockerfile“ mit Git zu versionieren. Wichtig ist in diesem Fall, sensible Daten wie Passwörter in einer separaten .env-Datei zu speichern und diese per .gitignore von der Versionskontrolle auszunehmen.

Von Datenbank in Docker-Container ein Backup erstellen

Datenbanken werden heutzutage gerne containerisiert. Um ein Backup einer im Docker-Container laufenden Datenbank zu erstellen, greift man auf datenbankspezifische Backup-Tools zurück. Dazu zählen insbesondere mysqldump und pg_dump.

Das jeweilige Backup-Tool wird innerhalb des Docker-Containers ausgeführt. Wir nutzen dafür das „docker exec“-Kommando – hier dargestellt am Beispiel einer MySQL-Datenbank. Wir führen den „mysqldump“-Befehl innerhalb des Containers aus. Der dabei entstehende Dump wird an die Standardausgabe der Host-Shell ausgegeben. Per Umleitung schreiben wir eine SQL-Dump-Datei im Backup-Ordner des lokalen Hosts:

docker exec <container-id> /usr/bin/mysqldump --user=root --password=<password> <dbname> > ~/backup/<dbname>.sql

Um aus einem laufenden Docker-Container ein Backup einer PostgreSQL-Datenbank zu erzeugen, gehen wir analog vor. Dabei setzen wir voraus, dass Datenbank-Nutzername und -Passwort in der .pgpass-Datei innerhalb des Containers gespeichert sind. Wir zeigen hier das Erstellen eines Backups im Custom-Dump-Format:

docker exec <container-id> pg_dump --format=custom --dbname=<dbname> > ~/backup/<dbname>.dump

Alternativ lässt sich ein klassischer Plain-Text-SQL-Dump erstellen. In diesem Fall fügen wir die Optionen „--clean“ und „--if-exists“ hinzu. Der Effekt ist, die Zieldatenbank vor dem Importieren zu bereinigen. So lässt sich der Dump auf dem Quellsystem einspielen, ohne dass es zu Fehlermeldungen kommt:

docker exec <container-id> pg_dump --format=plain --clean --if-exists --dbname=<dbname> > ~/backup/<dbname>.dump

Schritt-für-Schritt-Anleitung zum Wiederherstellen von Docker-Backups

Bisher haben wir gezeigt, wie Backups von Docker-Daten angelegt werden. Im weiteren Verlauf widmen wir uns der Wiederherstellung der Daten aus den Docker-Backups. Wir nehmen wiederum an, dass alle Backups auf dem lokalen Host im Ordner ~/backup/ verfügbar sind. In der Praxis müssten die Backups ggf. zunächst vom Backup-Medium in der Backup-Ordner kopiert werden.

Docker-Container aus Backup wiederherstellen

Zur Erinnerung: Um ein Backup eines Docker-Containers anzulegen, erstellen wir ein neues Image aus dem laufenden Container und speichern dieses im Anschluss als Tarball-Archiv-Datei. Zur Wiederherstellung eines Docker-Images aus einem Tarball-Archiv nutzen wir das „docker image load“-Kommando:

docker image load --input ~/backup/<image-name>.tar

Im Anschluss starten wir einen neuen Container aus dem resultierenden Image. Wir nutzen die „—detach“-Option, um den Container im Hintergrund zu starten:

docker run --detach <image-id>
Tipp

Verwenden Sie das „docker image ls“-Kommando, um eine Liste der verfügbaren Docker-Images samt Namen und IDs anzuzeigen.

Docker-Image aus Backup wiederherstellen

Die Wiederherstellung eines Docker-Images aus einem Tarball-Archiv haben wir bereits beschrieben. Wir nutzen dazu das „docker image load“-Kommando:

docker image load --input ~/backup/<image-name>.tar

Auf Docker-Host Backup eines Volumes wiederherstellen

Beim Wiederherstellen der Daten eines Docker-Volumes aus einem Backup handelt es sich um einen komplexen Prozess. Das genaue Vorgehen hängt vom spezifischen Einsatz-Szenario ab. Wir zeigen hier das Überschreiben der Volume-Daten aus einem Backup. Dabei nehmen wir an, dass wir uns auf demselben System befinden, auf dem das Backup erstellt wurde – d. h. die beteiligten Container, Volumes und weitere Docker-Objekte sind allesamt vorhanden. Handelt es sich um ein frisch eingerichtetes System, gestaltet sich der Prozess dementsprechend aufwendiger.

Das Wiederherstellen eines Docker-Volume-Backups erfordert wie beim Anlegen des Backups einen temporären Container mit Zugriff auf das Volume. Wie das dabei zum Tragen kommende Docker-Kommando genau funktioniert, ist im Abschnitt zum Anlegen eines Volume-Backups beschrieben. Wir bilden die einzelnen Schritte des Prozesses schematisch ab:

  1. Container, die das Volume nutzen, stoppen
docker stop <container-id>
  1. Temporären Container mit Zugriff auf Volume starten und Docker-Daten aus Backup in Volume kopieren
docker run --rm --volumes-from <container-id> --volume ~/backup:/backup ubuntu bash -c "cd <path/to/volume/data> && tar -xvf /backup/<volume-backup>.tar"
  1. Container, die das Volume nutzen, neu starten
docker start <container-id>

Einen Docker-Compose-Projektordner aus einem Backup wiederherstellen

Das Wiederherstellen eines Docker-Compose-Projektordners aus einem Backup geht unkompliziert von der Hand. Wir wechseln in den Docker-Compose-Ordner und entpacken dort das Tarball-Archiv. Bestehende Daten werden dabei überschrieben.

cd <path/to/docker-compose-dir> && tar -xvf ~/backup/<compose-backup>.tar

Ein Dockerfile aus einem Backup wiederherstellen

Das Wiederherstellen eines Dockerfiles aus einem Tarball-Archiv ist eine simple Operation. Wir entpacken dazu lediglich das Tarball-Archiv innerhalb des Dockerfile-Ordners. Das bestehende Dockerfile wird dabei überschrieben.

cd <path/to/dockerfile-dir> && tar -xvf ~/backup/<dockerfile-backup>.tar

Datenbank in Docker-Container aus Backup wiederherstellen

Um eine im Docker-Container befindliche Datenbank aus einem Backup wiederherzustellen, nutzen wir das „docker exec“-Kommando. Die Option „--interactive“ startet den Container im interaktiven Modus und hält die Standardeingabe offen.

Auf dem lokalen Host geben wir den Inhalt des MySQL-Dumps mittels cat-Befehl aus und leiten die Ausgabe per Pipe an den Docker-Befehl weiter. Innerhalb des Containers wird der mysql-Befehl ausgeführt, der die SQL-Anweisungen verarbeitet und damit die Datenbank neu aufbaut.

cat ~/backup/<dbname>.sql | docker exec --interactive <container-id> /usr/bin/mysql --user=root --password=<password> <dbname>

Etwas komplexer ist der Vorgang zum Wiederherstellen einer PostgreSQL-Datenbank. Je nach Format des Datenbank-Dumps kommt eines von zwei vorhandenen Tools zum Einsatz. Zum Wiederherstellen eines Datenbank-Dumps im PostgreSQL-„Custom“-Format führen wir das pg_restore-Tool innerhalb des Containers aus. Wir nutzen eine Eingabe-Umleitung, um die Dump-Datei als Eingabe einzuspeisen:

docker exec --interactive <container-id> pg_restore --dbname=<dbname> < ~/backup/<dbname>.dump

Das Wiederherstellen eines Plain-Text-PostgreSQL-Datenbank-Dumps funktioniert analog zum Wiederherstellen eines MySQL-Dumps. Wir geben die Dump-Datei per cat-Befehl aus und pipen die Ausgabe an das „docker exec“-Kommando mit Option „--interactive“. Innerhalb des Containers wird der psql-Befehl ausgeführt, der die SQL-Anweisungen verarbeitet und die Datenbank neu aufbaut.

cat ~/backup/<dbname>.sql | docker exec --interactive <container-id> psql --user=root --password=<password> <dbname>