Voraussetzung dafür ist Webhosting-Paket mit Shell-Zugang. Natürlich gibt es eine Vielzahl von Tools (z.B. MySQLDumper oder Shell-Scripte), wir werden automyslbackup benutzen. Hinweis vorweg: Die aktuelle Version von automysqlbackup ist v3.0-RC6, und das seit Dezember 2011. Ich setze diese Version seit Jahren sowohl beruflich als auch privat ein und habe noch keine Probleme gehabt.
Neulich wollte ich für einen Kunden ein automatisches MySQL-Backup einrichten. Natürlich soll das System nicht stur jede Nacht nur Backups anegen, vielmehr soll es die Backups nach dem Großvater-Vater-Sohn-Prinzip rotieren. Mein Kunde hostet bei all-inkl.com (es gibt schlimmeres), hier muss auf einige Dinge geachtet werden, die ich im Folgenden beschreibe.
Die erste Hürde ist, das all-inkl.com erst ab dem "Premium" Paket ssh-Zugang bietet – wer also "Privat" oder "PrivatPlus" hat, muss sich anders behelfen.
Wer diese Hürde genommen hat loggt sich per ssh ein, lädt automysqldumper in ein temporäres Verzeichnis herunter und entpackt das file.
wget --trust-server-name http://sf.net/projects/automysqlbackup/files/AutoMySQLBackup/AutoMySQLBackup%20VER%203.0/automysqlbackup-v3.0_rc6.tar.gz/download
Das Archiv enthält folgende 6 Dateien:
- automysqlbackup
- automysqlbackup.conf
- CHANGELOG
- install.sh
- LICENSE
- README
automysqlbackup ist das eigentliche Programm, ein handelt sich um ein bash-script
automysqlbackup.conf ist ein globales Config-File
install.sh der Installer
CHANGELOG, LICENSE und README sind – naja, was der Name nahelegt.
Da das Installationsscript in Verzeichnisse schreiben möchte, auf die man bei einem shared hosting account natürlich keinen Zugriff hat (z. B. /etc), machen wir eine "manuelle Installation". Wir kopieren also einfach die benötigten Dateien in ein Verzeichnis unserer Wahl (ich nehme /.automysqlbackup). Nach der Konfiguration starte ich einen Test, der aber mit folgendem Fehler endet:
/.automysqlbackup/bin/automysqlbackup: line 1058: /dev/fd/62: No such file or directory
Nanu, was ist denn das? Etwas im Script graben… Hat was mit redirection zu tun… Ein einfacher Test bringt Klarheit:
diff <(echo "a") <(echo "b")
Wenn das den gleichen Fehler zeigt, dann fehlt vermutlich das device /dev/fd, was dazu führt das bash redirection nicht geht. Auf einem VPS könnte das einfach mit einem Symlink gelöst werden (ln -s /proc/self/fd /dev/fd), aber auf einem shared account geht das natürlich nicht.
Lösung
Wenn also redirection nicht geht, dann bleibt nur, das automysqlbackup script zu editieren und eine temporäre Datei zu benutzen. Wir ändern die Funktion parse_databases() wie folgt: Vorher:
parse_databases() {
# bash 4.x version
#mapfile -t alldbnames < <(mysql --user="${CONFIG_mysql_dump_username}" --password="${CONFIG_mysql_dump_password}" --host="${CONFIG_mysql_dump_host}" --batch --skip-column-names -e "show databases")
alldbnames=()
printf "# Parsing databases ... "
# bash 3.0
local i;i=0;
while read -r; do alldbnames[i++]="$REPLY"; done < <(mysql --user="${CONFIG_mysql_dump_username}" --password="${CONFIG_mysql_dump_password}" --host="${CONFIG_mysql_dump_host}" "${mysql_opt[@]}" --batch --skip-column-names -e "show databases")
unset i
# mkfifo foo || exit; trap 'rm -f foo' EXIT
Nachher:
parse_databases() {
# bash 4.x version
alldbnames_tmp=$(mktemp)
mysql --user="${CONFIG_mysql_dump_username}" --password="${CONFIG_mysql_dump_password}" --host="${CONFIG_mysql_dump_host}" --batch --skip-column-names -e "show databases" > $alldbnames_tmp
mapfile -t alldbnames < $alldbnames_tmp
# mkfifo foo || exit; trap 'rm -f foo' EXIT
Um im Falle eines Abbruchs das tmpfile nicht liegen zu lassen sollte ein trap benutzt werden, der es dann löscht. Dazu gibt es schon die Funktion mail_cleanup(), die laut Kommentar bei EXIT, SIGHUP, SIGINT, SIGQUIT or SIGTERM aufgerufen wird, wir fügen also einfach als erste Zeile rm -f $alldbnames_tmp in die Funktion ein.
Vorher:
mail_cleanup () {
removeIO
Nachher:
mail_cleanup () {
rm -f $alldbnames_tmp
removeIO
Jetzt geht’s :-)