Komplette Ordner mit tar packen und speichern
Das folgende Perlscript ermöglicht es, einen kompletten Ordner mit tar zu packen und auf dem lokalen Dateisystem zu sichern.
Was und wohin gesichert werden soll, kann in einer SQL Tabelle definiert werden. Dabei kann der Rhytmus (Stündlich, Täglich, Wöchentlich und Monatlich), die Art der Sicherung (SQL Script oder Binär) und der Zielordner festgelegt werden.
Vorwort
Dieses Script ist genau so aufgebaut wie der »MySQL Backup 2.0«. Wenn beide Scripte verwendet werden sollen, sollten sich die Log Tabelle und die Definitionstabellen für die Backups in der selben Datenbank befinden.
Werden die drei Tabellen in der selben Datenbank angelegt, kann das anlegen des MySQL Benutzers und das setzen der Rechte für den User beim zweiten Script übersprungen werden. Zudem muss nur eine Konfigurationsdatei und eine Log Tabelle angelegt werden.
So sind alle Daten zentral gespeichert.
Konfiguration
Die Konfiguration ist in ein separates Perlscript ausgelagert, um diese auch in anderen Scripten verwenden zu können.
Bei dieser Datei unbedingt auf die Leserechte achten! Sonst kommen die MySQL Zugangsdaten in falsche Hände!
| 1 2 3 4 5 6 | #!/usr/bin/perl $MYSQL_HOST = "localhost"; $MYSQL_DATA = "database"; $MYSQL_USER = "backup"; $MYSQL_PASS = "sql passwort"; |
Datenbank Tabelle
| folder | frequency | name | target | owner | rights | active |
|---|---|---|---|---|---|---|
| /var/www/website/ | DAILY | website | /var/backup/databases/ | user:group | u=rwx,g=rx,o=- | Y |
- Ordner im Dateisystem
- Rhytmus [HOURLY, DAILY, WEEKLY, MONTHLY]
- Name des Backups
- Zielordner
- Besitzer
- Benutzerrechte
- Aktiv/Inaktiv
| 1 2 3 4 5 6 7 8 9 10 | CREATE TABLE IF NOT EXISTS `backup_folders` ( `folder` varchar(255) NOT NULL, `frequency` enum('HOURLY','DAILY','WEEKLY','MONTHLY') NOT NULL, `name` varchar(255) NOT NULL, `target` varchar(255) NOT NULL, `owner` varchar(255) NOT NULL, `rights` varchar(255) NOT NULL, `active` enum('Y','N') NOT NULL, PRIMARY KEY (`folder`,`frequency`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; |
Log Tabelle
Was letztendlich beim Backup Vorgang passiert, wird in eine Log Tabelle geschrieben.
Was nun mit den Daten getrieben wird, ist dem Anwender überlassen. Man könnte sich zum Beispiel ein PHP Script basteln, welches die Ausgaben schön Formatiert ausgibt.
Die Spalte "type" dient dazu mehrere Backup Prozesse von einander zu trennen. So könnte man Beispielsweise File Backup und Datenbank Backup in einer Log Tabelle aufzeichnen, und diese dennoch auseinanderhalten.
| 1 2 3 4 5 6 7 | CREATE TABLE IF NOT EXISTS `backup_log` ( `id` int(10) unsigned NOT NULL auto_increment, `date` datetime NOT NULL, `type` enum('FOLDER','DATABASE') NOT NULL, `message` text NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 |
MySQL Benutzer
Nun brauchen wir noch einen Backup Benutzer, der wirklich nur die Rechte hat, die er brauch. Beim erstellen des Benutzers, müssen die drei Sterne durch ein richtiges Passwort (Keygen) ersetzt werden.
Dem Benutzer werden Rechte zum lesen in allen Datenbanken, und zum sperren der Tabellen in einer Datenbank erteilt. Das RELOAD Recht wird benötigt, um den Cache von Datenbanken und Tabellen wegzuschreiben. Das ist wichtig, damit auch beim Backup alles enthalten ist.
Zu guter letzt wird dem Benutzer noch das Recht zum schreiben in die Tabelle "backup_log" erteilt. Dort werden die Statusausgaben die bei dem Backup Prozess entstehen hinein geschrieben. Der Benutzer kann dort nur einfügen und lesen.
| 1 2 3 4 5 6 7 8 9 10 | -- Benutzer mit dem Passwort "***" erstellen CREATE USER 'backup'@'localhost' IDENTIFIED BY '***'; -- Dem Benutzer die noetigen Leserechte geben GRANT SELECT , RELOAD , LOCK TABLES ON * . * TO 'backup'@'localhost' IDENTIFIED BY '***' WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0 ; -- Dem Benutzer erlauben, in die Log-Tabelle zu schreiben GRANT SELECT , INSERT ON `database`.`backup_log` TO 'backup'@'localhost'; |
Das Script
Das Script sollte so gespeichert werden, dass nur der Benutzer es aufrufen/lesen darf, der auch das Backup durchführt. Wird das Script via Cron aufgerufen, bietet sich der Benutzer root an. So hat man auch keine Probleme beim setzen des Besitzers und der Rechte auf das fertige Backup.
Im Script selber muss die Zeile 3 angepasst werden. Dort wird die Konfigurationsdatei eingelesen, wo die MySQL Zugangsdaten drin stehen.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | #!/usr/bin/perl require '/pfad/zu/config.inc.pl'; use DBI; ################################################################################################## sub filename { my ($string) = @_; $string =~ s/[^[:alnum:]_.]/_/g; return $string; } ################################################################################################## if($ARGV[0] eq "HOURLY" || $ARGV[0] eq "DAILY" || $ARGV[0] eq "WEEKLY" || $ARGV[0] eq "MONTHLY") { $frequency = $ARGV[0]; } else { print "Usage:\n"; print " ".$0." HOURLY\n"; print " ".$0." DAILY\n"; print " ".$0." WEEKLY\n"; print " ".$0." MONTHLY\n\n"; exit; } # Datum ermitteln my ($sec,$min,$hour,$mday,$mon,$year) = localtime(time); my $time = sprintf("%0.2d-%0.2d-%0.2d",$hour,$min,$sec); my $date = sprintf("%0.2d-%0.2d-%0.2d",$year+1900,++$mon,$mday); # Log Cache my $CONTENT = ""; # Hostname my $HOSTNAME = `hostname`; $HOSTNAME =~ s/\n//g; # Herstellen der MySQL Verbindung my $DB = DBI->connect('dbi:mysql:'.$MYSQL_DATA.':localhost:3306', $MYSQL_USER , $MYSQL_PASS) || exit 1; $CONTENT = $CONTENT."#=> Verbindung hergestellt\n"; # Auslesen der Datenbanken $RESULT = $DB->prepare("SELECT `folder`, `name`, `target`, `owner`, `rights` FROM backup_folders WHERE frequency='".$frequency."' AND active='Y'") || die "Error: ".$DBI::errstr; $RESULT->execute() || die "Error: ".$DBI::errstr; $CONTENT = $CONTENT."#=> Jobs ausgelesen\n"; # Backups vorhanden? if($RESULT->rows > 0) { # Backups erstellen $CONTENT = $CONTENT."#=> Starte Backup fuer \"".$HOSTNAME."\" (".$frequency.")\n\n"; while(my ($folder, $name, $target, $owner, $rights) = $RESULT->fetchrow_array) { $name = filename($name); # Falls nicht vorhanden Ordner fuer Datenbank anlegen $CONTENT = $CONTENT." => \"".$folder."\" (".$name.")"; if(-d $target) { if(! -d $target."/".$name."/") { system("mkdir ".$target."/".$name); system("chown -R ".$owner." ".$target."/".$name); system("chmod -R ".$rights." ".$target."/".$name); } if (-e $target."/".$name) { $dump_file = $target."/".$name."/".$date . "_" . $time . "_". $name . ".tar.gz"; if(system("tar cfz ".$dump_file." ".$folder." 2> /dev/null")==0) { $CONTENT = $CONTENT." erfolgreich\n"; } else { $CONTENT = $CONTENT." fehlgeschlagen!\n"; } # Backup durchfuehren system("chown -R ".$owner." ".$dump_file); system("chmod -R ".$rights." ".$dump_file); } else { $CONTENT = $CONTENT." FEHLER: ".$target.$name." ist nicht beschreibar!\n"; } } else { $CONTENT = $CONTENT." FEHLER: ".$target." existiert nicht!\n"; } } $CONTENT = $CONTENT."\n#=> Backup beendet\n"; } else { exit 0; } # Verbindung trennen $RESULT->finish() || die "Error: ".$DBI::errstr; $DB->disconnect() || die "Error: ".$DBI::errstr; $CONTENT = $CONTENT."#=> Datenbank Verbindung getrennt"; # Logverlauf in Datenbank schreiben my $LOG = DBI->connect('dbi:mysql:'.$MYSQL_DATA.':localhost:3306', $MYSQL_USER , $MYSQL_PASS) || print $CONTENT; $RESULT = $LOG->prepare("INSERT INTO backup_log SET date=NOW(), type='FOLDER', message='".$CONTENT."'") || print $CONTENT; $RESULT->execute() || print $CONTENT; $RESULT->finish() || die "Error: ".$DBI::errstr; $LOG->disconnect() || die "Error: ".$DBI::errstr; |
Cron
Das Script muss nun noch mit den verschiedenen Rhythmen als Cronjob aufgerufen werden.
Mit was für einem Benutzer das Script dann aufgerufen wird, ist Dir überlassen. Man muss nur bedenken, dass bei einem nicht-root Benutzer nur eingeschränkt Möglichkeit besteht den Besitzer und die Rechte des Backups zu ändern.
| 1 2 3 4 5 6 | # Datenbank Backup # m h dom mon dow user command 23 * * * * root /usr/bin/perl /pfad/zu/backup_folders.pl HOURLY 30 4 * * * root /usr/bin/perl /pfad/zu/backup_folders.pl DAILY 12 4 * * 6 root /usr/bin/perl /pfad/zu/backup_folders.pl WEEKLY 43 4 1 * * root /usr/bin/perl /pfad/zu/backup_folders.pl MONTHLY |
Nach den Änderungen an /etc/crontab muss ggf der Cron Service neu gestartet werden.
Have fun!




