In diesem Teil zeige ich euch meine aktuell im Test befindliche 2. Version des ehemaligen Shellscripts, mit dem ich meinen Webspace auf all-inkl.com auf meinen lokalen Server sichere. Ich habe dieses neu in Python implementiert.
Erforderliche Ordnerstruktur
Als lokalen Server habe ich einen Raspberry Pi erfolgreich getestet, da dieser sehr stromsparend betrieben werden kann.
Wichtig: Man sollte sich vorher ansehen, wie groß die auf dem Webspace das Hosting-Anbieters (bei mir all-inkl.com) im Filesystem gespeicherten Dateien sind. Es darf nicht dazu kommen, dass der Speicherplatz auf der SD-Karte im Raspberry Pi zu klein wird. Den freien Speicherplatz auf dem Raspberry Pi zeigt man sich wie folgt an.
# per ssh auf der raspberry pi angemeldet # anzeige des freien Speichers in megabyte df -hm
Damit das Script problemlos arbeitet, habe ich folgende Verzeichnisstruktur unter dem Home-Verzeichnis des Users pi eingerichtet. Wenn man diese anderes möchte, muss man das Script ein bisschen verändern.
#verzeichnis für website-backups /home/pi/test/allinkl_backup/website #verzeichnis für mysql-backups /home/pi/allinkl_backup/website/mysql
Script
Das Script verwendet wiederum für den eigentlichen FTP-Dateitransfer die Spezialform für Scripte ncftpget. Mit diesem habe ich sehr gute Erfahrungen beim rekursiven Download bei FTP gemacht.
Diesen installiert man einfach über apt-get:
#installation des ncftp-client sudo apt-get install ncftp
Meine Dateien der Web-Content-Mangement-Systeme (WordPress, Drupal, phpbb), liegen unter
/websites
Die mit dem mysqldumper erstellten tar.gz-Datenbankbackups liegen unter:
/MySqlDumper/work/backup/
Die einzelnen Stellen des Scripts sind kommentiert. So sieht man was es tut.
Vorteile des Scripts
- Es können über 1 Script die verschiedenen Sicherungsarten abgefangen werden. Dies erleichtert die Wartbarkeit.
- Das Script kann leicht um weitere Sicherungsarten erweitert werden um andere Verzeichnisse zu sichern.
- Es können mehrere Sicherungsarten gleichzeitig ablaufen, da jede in ihrem eigenen Verzeichnis abläuft (keine critical section mehr).
- Es werden mehrere Generationen von Sicherungen vorgehalten. Sobald ein individuell einstellbare Grenze (TIME_OFFSET_IN_SECONDS) überschritten wird, werden veraltete Sicherungen nach jedem Lauf automatisch bereinigt.
- Da es in Python implementiert wurde, ist mehr Programmlogik möglich (ich verfüge leider noch nicht über die dazu notwendigen Shell-Scripting-Kenntnisse).
#!/usr/bin/env python # -*- coding: utf-8 import os import sys import time import subprocess import shutil #1. Variablen #ftp-zugang host="domain_ftp_server" user="ftp_user" password="passwort_ftp_user" #zu sichernde Dateien - sicherungsarten try: art=sys.argv[1] #übergabe der Sicherungsart als Argument in Kommandozeile except IndexError: print "Geben Sie die Sicherungsart an (mysql, website)" sys.exit(1) sicherungsarten=("mysql", "website") if art not in sicherungsarten: print "falsche sicherungsart --> programm beendet" exit() #lokales Ziel ziel = "/home/pi/test/allinkl_backup" ziel = os.path.join(ziel, art) #Sicherungspfade festlegen sicherungspfade=[] if art == "mysql": #sicherung datenbankdumps sicherungspfade.append("/MySqlDumper/work/backup/") elif art == "website": #sicherung webseiten sicherungspfade.append("/websites") print("Sicherungspfade: ",sicherungspfade) #maximales Alter Sicherung TIME_OFFSET_IN_SECONDS = 60*60*24*7*4 # <= 60s * 60m * 24h * 7d * 4w #Zeitangaben datum = time.strftime("%Y%m%d") uhrzeit = time.strftime("%H%M%S") #Zielpfad festlegen zielverzeichnis="backup_"+datum+"_"+uhrzeit zielpfad=ziel+os.sep+zielverzeichnis #2. Sicherung durchführen def sichern(): #sicherung durchführen for sicherungspfad in sicherungspfade: #sicherungsbefehl command = "ncftpget -R -u %s -p %s %s %s %s" % (user, password, host, zielpfad, sicherungspfad) print command try: ncftp=subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT) print "ncftp erfolgreich gestartet" #for line in iter(ncftp.stdout.readline, ''): print line except subprocess.CalledProcessError as e: ret = e.returncode if ret in (1, 2): print("the command failed") elif ret in (3, 4, 5): print("the command failed very much") print "Returncode:",ret return ret #3. tar.gz erstellen def tarErstellen(): os.chdir(ziel) print "Wechsel in", os.getcwd() command ="tar -czvf %s.tar.gz %s/" % (zielverzeichnis, zielverzeichnis) print command tar=subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) for line in iter(tar.stdout.readline, ''): print line os.chdir(ziel) command ="rm -r %s" % (zielverzeichnis) print command rm=subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) #4. Bereinigen von alten Sicherungen (TIME_OFFSET_IN_SECONDS) def remove_files(path): time.sleep(60) for root, _, files in os.walk(path): anzahlSicherungen=len(files) for filename in files: full_path = os.path.join(root, filename) print full_path,"-- Alter: ",(time.time()-os.path.getmtime(full_path))/(60*60*24)," Tage" if time.time() - os.path.getmtime(full_path) > TIME_OFFSET_IN_SECONDS: try: print "Sicherung veraltet: full_path=",full_path if anzahlSicherungen>1: #mindestens eine Sicherungsdatei vorhalten os.remove(full_path) anzahlSicherungen-=1 else: print "keine Bereinigung durchgeführt, da mind. 1 Sicherungsdatei erforderlich" except Exception as e: print('Datei "{}" konnte nicht gelöscht werden. Fehlermeldung: {}'.format( full_path, e)) def main(): sichern() tarErstellen() print ziel remove_files(ziel) if __name__ == '__main__': main()
Das Script binde ich als cronjobs des Users pi ein und lasse es so automatisiert und regelmäßig über Nacht laufen. Dem Script wird immer die jew. Sicherungsart übergeben:
#als user pi crontab anlegen crontab -e #folgende Zeile einfügen, wobei es abhängt, wo das shell-script gespeichert ist #damit wird jede Woche am sonntag um 1 uhr eine Sicherung gestartet 0 1 * * 7 /home/pi/scripts/main.py mysql #damit wird jeden Monat um 4 Uhr ein Sicherungslauf gestartet 0 4 1 * * /home/pi/scripts/main.py website #die datei wird gespeichert
Über dieses Script habe ich es geschafft, meinen kompletten sicherungsrelevanten Bereich bei meinem Webhostinganbieter lokal doppelt vorzuhalten. Es wird beständig verbessert und alle Änderungen in diesem Betrag eingefügt.