Docker MySQL and MariaDB Backup Script
Bei MySQL oder MariaDB Containern legt man die persistenten Datenbank Daten zwar auf einem Docker Volume ab, sichert die Datenbank aber dennoch mit mysqldump
bzw. bei MariaDB mit mariadb-dump
. 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 MySQL oder MariaDB Datenbank via mysqldump
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)
# MySQL DB
docker exec -e MYSQL_PWD=ROOTPASSWORT \
DBCONTAINERNAME /usr/bin/mysqldump -u root DATABASENAME \
| gzip > backup.sql.gz
# MariaDB
docker exec -e MYSQL_PWD=ROOTPASSWORT \
DBCONTAINERNAME /usr/bin/mariadb-dump -u root DATABASENAME \
| gzip > backup.sql.gz
Will man wissen, welche Container auf dem MySQL oder MariaDB Image aufsetzen, welches man ggf. sichern möchte, erledigt das der folgende Befehl:
docker ps --format '{{.Names}}:{{.Image}}' | grep 'mysql\|mariadb' | 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 MySQL und MariaDB Images. Das backup-docker-mysql.sh
Script bündelt die beiden Befehle und sichert somit alle MySQL/MariaDB 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-mysql.sh
. Dieses kann dann via cron-job
automatisch, regelmäßig gestartet werden.
Script backup-docker-mysql.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/mysql
|
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")
|
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 'mysql\|mariadb' | cut -d":" -f1
mysql oder mariadb Image, zu sichern, oder diese mit grep weiter zu filtern. (Siehe Kommentare im Script) |
CONTAINER="mysqlcontainer 1 mysqlcontainer2 mysqlcontainer3"
VOLUME=CONTAINER=$(docker ps --format '{{.Names}}:{{.Image}}' | grep 'mysql\|mariadb' | cut -d":" -f1)
CONTAINER=$(docker ps --format '{{.Names}}:{{.Image}}' | grep 'mysql\|mariadb' | cut -d":" -f1 | grep -v 'container1\|container2')
|
Download des Scriptes hier möglich: https://github.com/alaub81/backup_docker_scripts/raw/main/backup-docker-mysql.sh
/usr/local/sbin/backup-docker-mysql.sh
#!/usr/bin/env bash
#########################################################################
#Name: backup-docker-mysql.sh
#Subscription: This Script backups docker mysql or mariadb containers,
#or better dumps their database to a backup directory
##by A. Laub
#andreas[-at-]laub-home.de
#
# More informations:
# https://www.laub-home.de/wiki/Docker_MySQL_and_MariaDB_Backup_Script
#
# Restore:
# docker exec CONTAINERNAME env
# zcat BACKUPFILE.sql.gz | docker exec -i CONTAINERNAME /usr/bin/mysql -u root --password=ROOTPASSWORD DATABASENAME
#
#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/mysql
# 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="mysqlcontainer1 mysqlcontainer2 mysqlcontainer3"
# you can use "$(docker ps --format '{{.Names}}:{{.Image}}' | grep 'mysql\|mariadb' | cut -d":" -f1)"
# for all containers which are using mysql or mariadb images
#CONTAINER=$(docker ps --format '{{.Names}}:{{.Image}}' | grep 'mysql\|mariadb' | 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 'mysql\|mariadb' | cut -d":" -f1 | grep -v 'container1\|container2')
#CONTAINER=$(docker ps --format '{{.Names}}:{{.Image}}' | grep 'mysql\|mariadb' | cut -d":" -f1 | grep -v 'container1\|container2')
CONTAINER=$(docker ps --format '{{.Names}}:{{.Image}}' | grep 'mysql\|mariadb' | 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
MYSQL_PWD=$(docker exec $i env | grep MYSQL_ROOT_PASSWORD | cut -d"=" -f2)
# check for dump method mariadb / mysql
if docker exec $i test -e /usr/bin/mysqldump; then
# Get a list of databases in the container
DATABASES=$(docker exec -e MYSQL_PWD=$MYSQL_PWD $i mysql -uroot -s -e "show databases" | grep -Ev "(Database|information_schema|performance_schema|mysql)")
# Loop through each database and create a backup
for MYSQL_DATABASE in $DATABASES; do
# Start Backup
echo -e " create MYSQL Backup for Database on Container:\n * $MYSQL_DATABASE DB on $i";
docker exec -e MYSQL_DATABASE=$MYSQL_DATABASE -e MYSQL_PWD=$MYSQL_PWD \
$i /usr/bin/mysqldump -u root $MYSQL_DATABASE | gzip > $BACKUPDIR/$i-$MYSQL_DATABASE-$TIMESTAMP.sql.gz
done
elif docker exec $i test -e /usr/bin/mariadb-dump; then
# Get a list of databases in the container
DATABASES=$(docker exec -e MYSQL_PWD=$MYSQL_PWD $i mariadb -uroot -s -e "show databases" | grep -Ev "(Database|information_schema|performance_schema|mysql)")
# Loop through each database and create a backup
for MYSQL_DATABASE in $DATABASES; do
# Start Backup
echo -e " create MariaDB Backup for Database on Container:\n * $MYSQL_DATABASE DB on $i";
docker exec -e MYSQL_DATABASE=$MYSQL_DATABASE -e MYSQL_PWD=$MYSQL_PWD \
$i /usr/bin/mariadb-dump -u root $MYSQL_DATABASE | gzip > $BACKUPDIR/$i-$MYSQL_DATABASE-$TIMESTAMP.sql.gz
done
else
echo " ERROR: cannot find dump command for container $i!"
fi
# 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-mysql.sh
Das Script kann nun via
backup-docker-mysql.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-mysql.sh /etc/cron.daily/backup-docker-mysql
Restore
Der Restore erfolgt händisch via mysql
command. Die Benötigten Variablen (DB Name und Root 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
zcat BACKUPFILE.sql.gz | docker exec -i CONTAINERNAME /usr/bin/mysql -u root --password=ROOTPASSWORD DATABASENAME
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: