Docker Compose Project Backup Script

Aus Laub-Home.de Wiki
Zur Navigation springen Zur Suche springen

Docker Compose Projekt Ordner enthalten normalerweise alle möglichen Dateien, damit die Docker Container deploybar sind. Meist liegen darin sogar persistente Ordner oder Dateien, die in die Container gemountet sind, ähnlich der Docker Volumes. Hinzukommt, sollte man mit --build arbeiten, das die Build Dateien ebenfalls in diesem Projekt Ordner liegen. Es liegt nahe, das auch diese Projekt Ordner regelmäßig gesichert werden müssen. Das sichern dieser Dateien ist relativ einfach, da man ihn einfach mit tar sicher kann.

Möchte man wissen, welche Docker Compose Projekte auf einem Docker Host laufen, dann kann man einfach folgenden Befehl dazu verwenden:

for i in $(docker ps --format '{{.Names}}'); do \
docker inspect --format '{{ index .Config.Labels "com.docker.compose.project.working_dir"}}' $i; done \
| sort -u | awk -F'/' '{print $NF}'

Möchte man die Ordnerpfade wissen:

for i in $(docker ps --format '{{.Names}}'); do \
docker inspect --format '{{ index .Config.Labels "com.docker.compose.project.working_dir"}}' $i; done \
| sort -u

Diese beiden for Schleifen holen sich zuerst eine Liste aller laufender Docker Container, um dann bei jedem einzelnen Container das Label mit dem Compose Project Working Dir auszulesen. Mit sort -u filtern wir auf gleiche Pfade.
Nun kann man, da man die Compose Projekt Pfade kennt, diese einfach sichern:

cd /PATH/TO/COMPOSEPROJECT
tar -czf backup.tar.gz .

(mehr Informationen hier.
Um nun das Ganze automatisiert und am Besten regelmäßig per cronjob zu machen, habe ich das kleine Script backup-docker-compose.shgeschrieben. Dieses sichert die angegebenen Docker Compose Projekt Ordner als tar.gz in den definierten Backup Ordner. Die Backupdateien werden mit einem Zeitstempel versehen und können nach X-Tagen (DAYS) automatisch gelöscht werden. Wichtig ist auch, da es sich um ein Lokales Backup handelt, dass man auf jeden Fall die Backup Dateien auf ein anderes System oder in die Cloud (Dropbox, Google Drive und Co) kopiert. Das Script legt man am besten nach /usr/local/sbin/backup-docker-compose.sh und gibt ihm das Execute Recht

Script backup-docker-compose.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/compose
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")
COMPOSE definiert die Compose Projekt Pfade die gesichert werden sollen. Bei mehr als einem Projekt einfach ein Leerzeichen zwischen die verschiedenen Compose Projektnamen setzen. Will man alle bestehenden Compose Projekte sichern, dann helfen die beiden Helferzeilen weiter:
ALLCONTAINER=$(docker ps --format '{{.Names}}')
ALLPROJECTS=$(for i in $ALLCONTAINER; do docker inspect --format '{{ index .Config.Labels "com.docker.compose.project.working_dir"}}' $i; done | sort -u)

Will man diese Ausgabe Filter, kann dies einfach mit grep getan werden (Siehe Kommentare im Script)

COMPOSE="/opt/project1 /opt/project2"
ALLCONTAINER=$(docker ps --format '{{.Names}}')
ALLPROJECTS=$(for i in $ALLCONTAINER; do docker inspect --format '{{ index .Config.Labels "com.docker.compose.project.working_dir"}}' $i; done | sort -u)
COMPOSE=$ALLPROJECTS
ALLCONTAINER=$(docker ps --format '{{.Names}}')
ALLPROJECTS=$(for i in $ALLCONTAINER; do docker inspect --format '{{ index .Config.Labels "com.docker.compose.project.working_dir"}}' $i; done | sort -u)
COMPOSE=$(echo -e "$ALLPROJECTS" | grep 'project1\|project2' | grep -v 'database')

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

#!/usr/bin/env bash
#########################################################################
#Name: backup-docker-compose.sh
#Subscription: This Script backups the docker compose project folder
#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/compose

# 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 Docker Compose Project you want to backup?
# Docker Compose Project pathes separated by space 
#COMPOSE="/opt/project1 /opt/project2"
# you can use the following two big command to read out all compose projects
# uncommend if you like to read automatic all projects:
ALLCONTAINER=$(docker ps --format '{{.Names}}')
ALLPROJECTS=$(for i in $ALLCONTAINER; do docker inspect --format '{{ index .Config.Labels "com.docker.compose.project.working_dir"}}' $i; done | sort -u)
# then to use all projects without filtering it:
#COMPOSE=$ALLPROJECTS
# you can filter all Compose Projects with grep (include only) or grep -v (exclude) or a combination
# to do a filter for 2 or more arguments separate them with "\|"
# example: $(echo $ALLPROJECTS |grep 'project1\|project2' | grep -v 'database')
# to use volumes with name project1 and project2 but not database
#COMPOSE=$(echo -e "$ALLPROJECTS" | grep 'project1\|project2' | grep -v 'database')
COMPOSE=$(echo -e "$ALLPROJECTS" | grep -v 'mailcow-dockerized')


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

for i in $COMPOSE; do
        PROJECTNAME=${i##*/}
        echo -e " Backup von Compose Project:\n  * $PROJECTNAME";
        cd $i
        tar -czf $BACKUPDIR/$PROJECTNAME-$TIMESTAMP.tar.gz .
        # dont delete last old backups!
        OLD_BACKUPS=$(ls -1 $BACKUPDIR/$PROJECTNAME*.tar.gz |wc -l)
        if [ $OLD_BACKUPS -gt $DAYS ]; then
                find $BACKUPDIR -name "$PROJECTNAME*.tar.gz" -daystart -mtime +$DAYS -delete
        fi
done
echo -e "\n$TIMESTAMP Backup for Compose Projects completed\n"

Das Script kann hier heruntergeladen werden: https://raw.githubusercontent.com/alaub81/scripts/master/backup-docker-compose.sh

zum Schluss das execute Recht setzten:

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

Das Script kann nun via

backup-docker-compose.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-compose.sh /etc/cron.daily/backup-docker-compose

Restore

Die Docker-Compose Projekte entpacken wir nach /opt/COMPOSEPROJEKT. Dazu legen wir als ersten den Compose-Projekt Ordner an und entpacken dann das tar.gz in diesen Ordner:

mkdir /opt/COMPOSEPROJEKT
tar -xzvf /backup/compose/COMPOSEPROJEKT-TIMESTAMP.tar.gz -C /opt/COMPOSEPROJEKT/

zum Beispiel für den NGINX Proxy:

mkdir /opt/nginxproxy
tar -xzvf /backup/compose/nginxproxy-202002121020.tar.gz -C /opt/nginxproxy/

Nun starten wir das Compose-Projekt ganz einfach:

cd /opt/nginxproxy
docker-compose up -d

wir können testen ob das Projekt hochfährt in dem wir via netstat schauen ob die Ports 80 und 443 offen sind:

netstat -tulpn |grep -E -w '80 | 443'

die Ausgabe sollte so aussehen:

tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      28669/nginx: master 
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      28669/nginx: master 
tcp6       0      0 :::80                   :::*                    LISTEN      28669/nginx: master 
tcp6       0      0 :::443                  :::*                    LISTEN      28669/nginx: master 

Will man alle gesicherten Compose Projekte auf einmal zurückspielen, kann man sich das Leben ein wenig einfacher machen und die unterstehenden Befehle kopieren. Der TIMESTAMP entspricht dem Datum welches man zurücksichern möchte.

# 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/compose
# Und dann alles entpacken (/opt/COMPOSEPROJEKT)
for i in $(ls *$TIMESTAMP*); do mkdir /opt/${i%%-*} && tar -xzvf $i -C /opt/${i%%-*}; done

nun sollten unter /opt alle Compose Projekte die im Backup Ordner waren zurückgesichert und bereit für den ersten Start sein. diesen kann man entweder händisch, ein Projekt nach dem anderen, oder mit dieser for-Schleife alle auf einmal deployen.

for i in $(find /opt -iname "docker-compose.yml"); do cd ${i%/*} && docker-compose up -d ;done

eines nach dem anderen:

cd /opt/COMPOSEPROJEKT
docker-compose up -d