Docker Postgres Backup Script
Bei Postgres Containern legt man die persistenten Datenbank Daten zwar auf einem Docker Volume ab, sichert die Datenbank aber dennoch mit pg_dumpall
. Dies verhindert dass die Daten die man sichert inkonsistent sind, da man beim Abzug der Datenbank Dateien sicherstellen müsste, das keine Datenbankoperatoren zur gleichen Zeit stattfinden. Man müsste also den DB Container vorher stoppen. Deshalb ist es Best Practice die im Container laufende Postgres Datenbank via pg_dumpall
zu sichern. Den Befehl reicht man einfach in den Container rein und lässt den Output, der über stdout
ausgegeben wird in eine Datei laufen. Will man es komprimieren, lässt man den Output vorher durch gzip
laufen. (mehr Informationen hier)
docker exec CONTAINERNAME pg_dumpall -c -U POSTGRESUSER \
| gzip > backup.sql.gz
Will man wissen, welche Container auf dem Postgres Image aufsetzen, welches man ggf. sichern möchte, erledigt das der folgende Befehl:
docker ps --format '{{.Names}}:{{.Image}}' | grep 'postgres' | cut -d":" -f1
--format '{{.Names}}:{{.Image}}'
sorgt dafür das nur der Containername und das verwendete Docker Image, aller laufender Container ausgegeben werden, der grep
Befehl filtert die Ausgabe dann nur auf Postgres Images. Das backup-docker-postgres.sh
Script bündelt die beiden Befehle und sichert somit alle Postgres Datenbanken, die als Container auf dem Docker Host laufen in den definierten Backup Ordner. Die Datenbank Backups 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, sollte man auf jeden Fall die Backup Dateien 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-postgres.sh
. Dieses kann dann via cron-job
automatisch, regelmäßig gestartet werden.
Script backup-docker-postgres.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/postgres
|
DAYS |
definiert die wie lange ein Backup aufgehoben wird | DAYS=2
|
TIMESTAMP |
definiert den Zeitstempel der im Backup Dateiname verwendet wird | TIMESTAMP=$(date +"%Y%m%d%H%M")
|
CONTAINER |
definiert die Container, dessen Datenbanken gesichert werden sollen. Bei mehr als einem Container, einfach ein Leerzeichen zwischen die verschiedenen Container Namen setzen. Hier kann auch mittels docker ps --format '{{.Names}}:{{.Image}}' | grep 'postgres' | cut -d":" -f1
Postgres Image, zu sichern, oder diese mit grep weiter zu filtern. (Siehe Kommentare im Script) |
CONTAINER="postgrescontainer1 postgrescontainer2 postgrescontainer3"
VOLUME=CONTAINER=$(docker ps --format '{{.Names}}:{{.Image}}' | grep 'postgres' | cut -d":" -f1)
CONTAINER=$(docker ps --format '{{.Names}}:{{.Image}}' | grep 'postgres' | cut -d":" -f1 | grep -v 'container1\|container2')
|
Download des Scriptes ist hier möglich: https://github.com/alaub81/backup_docker_scripts/raw/main/backup-docker-postgres.sh
/usr/local/sbin/backup-docker-postgres.sh
#!/usr/bin/env bash
#########################################################################
#Name: backup-docker-postgres.sh
#Subscription: This Script backups docker postgres containers,
#or better dumps their databases 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/postgres
# 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 Containers do you want to backup?
# Container names separated by space
#CONTAINER="postgrescontainer1 postgrescontainer2 postgrescontainer3"
# you can use "$(docker ps --format '{{.Names}}:{{.Image}}' | grep 'postgres' | cut -d":" -f1)"
# for all containers which are using postgres images
#CONTAINER=$(docker ps --format '{{.Names}}:{{.Image}}' | grep 'postgres' | cut -d":" -f1)
# you can filter all containers with grep (include only) or grep -v (exclude) or a combination of both
# to do a filter for 2 or more arguments separate them with "\|"
# example: $(docker ps --format '{{.Names}}:{{.Image}}' | grep 'postgres' | cut -d":" -f1 | grep -v 'container1\|container2')
#CONTAINER=$(docker ps --format '{{.Names}}:{{.Image}}' | grep 'postgres' | cut -d":" -f1 | grep -v 'container1\|container2')
CONTAINER=$(docker ps --format '{{.Names}}:{{.Image}}' | grep 'postgres' | cut -d":" -f1)
### Do the stuff
echo -e "Start $TIMESTAMP Backup for Databases: \n"
if [ ! -d $BACKUPDIR ]; then
mkdir -p $BACKUPDIR
fi
for i in $CONTAINER; do
POSTGRES_USER=$(docker exec $i env | grep POSTGRES_USER |cut -d"=" -f2)
echo -e " create Backup for Database on Container:\n * $i";
docker exec $i pg_dumpall -c -U $POSTGRES_USER | gzip > $BACKUPDIR/$i-$TIMESTAMP.sql.gz
# dont delete last old backups!
OLD_BACKUPS=$(ls -1 $BACKUPDIR/$i*.gz |wc -l)
if [ $OLD_BACKUPS -gt $DAYS ]; then
find $BACKUPDIR -name "$i*.gz" -daystart -mtime +$DAYS -delete
fi
done
echo -e "\n$TIMESTAMP Backup for Databases completed\n"
zum Schluss das execute Recht setzten:
chmod +x /usr/local/sbin/backup-docker-postgres.sh
Das Script kann nun via
backup-docker-postgres.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-postgres.sh /etc/cron.daily/backup-docker-postgres
Restore
Der Restore erfolgt händisch via psql
command. Die Benötigten Variablen (DB Name und DB User und ggf. DB Passwort) bekommt man einfach mit folgendem Befehl ausgeben:
docker exec CONTAINERNAME env
Mit diesen Informationen kann man dann einfach den folgenden Befehl editieren und ausführen
# Restore Aller Datenbanken komprimiert
zcat backup.sql.gz |docker exec -i CONTAINERNAME psql -U POSTGRESUSER
nun sollte die Datenbank mit dem SQL Backup gefüttert sein.
GitHub Repository
Das Ganze könnt ihr auch in GitHub als komplettes Repository finden: