Betreibt man MySQL als Docker Container, hat man zwar alle Daten in einem persistenten Ordner, jedoch ist es keine gute Idee diese im laufenden Betrieb zu sichern. Ein Backup-Skript erledigt diesen Job zuverlässig.

Backup aller MySQL-Datenbanken von außerhalb des Docker Containers

Das folgende MySQL Backup-Skript läuft ausserhalb des Docker Containers und steuert die Datensicherung über Aufrufe der entsprechenden Befehle im Docker-Container. Alle Datenbanken werden einzeln komprimiert gesichert. Jede tägliche Sicherung hat einen eigenen Ordner. Nach 7 Tagen werden ältere Sicherungen automatisch gelöscht:

#!/bin/bash
#
# backup-mysql.sh 1.0.7
#
# Dumps all databases to seperate files.
# All files are created in a folder named by the current date.
# Folders exceeding the defined hold time are purged automatically.
# 
# (c)2015-2020 Harald Schneider
#

# Setup.start
#

HOLD_DAYS=7 
TIMESTAMP=$(date +"%F")
BACKUP_DIR="./backup"

MYSQL_USR="root"
MYSQL_PWD="YOUR_PASSWORD_HERE"

CONTAINER=dstack-mysql 
MYSQL_CMD="docker exec $CONTAINER /opt/bitnami/mysql/bin/mysql"
MYSQL_DMP="docker exec $CONTAINER /opt/bitnami/mysql/bin/mysqldump"
MYSQL_CHECK="docker exec $CONTAINER /opt/bitnami/mysql/bin/mysqlcheck"

#
# Setup.end


# Check and auto-repair all databases first
#
echo
echo "Checking all databases - this can take a while ..."
$MYSQL_CHECK -u $MYSQL_USR --password=$MYSQL_PWD --auto-repair --all-databases

# Backup
#
echo
echo "Starting backup ..."
mkdir -p "$BACKUP_DIR/$TIMESTAMP"
databases=`$MYSQL_CMD --user=$MYSQL_USR -p$MYSQL_PWD -e "SHOW DATABASES;" | grep -Ev "(Database|information_schema|performance_schema)"`
 
for db in $databases; do
  echo "Dumping $db ..."
  $MYSQL_DMP --force --opt --user=$MYSQL_USR -p$MYSQL_PWD --databases "$db" | gzip > "$BACKUP_DIR/$TIMESTAMP/$db.gz"
done

echo
echo "Cleaning up ..."
find $BACKUP_DIR -maxdepth 1 -mindepth 1 -type d -mtime +$HOLD_DAYS -exec rm -rf {} \;
echo "-- DONE!"

Die Konfiguration wird über folgende Variablen gesteuert:

  • HOLD_DAYS: Die Haltezeit der Datensicherung in Tagen
  • BACKUP_DIR: Der Zielordner für alle Sicherungen
  • MYSQL_USR, MYSQL_PWD: Der MySQL Root-User und dessen Passwort
  • CONTAINER: Der Name des Docker Containers
  • MYSQL_CMD, _DMP und _CHECK: Die Systembefehle zum Überprüfen und Sichern der Datenbanken

Nach Aufruf des Skripts befindet sich die aktuelle Datensicherung im Pfad ./backup.

MySQL-Backup direkt aus dem Docker-Container heraus

Betreibt man Docker unter Windows, lässt sich das Bash-Script leider nur umständlich über WSL oder andere Unix-Umgebungen aufrufen. Viel eleganter ist es, das MySQL Backup-Script in den Docker-Container zu packen und in dessen Linux-Umgebung zu integrieren. Das folgende Beispiel basiert auf dem Bitnami MySQL Image und Docker Compose.

Zuerst modifizieren wir das MySQL Backup-Skript, indem wir die Setup-Sequenz durch diesen Code austauschen:

# Setup.start
#

HOLD_DAYS=7 
TIMESTAMP=$(date +"%F")
BACKUP_DIR="/backup"

MYSQL_USR="root"
MYSQL_PWD=$MYSQL_ROOT_PASSWORD

# Use this inside a Docker container
#
MYSQL_CMD=/opt/bitnami/mysql/bin/mysql
MYSQL_DMP=/opt/bitnami/mysql/bin/mysqldump
MYSQL_CHECK=/opt/bitnami/mysql/bin/mysqlcheck

#
# Setup.end

Ausser HOLD_DAYS sollte keine der Variablen angepasst werden. BACKUP_DIR zeigt auf einen Ordner, der später auf einen persistenten Ordner ausserhalb des Containers gemapped wird. MYSQL_PWD holt sich das aktuelle Root-Passwort direkt aus den Umgebungsvariablen des Containers. Die zum Backup benötigten System-Kommandos sind auf die Pfade des Bitnami Docker Images angepasst.

Das Skript speichern wir im folgenden Pfad: ./resources/bin/backup-mysql.sh.

Das neue Image wird dann über das folgende Dockerfile zusammengebaut:

# Run with 
# docker-compose build

FROM bitnami/mysql:5.7

USER 0
COPY resources/bin/* bin
RUN mkdir /backup
USER 1001

Danach starten wir den Build mit

docker-compose build

Nun ergänzen wir unseren Eintrag in der Datei docker-compose.yml mit dem Pfad-Mapping auf /backup (letzte Zeile). Die Zeile mit “build:” verweist auf den Ordner mit unserem modifizierten Dockerfile.

# --- MySQL 5.7
#
mysql:
  container_name: "dstack-mysql"
  image: bitnami/mysql:5.7
  build: ./build/mysql
  environment:
    - MYSQL_ROOT_PASSWORD=YOUR_PASSWORD_HERE
    - MYSQL_USER=admin
    - MYSQL_PASSWORD=YOUR_PASSWORD_HERE
  ports:
    - '127.0.0.1:3306:3306'
  volumes:
    - ./docker/mysql/data:/bitnami/mysql/data
    - ./docker/mysql/backup:/backup

./docker/mysql/backup ist hierbei unser lokaler Pfad, außerhalb des Docker-Containers und frei wählbar. In diesem Ordner werden dann alle Backups erzeugt.

Die Datensicherung der MySQL-Datenbanken wird dann von außerhalb des Docker Containers über den folgenden Befehl angestossen:

docker exec  -it  dstack-mysql /bin/backup-mysql.sh

dstack-mysql ist der Name des Containers. Der Pfad zum Backup-Script darf hier nicht geändert werden, da er container-intern ist.

Nach Aufruf des Skripts befindet sich die aktuelle Datensicherung im Pfad ./docker/mysql/backup:/backup.