Restic für Backups nutzen

Für Backups nutze ich seit vielen Jahren rsync-time-backup. Allerdings hörte ich in letzter Zeit viel gutes über die freie Software Restic. Restic selbst wird über GitHub entwickelt und ist unter der BSD-Lizenz in der Zweiklausel-Version lizenziert. Unter Linux und macOS kann Restic einfach über entsprechende Paketmanager installiert werden:

brew install restic

Restic arbeiten mit sogenannten Repositories. In einem Repository befindet sich das entsprechende Backup mit all seinen Versionen. Um ein solchen Repository anzugelegen wirde der Befehl:

restic init --repo ./

genutzt. Bei Restic ist jedes Backup automatisch verschlüsselt, sodass bereits beim Anlegen eines Backups ein entsprechendes Passwort vergeben werden muss. Die Daten werden mit AES, bei 256 Bit, verschlüsselt.

restic.net

Danach kann theoretisch mit dem ersten Backup begonnen werden:

restic -r /Volumes/Volume/ResticRepository backup /Users/User

In diesem Fall würde der Ordner /Users/User/ in das Restic-Repository gesichert. Bevor das Backup startet, muss das entsprechende Passwort des Repositorys eingegeben werden. Anschließend wird der Nutzer über den Fortschritt des Prozesses informiert:

repository 567f35fa opened successfully, password is correct
created new cache in /Users/User/Library/Caches/restic
[0:09] 10 files 4.296 MiB, total 451 files 224.551 MiB, 0 errors
/Users/User/System/btrfstune
/Users/User/System/busybox
...

Nach dem Abschluss des Backups erscheint eine entsprechende Meldung im Terminal:

Files:          25 new,     0 changed,     0 unmodified
Dirs:            2 new,     0 changed,     0 unmodified
Added to the repo: 616.694 KiB

processed 25 files, 615.493 KiB in 0:00
snapshot 6c0d7af6 saved

Nun verfügt der Nutzer über ein Backup Repository mit einem bzw. mehreren Snapshots. Die angelegten Snapshots können über dem Befehl:

restic -r /Volumes/Volume/ResticRepository snapshots

angezeigt werden. Der Nutzer erhält eine entsprechende Ausgabe im Terminal:

repository fd5947c7 opened successfully, password is correct
ID        Time                 Host        Tags        Paths
------------------------------------------------------------------------------
6c0d7af6  2020-01-05 10:09:15  Earth.local             /Users/User/System
31d3160f  2020-01-05 10:11:30  Earth.local             /Users/User/System
38d6cbca  2020-01-05 10:15:09  Earth.local             /Users/User/System
ea96fa22  2020-01-05 10:15:20  Earth.local             /Users/User/System
------------------------------------------------------------------------------
4 snapshots

Das beste Backup nutzt nichts, wenn es nicht wiederhergestellt werden kann. Dazu wird die Option restore genutzt:

restic -r /Volumes/Volume/ResticRepository restore 38d6cbca --target /Users/User/System

Anschließend wird der gewünschte Snapshop wieder hergestellt:

repository fd5947c7 opened successfully, password is correct
restoring  to /Users/User/System

Soll anstatt eines bestimmten Snapshot der letzte Snapshot wiederhergestellt werden so wird anstatt einer Snapshot-ID einfach latest als Wert angegeben. Soll nur eine einzelne Datei wiederhergestellt werden, ist das komplette zurückspielen eines Backup eher suboptimal. Für einen solchen Fall können die Snapshots im Dateisystem gemountet werden.

restic -r /Volumes/Volume/ResticRepository mount /Volumes/Volume/ResticRepositoryMounted

Anschließend wird das Repository im Dateisystem unter dem angegebenen Mountpoint eingebunden:

repository fd5947c7 opened successfully, password is correct
Now serving the repository at /Volumes/Volume/ResticRepositoryMounted
When finished, quit with Ctrl-c or umount the mountpoint.

Im Gegensatz zu den Befehlen zur Wiederherstellung des Backups muss beim Mounten keine Snapshot-ID angegeben werden. In der gemounteten Struktur werden stattdessen alle Snapshots angezeigt. Die gewünschte Datei zur Wiederherstellung kann somit gesucht und wiederhergestellt werden.

Beim Backup sollen in vielen Fällen bestimmte Dateien nicht gesichert werden. Dies können z.B. temporäre Dateien oder Caches sein. Um diese Datei vom Backup auszuschließen, kann ein sogenanntes Exclude File genutzt werden:

restic -r /Volumes/Volume/ResticRepository backup /Users/User/System --exclude-file="/Users/User/excludes.txt"

Eine solche Datei könnte z.B. wie folgt aussehen:

+ /etc/
+ /home/
+ /root/
+ /srv/
+ /usr/local/
+ /var/

- /*
- /var/cache/*
- /var/lib/lxcfs/*
- /var/log/*
- /var/tmp/*

Neben diesen Basisfunktionalitäten, verfügt Restic über weitere Funktionen, so z.B. zum Löschen alter Snapshots nach bestimmten Regeln. Alles in allem wirkt Restic für mich wie eine durchdachte Backup-Lösung, deren Nutzung durchaus ins Auge gefasst werden kann.

Mapcrafter unter Ubuntu aufsetzen

Eine Welt in Minecraft hat die Angewohnheit, mit der Zeit immer größer zu werden. In einem solchen Fall ist eine Karte natürlich sehr praktisch. Mithilfe des Tools Mapcrafter kann eine solche Karte erstellt werden. Der Mapcrafter erzeugt neben den Kartenkacheln auch eine JavaScript-Anwendung, mit der diese betrachtet werden können.

Eine Mapcrafter-Karte

Im ers­ten Schritt muss das Mapcrafter-Repository mittels:

git clone https://github.com/mapcrafter/mapcrafter.git

auf den Ser­ver geholt werden. Mit dem Befehl wird das Git-Repository, in welchem sich der Quelltext befindet, auf den Server geklont. Im Git-Kontext bedeutet dies, dass das gesamte Repository heruntergeladen wird. Falls Git nicht installiert ist, muss das entsprechende Paket mittels:

apt install git

installiert werden. Die aktuelle Entwicklung findet im Branch world113 statt, so das in diesen gewechselt werden muss:

cd mapcrafter
git checkout world113

Bevor die Software kompiliert werden kann, müssen einige Abhängigkeiten installiert werden:

apt install build-essential cmake libboost-all-dev libjpeg-dev libpng-dev

Anschließen kann die Software kompiliert und installiert werden:

cmake .
make 
make install
ldconfig

Nach der Installation könnte Mapcrafter über den Befehl:

/usr/local/bin/mapcrafter -c example.conf -b -j 4

ausgeführt werden. Allerdings muss vor dem ersten Start noch eine Konfigurationsdatei erstellt werden. In dieser Konfigurationsdatei ist definiert, wie die Karte gerendert werden soll. Die Datei und die Skripte zur Aktualisierung werden im Kontext des Nutzers minecraft angelegt:

su minecraft
cd
mkdir map
nano example.conf

Exemplarisch könnte die Konfigurationsdatei wie folgt aussehen:

output_dir = /home minecraft/map
background_color = #000000

[marker:teleporter]
name = Teleporter
prefix = Hauptteleporter
icon = beacon.png
icon_size = [32, 32]
show_default = false
title_format = %(textp)

[marker:signs]
name = Signs
icon = sign.png
icon_size = [32, 32]
show_default = false
title_format = %(textp)

[world:world]
input_dir = world
world_name = Example

[global:map]
image_format = png
png_indexed = true
rotations = top-left
texture_size = 16

[map:day_isometric]
name = Day (isometric)
render_view = isometric
render_mode = daylight
world = world

Nachdem die Konfigurationsdatei angelegt wurde, kann die Karte testweise mittels des Befehls:

/usr/local/bin/mapcrafter -c example.conf -b -j 4

erzeugt werden. Damit die Aktualisierung später automatisch geschieht, werden die Befehle zur Aktualisierung der Skripte in eine Skript-Datei geschrieben:

nano updateMap.sh

Diese Datei wird mit folgendem Inhalt befüllt:

#!/bin/bash
/usr/local/bin/mapcrafter -c example.conf -b -j 4
/usr/local/bin/mapcrafter_markers -v -c example.conf

Anschließend soll ein Cronjob eingerichtet werden. Dazu wird der Crontab-Editor geöffnet:

crontab -e

In der sich öffnende Datei muss nun folgende Zeile hinzugefügt werden:

0    1    * * *   (. ~/.profile; /usr/bin/screen -dmS mapcrafter /home/minecraft/updateMap.sh)

Danach kann die Datei geschlossen werden. Der Cronjob startet nun um 1 Uhr die tägliche Aktualisierung der Karte.

Maven-Repository in Eigenregie hosten

Wenn mittels Maven eine Abhängigkeit zur pom.xml-Datei, wie in folgendem Beispiel, hinzugefügt wird:

<dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>slf4j-api</artifactId>
	<version>1.7.26</version>
</dependency>

versucht Maven diese Abhängigkeit von Maven Central, dem zentralen Repository, zu beziehen. Es ist allerdings möglich Abhängigkeiten aus anderen Repositories zu beziehen. Dazu muss der repositories-Block zur pom.xml hinzugefügt werden.

<repositories>
	<repository>
		<id>example</id>
		<url>https://repository.example.org</url>
	</repository>
</repositories>

Aus Nutzersicht ist die Konfiguration von Maven damit erledigt. Soll ein solches Maven-Reposity aufgesetzt werden, ist dies relativ einfach möglich. Dazu wird ein Verzeichnis per HTTP über den Webserver Nginx ausgeliefert. Innerhalb dieses Verzeichnisses wird ein gesicherter Ordner erstellt, welcher über WebDAV erreicht werden kann. Die entsprechende Nginx-Konfiguration sieht für diesen Fall wie folgt aus:

server {
        listen   443 ssl;
        listen [::]:443 ssl;

        ssl_certificate /etc/letsencrypt/live/repository.example.org/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/repository.example.org/privkey.pem;

        root /var/www/example/repository;

        server_name repository.example.org;

        location / {
                autoindex     on;
        }

        location /upload {
                dav_methods     PUT DELETE MKCOL COPY MOVE;
                dav_ext_methods   PROPFIND OPTIONS;

                dav_access    user:rw group:rw all:rw;

                create_full_put_path  on;

                autoindex     on;

                auth_basic "restricted";
                auth_basic_user_file /var/www/example/repository/upload/.htpasswd;
        }
}

Die .htpasswd-Datei, welche für die Authentifizierung benötigt wird, kann mit dem Tool htpasswd erstellt werden:

htpasswd -c .htpasswd nutzer1

Bei der Nutzung wird das gewünschte Passwort erfragt. Soll ein weiterer Nutzer hinzugefügt werden, so muss der Parameter -c entfernt werden:

htpasswd .htpasswd nutzer2

Anschließend wird die Konfiguration von Nginx mittels:

service nginx reload

aktualisiert. Danach kann WebDAV für die Ressource verwendet werden. In der pom.xml-Datei für das Projekt, welches ein Artefakt für das Repository erzeugt, wird der build-Bereich erweitert und der distributionManagment-Bereich hinzugefügt:

            </plugin>
        </plugins>
        <extensions>
            <extension>
                <groupId>org.apache.maven.wagon</groupId>
                <artifactId>wagon-webdav-jackrabbit</artifactId>
                <version>3.2.0</version>
            </extension>
        </extensions>
    </build>
    <distributionManagement>
        <repository>
            <id>example</id>
            <url>dav:https://repository.example.org/upload/</url>
            <layout>default</layout>
        </repository>
    </distributionManagement>
</project>

Im Extension-Bereich wird das Wagon-Plugin für WebDAV aktiviert. Dieses sorgt dafür das die Artefakte per WebDAV zum Repository hochgeladen werden. In dem distributionManagment-Bereich wird die WebDAV-URL definiert. Wenn nun ein:

mvn deploy

durchgeführt wird, wird dies allerdings nicht funktionieren. Hintergrund ist das der upload-Ordner per Basic authentication geschützt ist. Die Zugangsdaten für diese Authentifikation müssen noch hinterlegt werden. Natürlich werden diese nicht in der pom.xml hinterlegt, da dies aus Gründen der Sicherheit keine gute Idee wäre. Stattdessen werden die Daten in der settings.xml hinterlegt. Diese befindet sich im Pfad:

~/.m2/settings.xml

In dieser Datei wird eine server-Sektion mit den Zugangsdaten hinzugefügt:

<settings>
	<servers>
		<server>
			<id>example</id>
			<username>example</username>
			<password>password</password>
		</server>
	</servers>
</settings>

Anschließend kann das Artefakt erfolgreich mittels:

mvn deploy

in das Repository hochgeladen werden. Problematisch ist das sich die Daten nur im upload-Verzeichnis und nicht im eigentlichen Verzeichnis des Repository liegen. Zur Lösung hierfür wird ein Cronjob, im Kontext des Nutzers www-data, angelegt:

sudo -u www-data crontab -e

Ziel des Cronjobs ist es die Daten aus dem upload-Verzeichnis regelmäßig in das eigentliche Verzeichnis des Repository zu kopieren:

*/5  *    * * *   cp /var/www/example/repository/upload/* /var/www/example/repository/ -r

Damit wird alle 5 Minuten der Inhalt des uploadVerzeichnisses in das Repository kopiert. Ein Verschieben kann leider nicht durchgeführt werden, da die Metadaten beim jeden Deployment von Maven eingelesen werden und erweitert werden. Hier könnten Optimierungen durchgeführt werden, so das alle Dateien bis auf die Metadaten verschoben werden. Soll ein nicht öffentliches Repository erstellt werden, kann auf den zusätzlichen upload-Ordner verzeichnet werden und das Hauptverzeichnis selber per WebDAV befüllt werden. So lange die Zugangsdaten für den Server in der settings.xml-Datei hinterlegt sind, können seitens Maven die entsprechenden Artefakte bezogen werden.

Git-Branch ohne History erstellen

Eine wichtige Eigenschaft moderner Versionskontrollsysteme ist die Möglichkeit Branches zu erstellen. Ein neu erstellter Branch stellt aus Anwendersicht eine Kopie des Quellbranches da. Manchmal soll allerdings ein Branch erstellt werden, welcher nicht von der Versionsgeschichte eines Quellbranches beeinflusst ist. Unter Git kann ein solcher Branch mit dem Befehl:

git checkout --orphan branchName

erstellt werden. Dadurch wird ein Branch ohne Elternteil erstellt. Dies wiederum führt dazu das der Branch keinerlei Versionsgeschichte verfügt und unabhängig von anderen Branches des gleichen Repository existiert.

Git Repository mit Submodulen klonen

In der Git Welt existieren sogenannte Submodule. Diese kann man dem Repository hinzufügen und damit ein Git Repository in ein anderes Git Repository einbetten. Nach dem klonen eines solchen Projektes mittels:

git clone git@example.org:seeseekey/project.git

wird man feststellen das sich nur das Hauptprojekt auf der Festplatte befindet. Möchte man die Submodule ebenfalls mit klonen so muss der Parameter recursive zusätzlich übergeben werden:

git clone --recursive git@example.org:seeseekey/project.git

Mit Hilfe des Parameters werden alle Submodule ebenfalls geklont und landen somit auf der Festplatte.