Docker Volume Backup Script

Aus Laub-Home Wiki

Um bei Docker Daten persistent zu machen, wird empfohlen das durch sogenannte docker volumes zu machen. Eine Liste aller Docker Volumes, die auf einem Docker Host vorhanden sind bekommt man ganz einfach durch den folgenden Befehl:

docker volume ls -q

-q zeigt nur die Volume Namen an, nicht den Driver Um nun diese richtig zu sichern, wird mittels "Hilfscontainer" das Volume gemountet und dann via tar Pipe komprimiert (gzip) gesichert (mehr Informationen hier. Um das Ganze automatisiert, am besten regelmäßig per cronjob zu machen, habe ich das kleine Script backup-docker-volumes.shgeschrieben. Dieses sichert die angegebenen Docker Volumes via tar.gz in einen Backup Ordner. Die Volume Backups werden mit einem Zeitstempel versehen und können nach X-Tagen automatisch gelöscht werden. Wichtig ist auch, da es sich um ein Lokales Backup handelt, sollte man auf jeden Fall die Backup Dateien noch auf irgendein anderes System oder in die Cloud (Dropbox, Google Drive und Co) sichern. Das Script legt man am besten nach /usr/local/sbin/backup-docker-volume.sh

Script backup-docker-volume.sh

Das Script kann einfach in /usr/local/sbin/ angelegt werden. Nach dem Anlegen das Execute Recht vergeben und die folgenden Parameter im Script nach belieben definieren:

Parameter Definition Beispiel
BACKUPDIR definiert den Backup Ordner, sollte er nicht existieren, wird er automatisch angelegt
BACKUPDIR=/backup/volumes
DAYS definiert die wie lange ein Backup aufgehoben wird
DAYS=3
TIMESTAMP definiert den Zeitstempel der im Backup Dateiname verwendet wird
TIMESTAMP=$(date +"%Y%m%d%H%M")
VOLUME definiert die Volumes die gesichert werden sollen. Bei mehr als einem Volume einfach ein Leerzeichen zwischen die verschiedenen Volume Namen setzen. Hier kann auch mittels docker volume ls -q gearbeitet werden, um zum Beispiel alle Volumes zu sichern, oder diese mit grep zu filtern. (Siehe Kommentare im Script)
VOLUME="project1_data_container1 project2_data_container1"
VOLUME=$(docker volume ls -q)
VOLUME=$(docker volume ls -q |grep 'project1\|project2' | grep -v 'database')
MEMORYLIMIT Hier kann ein Memory Limit für den Docker Container, der für das Backup verwendet wird, festgelegt werden. Dafür muss aber vom Kernel Supporten werden.
MEMORYLIMIT="-m 35m"

Download des Skriptes hier möglich: https://github.com/alaub81/backup_docker_scripts/raw/main/backup-docker-volume.sh

/usr/local/sbin/backup-docker-volume.sh

#!/bin/bash
#########################################################################
#Name: backup-docker-volumes.sh
#Subscription: This Script backups docker volumes to a backup directory
##by A. Laub
#andreas[-at-]laub-home.de
#
#License:
#This program is free software: you can redistribute it and/or modify it
#under the terms of the GNU General Public License as published by the
#Free Software Foundation, either version 3 of the License, or (at your option)
#any later version.
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
#or FITNESS FOR A PARTICULAR PURPOSE.
#########################################################################
#Set the language
export LANG="en_US.UTF-8"
#Load the Pathes
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# set the variables

# Where to store the Backup files?
BACKUPDIR=/backup/volumes

# How many Days should a backup be available?
DAYS=2

# Timestamp definition for the backupfiles (example: $(date +"%Y%m%d%H%M") = 20200124-2034)
TIMESTAMP=$(date +"%Y%m%d%H%M")

# Which Volumes you want to backup?
# Volumenames separated by space 
#VOLUME="project1_data_container1 project2_data_container1"
# you can use "$(docker volume ls  -q)" for all volumes
#VOLUME=$(docker volume ls -q)
# you can filter all Volumes with grep (include only) or grep -v (exclude) or a combination
# to do a filter for 2 or more arguments separate them with "\|"
# example: $(docker volume ls -q |grep 'project1\|project2' | grep -v 'database')
# to use volumes with name project1 and project2 but not database
#VOLUME=$(docker volume ls -q |grep 'project1\|project2' | grep -v 'database')
VOLUME=$(docker volume ls -q | grep -v 'mailcowdockerized\|_db')

# if you want to use memory limitation. Must be supported by the kernel.
#MEMORYLIMIT="-m 35m"

### Do the stuff
echo -e "Start $TIMESTAMP Backup for Volumes:\n"
if [ ! -d $BACKUPDIR ]; then
        mkdir -p $BACKUPDIR
fi

for i in $VOLUME; do 
        echo -e " Backup von Volume:\n  * $i"; 
        docker run --rm \
        -v $BACKUPDIR:/backup \
        -v $i:/data:ro \
        -e TIMESTAMP=$TIMESTAMP \
        -e i=$i ${MEMORYLIMIT} \
        --name volumebackup \
        alpine sh -c "cd /data && /bin/tar -czf /backup/$i-$TIMESTAMP.tar.gz ."
        #debian:stretch-slim bash -c "cd /data && /bin/tar -czf /backup/$i-$TIMESTAMP.tar.gz ."
        # dont delete last old backups!
        OLD_BACKUPS=$(ls -1 $BACKUPDIR/$i*.tar.gz |wc -l)
        if [ $OLD_BACKUPS -gt $DAYS ]; then
                find $BACKUPDIR -name "$i*.tar.gz" -daystart -mtime +$DAYS -delete
        fi
done
echo -e "\n$TIMESTAMP Backup for Volumes completed\n"

zum Schluss das execute Recht setzten:

chmod +x /usr/local/sbin/backup-docker-volume.sh

Das Script kann nun via

backup-docker-volume.sh

ausgeführt werden.

Regelmäßiges Backup einrichten (cron-job)

Will man nun das Script regelmäßig, zum Beispiel täglich ausführen, reicht es einen Symlink in das cron.daily Verzeichnis zu legen:

ln -s /usr/local/sbin/backup-docker-volume.sh /etc/cron.daily/backup-docker-volume

Restore

Der Restore wird mittels einem einen Hilfscontainer gemacht, der A das Volume mountet in dem die Backup Dateien (tar.gz) liegen und B das Docker Volume, in das wir die Backup Dateien entpacken wollen. Bitte beim unterstehenden die folgenden Dinge anpassen:

  • DOCKER-VOLUME-NAME
  • BACKUPFILE.tar.gz
docker run --rm \
        -v /backup/volumes:/backup \
        -v DOCKER-VOLUME-NAME:/data \
        debian:stretch-slim bash -c "cd /data && /bin/tar -xzvf /backup/BACKUPFILE.tar.gz"

Wenn ihr das oben stehende Backup Script verwendet habt, könnt ihr alles auf einen Schlag machen. Dafür einfach in den Volume Backup Ordner /backup/volumes wechseln und die for-Schleife kopieren und ausführen. Der Timestamp entspricht dem Datum des gewünschten Backup Files.

# zuerst das richtige Datum der Restore Dateien wählen, 
# sollte im besten Fall das letzt Verfügbare Datum sein
# also den Timestamp (YYYYMMDD) setzen
TIMESTAMP=20200212
# dann ins Verzeichniss wechseln
cd /backup/volumes
# dann den restore anstoßen
for i in $(ls *$TIMESTAMP*); do 
    docker run --rm \
        -v /backup/volumes:/backup \
        -v ${i%%-[0-9]*}:/data \
        debian:stretch-slim bash -c "cd /data && /bin/tar -xzvf /backup/$i"
done

Nun sollten alle Volumes wiederhergestellt sein. Am besten ein kurzer Check in /var/lib/docker/volumes machen.

ls -la /var/lib/docker/volumes/*/*

GitHub Repository

Das Ganze könnt ihr auch in GitHub als komplettes Repository finden: