Nextcloud im Container – Teil 5: Backup und Restore

Hallo und herzlich willkommen zu Teil 5 von Nextcloud im Container. In diesem Artikel geht es um Backup und Restore. Die vorhergehenden Teile dieser Serie sind weiter unten verlinkt.

Backup

Mit dem Thema Backup und Restore im Containerland habe ich mich bereits in einem früheren Artikel beschäftigt. Da ich mit dem Ansatz von dort nicht ganz zufrieden bin, gehe ich in diesem Wochenend-Projekt einen anderen Weg.

Für Nextcloud existiert die App Backup, welche im Folgenden zum Einsatz kommt. Diese wird über die App-Verwaltung in den Admin-Einstellungen der Nextcloud aktiviert.

Die englischsprachige Dokumentation (siehe [5]) macht einen soliden und verständlichen Eindruck. Ich habe mich von dieser durch die Konfiguration führen lassen.

Einstellungen der Nextcloud-Sicherung
Standard-Einstellungen der Nextcloud-Sicherungs-App

Ich habe die im obigen Bild dargestellten Einstellungen wie folgt geändert:

  1. Zeitintervall zwischen zwei vollständigen Wiederherstellungspunkten: 7 Tage
  2. Die Verschlüsselung für Wiederherstellungspunkte habe ich deaktiviert
  3. Richtlinie für die lokalen App-Daten: 4

Nun kann man über die entsprechende Schaltfläche einen vollständigen Wiederherstellungspunkt erstellen. Alternativ kann man auch warten, bis das Zeitfenster für den ersten vollständigen Wiederherstellungspunkt erreicht ist.

Ich habe die Sicherung einige Tage mitlaufen lassen. Wie der folgende Screenshot zeigt, wurden ein Full-Backup und zwei darauf folgende differenzielle Backups erzeugt, bevor ein neues Full-Backup erstellt wurde.

Backup-History on Sun 13th Mar
Backup-Historie am 13.03.2022

Hierbei ist zu beachten, dass die Backups in der gleichen Container-Instanz liegen wie die Live- bzw. Produktions-Daten. Damit ist es noch kein richtiges Backup. Denn wenn diese Instanz komplett zerstört wird, ist auch das Backup weg. Die Backups müssen daher unbedingt an einem anderen Ort gespeichert werden. Ich habe mich entschieden, diesem Thema einen eigenen Artikel zu widmen und es in Teil 6 Desaster-Recovery zu behandeln.

Wiederherstellung einer einzelnen Datei

An dieser Stelle möchte ich festhalten, wie eine einzelne Datei wiederhergestellt werden kann. Mit der Wiederherstellung einer kompletten Nextcloud-Instanz beschäftige ich mich in einem folgenden Artikel.

Wiederherstellungspunkte auflisten

Um vorhandene Wiederherstellungspunkte auflisten zu können, wechselt man auf dem Container-Host zuerst in die Container-Instanz mit der laufenden Nextcloud:

$ podman exec -u 33 -it nextcloud bash
www-data@nc_pod:~/html$

Durch ‚-u 33′ betritt man den Container mit der UID des Users www-data, welcher berechtigt ist, die folgenden Kommandos auszuführen. In obigem Beispiel heißt die Container-Instanz schlicht ’nextcloud‘. Für weitere Informationen zum Kommando siehe podman-exec(1). Die Restore-Points können nun wie folgt aufgelistet werden:

www-data@nc_pod:~/html$ ./occ backup:point:list
- retreiving data from local
 > found RestoringPoint 20220305001002-full-3ebDDoh2yinj55C
 > found RestoringPoint 20220307235028-differential-W558tuHGTnCbwgx
 > found RestoringPoint 20220310234002-differential-1NHETYudPSx6Yxc
 > found RestoringPoint 20220312001002-full-i1SY9VxDZRL8n1O
Ausgabe gekürzt.

Einen Wiederherstellungspunkt nach einer Datei durchsuchen

Angenommen, die Bilddatei Frog.jpg ist abhandengekommen. Nun kann ein Wiederherstellungspunkt wie folgt nach dem Dateinamen durchsucht werden:

www-data@nc_pod:~/html$ ./occ backup:file:search --point 20220305001002-full-3ebDDoh2yinj55C Frog.jpg

- searching in 20220305001002-full-3ebDDoh2yinj55C (2022-03-05 00:10:02)
 1/1 [============================] 100%
   > found tronde/files/Photos/Frog.jpg (447.02 KB) in data/data-baa61d4a-85a8-4cc7-b43b-5a6270b7143e
   > found bob/files/Photos/Frog.jpg (447.02 KB) in data/data-baa61d4a-85a8-4cc7-b43b-5a6270b7143e
 1/1 [============================] 100%
   > found core/skeleton/Photos/Frog.jpg (447.02 KB) in nextcloud/nextcloud-853e4f81-7f34-4a85-a428-1f569fe7efb5
 1/1 [============================] 100%

In dem angegebenen Wiederherstellungspunkt existiert die Datei Frog.jpg insgesamt dreimal. Es wird jeweils der komplette Pfad angezeigt.

Wiederherstellung von bob/files/Photos/Frog.jpg

Nun soll die Datei Frog.jpg für den Benutzer Bob aus dem oben verwendeten Wiederherstellungspunkt wiederhergestellt werden. Da meine Wiederherstellungspunkte komprimiert gespeichert werden, dient der erste Befehl im folgenden Codeblock jedoch erstmal dazu, einen Wiederherstellungspunkt zu entpacken.

www-data@nc_pod:~/html$ ./occ backup:point:unpack 20220305001002-full-3ebDDoh2yinj55C
Unpacking Restoring Point 20220305001002-full-3ebDDoh2yinj55C
 > lock and set status to unpacking
 > Browsing RestoringData data
   > Unpacking RestoringChunk data-baa61d4a-85a8-4cc7-b43b-5a6270b7143e: proceeding
     * copying parts to temp files
       - 00001-Ur86KyoXRnp8Evt: /tmp/phpkzVs4Y
     * merging parts into single file: /tmp/phpyLjmxZ
     * Extracting /tmp/phpyLjmxZ: /tmp/phpmJG1O1
     - storing chunk in appdata ok
     * removing old chunk parts
 > Browsing RestoringData nextcloud
   > Unpacking RestoringChunk nextcloud-853e4f81-7f34-4a85-a428-1f569fe7efb5: proceeding
     * copying parts to temp files
       - 00001-EUEeVME26dbQyf6: /tmp/phpVfSAt3
     * merging parts into single file: /tmp/phpc3kVw0
     * Extracting /tmp/phpc3kVw0: /tmp/phpF1kt52
     - storing chunk in appdata ok
     * removing old chunk parts
 > Browsing RestoringData apps
   > Unpacking RestoringChunk apps-14864f48-87a9-4c61-82f5-33defc3de2d2: proceeding
     * copying parts to temp files
       - 00001-65lDdATRHTQde5b: /tmp/phpDngG62
     * merging parts into single file: /tmp/php9U5X7Y
     * Extracting /tmp/php9U5X7Y: /tmp/phpXGwXP0
     - storing chunk in appdata ok
     * removing old chunk parts
 > Browsing RestoringData config
   > Unpacking RestoringChunk config-a8809c3e-5259-49b4-b2cb-2dbeb755949f: proceeding
     * copying parts to temp files
       - 00001-HMfvJewXGLEckCH: /tmp/phpPePsK1
     * merging parts into single file: /tmp/phpVlxXA1
     * Extracting /tmp/phpVlxXA1: /tmp/phpBUIDm0
     - storing chunk in appdata ok
     * removing old chunk parts
 > Browsing RestoringData apps-custom_apps-84a585e6
   > Unpacking RestoringChunk apps-custom_apps-84a585e6-c4e2adaa-eb06-4318-8196-62aea73b89c8: proceeding
     * copying parts to temp files
       - 00001-pXttjhVm9cRU6DU: /tmp/phpATT8t2
     * merging parts into single file: /tmp/php8HMcR1
     * Extracting /tmp/php8HMcR1: /tmp/phpmHRKS1
     - storing chunk in appdata ok
     * removing old chunk parts
 > Browsing RestoringData sqldump
   > Unpacking RestoringChunk sqldump-d0ebed1c-81dd-418b-a8ba-cecca8d92c00: proceeding
     * copying parts to temp files
       - 00001-QYOIpn2zOj43TsL: /tmp/phpcEUqQZ
     * merging parts into single file: /tmp/phpOwn0g1
     * Extracting /tmp/phpOwn0g1: /tmp/phpiJxrh3
     - storing chunk in appdata ok
     * removing old chunk parts
 > removing status packed
 > unlocking restoring point

www-data@nc_pod:~/html$ ./occ backup:point:restore 20220305001002-full-3ebDDoh2yinj55C --file bob/files/Photos/Frog.jpg --data data                                           
   > restoring bob/files/Photos/Frog.jpg (447.02 KB) from /data/data-baa61d4a-85a8-4cc7-b43b-5a6270b7143e/data-baa61d4a-85a8-4cc7-b43b-5a6270b7143e (rewind: 8 days, 20 hours, 51 minutes and 20 seconds): ok

Die allgemeine Befehlsform für die Wiederherstellung lautet:

backup:point:restore [--force] [--do-not-ask-data] [--do-not-ask-sql] [--file FILE] [--chunk CHUNK] [--data DATA] [--] <pointId>

Es ist nicht gut dokumentiert, wie man den korrekten Wert für --data herausfindet. Ich habe diesen durch Ausprobieren gefunden. Dann war der Restore jedoch kein Problem mehr. Wie man die korrekten Werte für --data bzw. --chunk sicher identifiziert, muss ich noch herausfinden. Falls hier jemand einen Tipp für mich hat, freue ich mich über euren Kommentar oder eine E-Mail.

Um Speicherplatz zu sparen, komprimiere ich den genutzten Wiederherstellungspunkt wieder und verlasse den Container:

www-data@nc_pod:~/html$ ./occ backup:point:pack 20220305001002-full-3ebDDoh2yinj55C
Packing Restoring Point 20220305001002-full-3ebDDoh2yinj55C
 > lock and set status to processing
 > Browsing RestoringData data
   > Packing RestoringChunk data-baa61d4a-85a8-4cc7-b43b-5a6270b7143e: proceeding
     * copying chunk to temp file /tmp/phpsyGIxw: ok
     * compressing /tmp/phpsyGIxw: /tmp/phpjuZY7z
     * spliting /tmp/phpjuZY7z in parts: 1 part(s) 
     - storing parts in appdata .ok
     * Removing old chunk file data-baa61d4a-85a8-4cc7-b43b-5a6270b7143e.zip
 > Browsing RestoringData nextcloud
   > Packing RestoringChunk nextcloud-853e4f81-7f34-4a85-a428-1f569fe7efb5: proceeding
     * copying chunk to temp file /tmp/php6f6Kfx: ok
     * compressing /tmp/php6f6Kfx: /tmp/phpz3Ndtz
     * spliting /tmp/phpz3Ndtz in parts: 1 part(s) 
     - storing parts in appdata .ok
     * Removing old chunk file nextcloud-853e4f81-7f34-4a85-a428-1f569fe7efb5.zip
 > Browsing RestoringData apps
   > Packing RestoringChunk apps-14864f48-87a9-4c61-82f5-33defc3de2d2: proceeding
     * copying chunk to temp file /tmp/phpf19OHA: ok
     * compressing /tmp/phpf19OHA: /tmp/phpZMcpmw
     * spliting /tmp/phpZMcpmw in parts: 1 part(s) 
     - storing parts in appdata .ok
     * Removing old chunk file apps-14864f48-87a9-4c61-82f5-33defc3de2d2.zip
 > Browsing RestoringData config
   > Packing RestoringChunk config-a8809c3e-5259-49b4-b2cb-2dbeb755949f: proceeding
     * copying chunk to temp file /tmp/phpykt9Rw: ok
     * compressing /tmp/phpykt9Rw: /tmp/phpxik6bx
     * spliting /tmp/phpxik6bx in parts: 1 part(s) 
     - storing parts in appdata .ok
     * Removing old chunk file config-a8809c3e-5259-49b4-b2cb-2dbeb755949f.zip
 > Browsing RestoringData apps-custom_apps-84a585e6
   > Packing RestoringChunk apps-custom_apps-84a585e6-c4e2adaa-eb06-4318-8196-62aea73b89c8: proceeding
     * copying chunk to temp file /tmp/php1oAWAA: ok
     * compressing /tmp/php1oAWAA: /tmp/phpOtyrjA
     * spliting /tmp/phpOtyrjA in parts: 1 part(s) 
     - storing parts in appdata .ok
     * Removing old chunk file apps-custom_apps-84a585e6-c4e2adaa-eb06-4318-8196-62aea73b89c8.zip
 > Browsing RestoringData internal
   > Packing RestoringChunk app.zip: already packed
   > Packing RestoringChunk restore.php: already packed
 > Browsing RestoringData sqldump
   > Packing RestoringChunk sqldump-d0ebed1c-81dd-418b-a8ba-cecca8d92c00: proceeding
     * copying chunk to temp file /tmp/phpFfW2zy: ok
     * compressing /tmp/phpFfW2zy: /tmp/phpvXl8qy
     * spliting /tmp/phpvXl8qy in parts: 1 part(s) 
     - storing parts in appdata .ok
     * Removing old chunk file sqldump-d0ebed1c-81dd-418b-a8ba-cecca8d92c00.zip
 > removing status processing, adding status packed
 > unlocking restoring point
www-data@nc_pod:~/html$ exit
exit

Wiederherstellung eines Ordners inkl. Inhalt

Manchmal ist es erforderlich, statt einzelner Dateien ganze Ordner inkl. Inhalt wiederherzustellen. Wie dies funktioniert, demonstriere ich im Folgenden für den Ordner Documents des Benutzers Bob. Dazu wechsle ich zuerst wieder in den Container, wie in diesem Abschnitt bereits beschrieben wurde.

TL;DR: Die Wiederherstellung eines Ordners inkl. dessen Inhalts ist aktuell nicht möglich (siehe [6]). Wer es eilig hat, kann direkt zum Fazit springen.

Während ich im vorherigen Abschnitt einen ausgewählten Wiederherstellungspunkt nach einer Datei durchsucht habe, liste ich diesmal alle Wiederherstellungspunkte bis zum 15.03.2022 auf, welche den gesuchten Pfad enthalten:

www-data@nc_pod:~/html$ ./occ backup:file:search bob/files/Documents --until 2022-03-15

- searching in 20220305001002-full-3ebDDoh2yinj55C (2022-03-05 00:10:02)
 1/1 [============================] 100%
   > found bob/files/Documents/Example.md (1.07 KB) in data/data-baa61d4a-85a8-4cc7-b43b-5a6270b7143e
   > found bob/files/Documents/Nextcloud flyer.pdf (365.24 KB) in data/data-baa61d4a-85a8-4cc7-b43b-5a6270b7143e
   > found bob/files/Documents/Readme.md (136 B) in data/data-baa61d4a-85a8-4cc7-b43b-5a6270b7143e
   > found bob/files/Documents/Welcome to Nextcloud Hub.docx (24.56 KB) in data/data-baa61d4a-85a8-4cc7-b43b-5a6270b7143e
 1/1 [============================] 100%

- searching in 20220307235028-differential-W558tuHGTnCbwgx (2022-03-07 23:50:28)
 1/1 [============================] 100%   no result

- searching in 20220310234002-differential-1NHETYudPSx6Yxc (2022-03-10 23:40:02)
 1/1 [============================] 100%   no result

- searching in 20220312001002-full-i1SY9VxDZRL8n1O (2022-03-12 00:10:02)
 1/1 [============================] 100%
   > found bob/files/Documents/Example.md (1.07 KB) in data/data-f55df957-3368-4b84-b957-4dc3e819c0ce
   > found bob/files/Documents/Nextcloud flyer.pdf (365.24 KB) in data/data-f55df957-3368-4b84-b957-4dc3e819c0ce
   > found bob/files/Documents/Readme.md (136 B) in data/data-f55df957-3368-4b84-b957-4dc3e819c0ce
   > found bob/files/Documents/Welcome to Nextcloud Hub.docx (24.56 KB) in data/data-f55df957-3368-4b84-b957-4dc3e819c0ce
 1/1 [============================] 100%

- searching in 20220314234502-differential-suwLdJJegRlO4XI (2022-03-14 23:45:02)
 1/1 [============================] 100%   no result

Es muss der vollständige Pfad zum gesuchten Verzeichnis angegeben werden. Wildcards wie z.B. */Documents oder "*/Documents" funktionieren genauso wenig wie reguläre Ausdrücke. Dies kann die Suche nach einem Ordner schonmal schwierig gestalten. Denn welcher Anwender kennt schon den vollständigen Pfad zu dem Ordner, der vermisst wird?

Im obigen Codeblock ist zu sehen, dass der Pfad zum Ordner lediglich als Bestandteil der Pfade zu den darin enthaltenen Dateien angezeigt wird. Dies und die Erkenntnis, keine Suchmuster verwenden zu können, lassen bei mir erste Zweifel aufkommen, ob das Verzeichnis inkl. Inhalt wiederhergestellt werden kann, oder ob ich jede enthaltene Datei einzeln wiederherstellen muss.

Doch bevor ich mich an der Wiederherstellung versuchen kann, muss ich zuerst den ausgewählten Wiederherstellungspunkt entpacken. Wie dies aussieht, kann dem Abschnitt über die Dateiwiederherstellung entnommen werden.

Der folgende Codeblock zeigt dann auch, dass der Ordner nicht wiederhergestellt werden kann:

www-data@nc_pod:~/html$ ./occ backup:point:restore 20220312001002-full-i1SY9VxDZRL8n1O --file bob/files/Documents --data data
 
In ChunkService.php line 925:
                                                        
  [OCA\Backup\Exceptions\ArchiveFileNotFoundException]  
                                                        

backup:point:restore [--force] [--do-not-ask-data] [--do-not-ask-sql] [--file FILE] [--chunk CHUNK] [--data DATA] [--] <pointId>

Eine Wiederherstellung ist offenbar nur auf Dateiebene möglich (siehe [6]). Das ist sehr schade, da dies die Wiederherstellung deutlich verkompliziert. Vor allem da Wildcards ebenfalls nicht funktionieren.

Fazit

In diesem Artikel habe ich das Thema Backup und Recovery aufgegriffen. Ich habe kurz beschrieben, wie eine Sicherung mit der Nextcloud-Backup-App konfiguriert werden kann. Nachdem einige Wiederherstellungspunkte erstellt wurden, habe ich exemplarisch eine Datei wiederhergestellt.

Da die Wiederherstellungspunkte komprimiert gespeichert werden, musste der ausgewählte Wiederherstellungspunkt vor dem Restore erst dekomprimiert werden, was einige Zeit gedauert hat. Hier muss jeder für sich selbst entscheiden, ob man sich die kürzere Zeit zur Wiederherstellung mit einem erhöhten Speicherbedarf durch unkomprimierte Wiederherstellungspunkte erkaufen möchte oder nicht.

Die zu Beginn des Artikels noch gelobte Dokumentation offenbarte schnell Lücken und ich muss mein Urteil revidieren. Sie ist im besten Fall ausreichend.

Der Versuch, einen Ordner inkl. Inhalt wiederherzustellen, endete hingegen in einer Enttäuschung. Dies ist aktuell offenbar nicht möglich, da nur der Datei-Restore oder die Wiederherstellung der gesamten Nextcloud-Instanz unterstützt wird. Diese Erfahrung lässt mich ein wenig enttäuscht und unzufrieden zurück.

Wie sichert ihr eure Nextcloud? Welche Restore-Fälle habt ihr damit bereits durchgespielt? Ich freue mich auf eure Kommentare und darauf euch zu Teil 6: Desaster-Recovery Updates wieder begrüßen zu dürfen.

Update 27.03.2022

Der obige Text wurde dahingehend angepasst, dass nun deutlich wird, dass die Wiederherstellung ganzer Verzeichnisse inkl. deren Inhalt aktuell nicht unterstützt wird (siehe [6]). Nicht mehr zutreffende Textstellen habe ich gestrichen.

Entgegen meiner ursprünglichen Planung wird es keinen Artikel zum Thema Desaster-Recovery geben, da es mir aktuell nicht möglich ist, die Restore-Points auf externem Speicher abzulegen (siehe [7] und [8]).

Damit ist die Backup-App in ihrem aktuellen Zustand (Version 1.0.6; Stand 27.03.2022) in meinen Augen unbrauchbar. Das ist schade, da mir die Idee, die Backup&Recovery-Funktion als App direkt zu integrieren, vom Grundsatz her gut gefällt.

Bis auf Weiteres verfahre ich daher so, wie analog im Artikel Backup und Restore im Kanboard-Container-Land beschrieben. Das dort beschriebene Verfahren lässt sich auch hier anwenden und genügt meinen Anforderungen.

  1. Nextcloud im Container – Teil 1: Der Plan
  2. Nextcloud im Container – Teil 2: Die Ansible-Rolle
  3. Nextcloud im Container – Teil 3: Mit Reverse-Proxy
  4. Nextcloud im Container – Teil 4: Hier und da klemmt es
  5. Nextcloud im Container – Teil 6: Updates
  6. Nextcloud Backup App auf GitHub
  7. How to restore a folder with all files in it? #211
  8. S3 upload still failes with OOM for 1.0.6 #237
  9. Nothing being uploaded to external storage (WebDAV) #238

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.