Raspberry Pi: Live Backup der SD Karte anlegen

Raspberry Pi: Live Backup der SD Karte anlegen

letzte Aktualisierung: 28. November 2022
#
Ungefähre Lesezeit: 5 min

Ein Raspberry Pi kann vielfältige Aufgaben übernehmen. Einige Projekte kommen mit wenigen Handgriffen aus bis alles läuft und in manchen steckt viel Zeit, Energie und Gehirnschmalz. Wie bei allen anderen Daten auch, ist hier ein Backup das A&O. Die Automatisierung des eigenen Heimes soll natürlich auch im Fehlerfall genauso schnell wieder zum Laufen gebracht werden wie der geplante Videoabend mit Kodi.

Bei einigen Projekten reicht es die Config-Dateien regelmäßig zu sichern. Aber gerade wenn die Einrichtung und Installation der Programme einiges an Zeit kostet, lohnt es sich hier auch in regelmäßigen Abständen ein Vollbackup anzulegen. Um den Betrieb der kleinen Server nicht allzu lange zu stören, bietet sich ein Live-Backup an. Linux stellt dafür den bekannten Befehl dd zur Verfügung. Da hierbei eine 1:1 Kopie der SD Karte angelegt wird, wird bei 32GB, 64GB … schnell mal eine ganze Menge Speicherplatz fällig. Außerdem erhöht sich natürlich bei größeren Images auch die Wiederherstellungszeit. Um dies zu umgehen nutzen wir das Script “pishrink” von Drewsif, dass die Aufgabe der Verkleinerung übernimmt.

Das shrinken benötigt allerdings eine Menge Ressourcen, so dass das Script erst an einem Raspberry Pi 4 genutzt werden sollte. Selbst da benötigt es für 32GB noch rund 2h.

Voraussetzungen

  • Installation von Mutt – The Mutt Mail User Agent
  • Eingerichteter MTA, z.B. postfix
    (siehe Raspberry Pi: E-Mail-Versand einrichten)
  • Download von PiShrink
  • Konfiguration der fstab Datei zur Einbindung eines externen Datenträgers zur Speicherung des Images

Installation von Mutt

  • sudo apt-get update && sudo apt-get install mutt

Einrichtung von PiShrink

  • Script pishrink.sh unter /home/pi/ speichern
  • wget https://raw.githubusercontent.com/Drewsif/PiShrink/master/pishrink.sh
  • chmod +x pishrink.sh – Script ausführbar machen

Externe Festplatte vorbereiten

  • mit sudo blkid finden wird die Bezeichnung unserer Festplatte heraus, in meinem Fall sda2
  • mkdir backup – legt das Verzeichnis /home/pi/backup an, das wir später als Mountpunkt nutzen
  • Eintrag in der Datei fstab ergänzen, damit die externe Platte bei jedem Neustart, bzw. bei Ausführung unseres Backupscriptes gemountet wird
    sudo nano /etc/fstab
  • Zeile ergänzen
    /dev/sda2 home/pi/backup ntfs defaults,nofail,x-systemd.device-timeout=5 0 2
  • als nächsten Schritt würde ich einen reboot empfehlen, um die Einstellungen der fstab zu testen
    sudo reboot
  • alternativ kann man die externe Festplatte auch erstmal per Hand einbinden
    mount /dev/sda2 home/pi/backup
  • Ordner anlegen, da ich in meinem Fall einen Extra Ordner nutze um später das Image auf der externen Festplatte zu speichern (Dank an Arthur ;) )
    mkdir home/pi/backup/imagebackup

NAS als Speicherort nutzen

  • Alternativ kann man das Backup auch über das Netzwerk auf eine NAS speichern
  • die notwendigen Änderungen sind im Backupscript enthalten
  • wird die Auskommentierung für die NAS Speicherung aufgehoben, sollte man den Teil für die lokale Speicherung auskommentieren
  • die Speicherung erfolgt in meinem Fall über das CIFS Protokoll, was mit vielen NAS Systemen gut klarkommt

Backupscript

Das Backup übernimmt ein Script und regelt dabei die 1:1 Kopie, die Verkleinerung und Mailbenachrichtigung über den Verlauf des Backups. Ich habe dafür das Script von Stefan Strobel genommen und an meine Bedürfnisse angepasst.

#!/bin/bash
# by strobelstefan.org
# 2019-10-23
# Version: 2.0
# https://strobelstefan.org/?p=5985
#
# This script creates a full clone of your Raspberry Pi´s SD card.
#

###################################
# Define Variables
###################################

# Storage device as defined in your /etc/fstab.
### mount point lokal ###
mountpoint='/home/pi/backup/'
#########################

# Path were the image of your SD card should be saved to
### Speicherort lokal ###
STORAGEPATH="/home/pi/backup/imagebackup"
#########################

# E-Mail Address
EMAIL="info@mail.de"

# Image name
IMAGENAME="raspi-image"

#Log File location and name
LOGFILE="/var/log/"$HOSTNAME_${IMAGENAME}_"backup-image.log"

###################################
# This removes your old log file
###################################
# This removes your old log file.
# When you run the script the first time an error will be displayed,
# because no log file is in the defined path.
rm ${LOGFILE}

###################################
# MOUNTPOINT Section - Check Mount point Availability
###################################
# It checks if your mount point is accessible by your RPi.
# This is a crucial step, if the storage is not available the clone process of the SD card$
# Process
# 1. Check if mount point is accessible
# 2. If YES go to DELETION Section
# 3.1 If NO, try to mount storage device as defined in /etc/fstab
# 3.2 If mount is again not successful exit script, no further action will be conducted

if [ "$(findmnt ${mountpoint})" ] ;
    then
        echo $(date +%Y-%m-%d_%H-%M-%S) " - Mount point accessible by your "$HOSTNAME >> ${LOGFILE}
    else
        echo $(date +%Y-%m-%d_%H-%M-%S) " - Mount point was not accessible, try to mount it now as defined in your /etc/fstab" >> ${LOGFILE}

    #### Speicherort lokal ############################
    #This command mounts all storages defined in /etc/fstab
    mount -a
    ####################### END #########################

    ### Speicherort NAS über CIFS #####################
    # sudo mount -t cifs -o username=USERNAME,password="PASSWORD" //IP-NAS/00-backup/raspberry /home/pi/backup
    ####################### END #########################
    if [ $? != 0 ]
        then
            echo $(date +%Y-%m-%d_%H-%M-%S) " - Mount of storage in first try successfully completed" >> ${LOGFILE}
        sleep 5
            mount -a
        if [ $? != 0 ]
        then
            echo $(date +%Y-%m-%d_%H-%M-%S) " - Backup FAILED! Was not able to mount your storage device. Stop backup process. You have to check it manually." >> ${LOGFILE}
            echo "Sent backup status via e-mail" | mutt ${EMAIL} -a ${LOGFILE} -s $HOSTNAME" - Backup FAILED" >> ${LOGFILE}
        exit
        fi
    fi
fi

##################################################################
# DELETION Section - Remove old Images from Storage Device
##################################################################
# Use this command with CAUTION!
# This will help you to automatically remove old images from your storage device to avoid that your
# storage will run out of disk space

echo $(date +%Y-%m-%d_%H-%M-%S) " - Start to delete files older than defined time " >> ${LOGFILE}

# Uncomment if the files should be identified by days, file > 32 days than it gets deleted
find ${STORAGEPATH}/*.* -mtime +32 -exec rm -r {} \;

# Uncomment if you would like to use minutes file > 10080 minutes than it gets deleted
#find ${STORAGEPATH}/*.* -type f -mmin +43200 -exec rm {} \;

if [ $? != 0 ]
    then
        echo $(date +%Y-%m-%d_%H-%M-%S) " - Deletion of old image files successfully completed" >> ${LOGFILE}
     if [ $? != 0 ]
     then
        echo $(date +%Y-%m-%d_%H-%M-%S) " - Was not able to delete old image files. You have to check it manually." >> ${LOGFILE}
    break
    fi
fi
 
###################################
# Dienste beenden
###################################
## DB-Dienste etc. beenden, SmartHome in der Zeit nicht nutzbar

sudo systemctl stop openhab.service
echo $(date +%Y-%m-%d_%H-%M-%S) " - OpenHAB beendet" >> ${LOGFILE}
sudo /etc/init.d/z-way-server stop
echo $(date +%Y-%m-%d_%H-%M-%S) " - Z-way-Server beendet" >> ${LOGFILE}
sudo /etc/init.d/watchdog stop
echo $(date +%Y-%m-%d_%H-%M-%S) " - Watchdog beendet" >> ${LOGFILE}

###################################
# CLONE Section - Clone SD Card Image
###################################
# This line creates a full copy of the SD card and writes it as an image file to the defined patch
 
echo $(date +%Y-%m-%d_%H-%M-%S) " - Started to clone image" >> ${LOGFILE}
 
# Saves a plain img file on your storage device
sudo dd if=/dev/mmcblk0 of=${STORAGEPATH}/${IMAGENAME}_$(date +%Y-%m-%d).img bs=1MB
 
echo $(date +%Y-%m-%d_%H-%M-%S) " - Finished to clone image" >> ${LOGFILE}
 
###################################
# Dienste starten
###################################
# Startet beendete Dienste neu, SmartHome wieder möglich
sudo systemctl start openhab.service
echo $(date +%Y-%m-%d_%H-%M-%S) " - openHAB gestartet" >> ${LOGFILE}
sudo /etc/init.d/z-way-server start
echo $(date +%Y-%m-%d_%H-%M-%S) " - Z-way-Server gestartet" >> ${LOGFILE}

###################################
# Resize dd Image
###################################
# Resize image with pishrink
# Please see https://github.com/Drewsif/PiShrink for further details
# pishrink.sh must be located in the same directory as this script!
 
echo $(date +%Y-%m-%d_%H-%M-%S) " - Started to resize image" >> ${LOGFILE}
sudo /bin/bash /home/pi/pishrink.sh -d ${STORAGEPATH}/${IMAGENAME}_$(date +%Y-%m-%d).img ${STORAGEPATH}/${IMAGENAME}_$(date +%Y-%m-%d)-small.img
echo $(date +%Y-%m-%d_%H-%M-%S) " - Finished to resize big image" >> ${LOGFILE}

#Delete big image file
echo $(date +%Y-%m-%d_%H-%M-%S) " - Started to delete big image" >> ${LOGFILE}
sudo rm ${STORAGEPATH}/${IMAGENAME}_$(date +%Y-%m-%d).img
echo $(date +%Y-%m-%d_%H-%M-%S) " - Finished to delete big image" >> ${LOGFILE}
 
# Creates a compressed file of the resized image
# This command will create a compressed gz archive of the small image file.
# The small file will get deleted during the process if you would like to keep
# the small image file use the command gzip -k ${STORAGEPATH}/${IMAGENAME}_$(date +%Y-%m-%d)-small.img
# Before you change the compression process check your disk space size
 
echo $(date +%Y-%m-%d_%H-%M-%S) " - Started to compress small image" >> ${LOGFILE}
 
gzip -q ${STORAGEPATH}/${IMAGENAME}_$(date +%Y-%m-%d)-small.img
 
echo $(date +%Y-%m-%d_%H-%M-%S) " - Finished to compress small image" >> ${LOGFILE}

if [ $? != 0 ]
    then
        echo $(date +%Y-%m-%d_%H-%M-%S) " - Image file created" >> ${LOGFILE}
     if [ $? != 0 ]
    then
        echo $(date +%Y-%m-%d_%H-%M-%S) " - Was not able to create your image file. You have to check it manually." >> ${LOGFILE}
    break
    fi
fi

###################################
# UMOUNT Section - Unmount Storage Device
###################################
# This command unmounts the defined storage device.
# In the first try it will gently try to unmount, if the device is busy the command will force the unmount.
 
#if [ "$(umount ${mountpoint})" ] ; 
#    then
#        echo $(date +%Y-%m-%d_%H-%M-%S) " - Umounted #your storage device" >> ${LOGFILE}
#    else
#        echo $(date +%Y-%m-%d_%H-%M-%S) " - Umount of #storage device was not possible in first run, wait #for 30 seconds" >> ${LOGFILE}
#    sleep 30
#  
#    if [ $? != 0 ]
#        then
#            echo $(date +%Y-%m-%d_%H-%M-%S) " - #Umount was successful" >> ${LOGFILE}
#        sleep 5
#            umount ${mountpoint}
#        if [ $? != 0 ]
#        then
#            echo $(date +%Y-%m-%d_%H-%M-%S) " - #Umount successful" >> ${LOGFILE}
#        exit
#        fi
#    fi
#fi

# Skript finished
echo $(date +%Y-%m-%d_%H-%M-%S) " - Mission Accomplished!!! System is going for a reboot." >> ${LOGFILE}
 
# Send status via e-mail
echo "Sent backup status via e-mail" | mutt ${EMAIL} -a ${LOGFILE} pishrink.log -s $HOSTNAME" - Backup SUCCESSFULL" >> ${LOGFILE}
 
# start watchdog
sudo /etc/init.d/watchdog start
echo $(date +%Y-%m-%d_%H-%M-%S) " - Watchdog gestartet" >> ${LOGFILE}
# If you like to reboot your system, please uncomment
#sudo reboot
  • Script ausführbar machen
    sudo chmod +x backup-pi.sh
  • Script händisch ausführen
    sudo ./backup-pi.sh
  • für eine automatische Sicherung nutzen wir einen Crontab
    sudo crontab -e
  • Script eintragen und Startzeit festlegen. (z.B. jeden Ersten Tag im Monat um 02:00 Uhr)
    0 2 1 * * /bin/bash /home/pi/backup-pi.sh
    ┬ ┬ ┬ ┬ ┬
    │ │ │ │ │
    │ │ │ │ └───── Wochentag (0-7, Sonntag ist 0 oder 7)
    │ │ │ └────── Monat (1-12)
    │ │ └──────── Tag (1-31)
    │ └────────── Stunde (0-23)
    └──────────── Minute (0-59)
Wird das Script über ssh ausgeführt, und die Sitzung absichtlich oder unabsichtlich geschlossen, dann wird auch das Script beendet.
Um diesem Umstand vorzubeugen, empfiehlt es sich den Fenstermanager screen zu nutzen, mit dem sich mehrere virtuelle Sitzungen in der Konsole erzeugen lassen (ähnlich Tabs beim Browser).
Wird dieses Fenster geschlossen, kann man diese später mit einem Befehl wieder aufrufen, wobei die laufenden Aufgaben weiterhin abgearbeitet werden.

screen – startet Fenstermanager (man denkt es passiert nichts, aber der Fenstermanager wird im Hintergrund gestartet)
screen -r – nimmt die letzte Sitzung nach einer Trennung wieder auf, solange nur eine Sitzung erstellt wurde

Quellen

Tags:
Artikelaufrufe: 2976
Nach oben