MySQL Datenbank Backup

Unten stehendes Script kann auf Linux, Solaris und anderen Unix-Varianten als täglichen Cronjob gestartet werden. Es erzeugt MySQL Datenbank Dumps jeder einzelnen Datenbank und konsolidiert durch einen einfachen Recycling Algorithmus ältere Dumps, so dass die lokale Festplatte oder das NFS-Share nicht vollläuft.

Programmaufruf wie folgt:

/usr/local/bin/mysqlbackup.sh dbhost1.example.com:3306 dbhost2.example.com:3306

In der MySQL Datenbank muss ein User mit folgenden Privilegien erstellt werden:

grant show databases,show view,file,select,lock tables \
on *.* to 'backup'@'backuphost.example.com' identified by 'changeme';

In der Konfigurationsdatei .my.cnf im Benutzerverzeichnis muss der Datenbankbenutzer und das Passwort eingetragen werden, so dass es nicht als Prozessargument in der Prozesstabelle erscheint oder im Script eingetragen werden muss.

[client]
user=backup
password=changeme

[mysqldump]
max-allowed-packet=2147483648
quote-names=true
verbose=true

Hier das Bash-Script:

#!/bin/bash

PATH="/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin"
BACKUPDIR="/var/backup/mysql"
CONFIG="/home/user/.my.cnf"
EXCLUDEDB='^(Database|information_schema|performance_schema)$'
MAILFROM="backup@example.com"
MAILTO="user@example.com"

# Simple housekeeping
# Daily backups with week day names
# Monthly backups on the last day of month
# Yearly backups on last day of december

year=$(date "+%Y")
month=$(date "+%m")
monthname=$(date "+%B")
day=$(date "+%d")
dayname=$(date "+%A")

d=28
if (( $year %   4 == 0 )); then d=29; fi
if (( $year % 100 == 0 )); then d=28; fi
if (( $year % 400 == 0 )); then d=29; fi

case "$month:$day" in
  01:31) timestamp="monthly_${month}"   ;;
  02:$d) timestamp="monthly_${month}"   ;;
  03:31) timestamp="monthly_${month}"   ;;
  04:30) timestamp="monthly_${month}"   ;;
  05:31) timestamp="monthly_${month}"   ;;
  06:30) timestamp="monthly_${month}"   ;;
  07:31) timestamp="monthly_${month}"   ;;
  08:31) timestamp="monthly_${month}"   ;;
  09:30) timestamp="monthly_${month}"   ;;
  10:31) timestamp="monthly_${month}"   ;;
  11:30) timestamp="monthly_${month}"   ;;
  12:31) timestamp="yearly_${year}"   ;; 
  *)     timestamp="daily_${dayname}" ;;
esac

for hostport in $@; do
  echo ""
  echo "*******************************************************************************"
  echo "Backing up MySQL on $hostport to $BACKUPDIR" 
  echo "*******************************************************************************"
  echo ""
  host=$(echo $hostport | awk -F: '{print $1}')
  port=$(echo $hostport | awk -F: '{print $2}')

  hostdir="$BACKUPDIR/$hostport"
  test -d $hostdir || mkdir -p $hostdir

  databases=$(echo "show databases;" \
    | mysql --defaults-file="$CONFIG" -h "$host" -P "$port" | grep -Ev "$EXCLUDEDB")

  for db in $databases; do
    echo -n "Dumping database $db ... "

    dbdir="$hostdir/$db"
    dumpfile="$dbdir/${db}.${timestamp}.sql"
    logfile="$dbdir/${db}.${timestamp}.log"

    test -d $dbdir || mkdir -p $dbdir
    mysqldump --defaults-file="$CONFIG" --log-error="$logfile" \
      -h "$host" -P "$port" "$db" >$dumpfile
    retval=$?
    chmod 0644 $logfile
    chmod 0400 $dumpfile

    case $retval in
      0) echo "OK" ;;
      *) echo "FAILED"
         ( echo "From: $MAILFROM"
           echo "To: $MAILTO"
           echo "Subject: Error backing up MySQL database $db on $hostport"
           echo ""
           echo "The command"
           echo "mysqldump --defaults-file=$CONFIG --log-error=$logfile -h $host -P $port $db"
           echo "returned value: $retval"
           echo ""
           echo "Error log: $logfile"
           echo "$(cat $logfile)"
           echo "."
         ) | sendmail -t
        ;;
    esac 
  done
done