backup.sh script hinzugefuegt
This commit is contained in:
230
backup.sh
Normal file
230
backup.sh
Normal file
@@ -0,0 +1,230 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
############################
|
||||
# Konfiguration
|
||||
############################
|
||||
|
||||
SFTP_SERVER="sftp.domain.tld"
|
||||
SFTP_PORT="22"
|
||||
SFTP_USER="sftp-user"
|
||||
SFTP_PASS="passw0rd"
|
||||
REMOTE_DIR="/uploads"
|
||||
|
||||
EMAIL=""
|
||||
|
||||
############################
|
||||
# Basis
|
||||
############################
|
||||
|
||||
HOSTNAME=$(hostname)
|
||||
DATE=$(date "+%Y-%m-%d_%H-%M")
|
||||
|
||||
BACKUP_DIR="/backups/docker"
|
||||
LOG_DIR="/var/log/script-logs"
|
||||
|
||||
mkdir -p "$BACKUP_DIR" "$LOG_DIR"
|
||||
|
||||
PROJECT_NAME=""
|
||||
ARCHIVE_FILE=""
|
||||
LOG_FILE=""
|
||||
|
||||
############################
|
||||
# Mail Funktion
|
||||
############################
|
||||
send_mail() {
|
||||
STATUS="$1"
|
||||
SUBJECT="[$HOSTNAME] Docker Backup $STATUS ($PROJECT_NAME)"
|
||||
|
||||
if command -v mail >/dev/null 2>&1; then
|
||||
mail -s "$SUBJECT" "$EMAIL" -A "$LOG_FILE" <<EOF
|
||||
Docker Backup Status: $STATUS
|
||||
|
||||
Host: $HOSTNAME
|
||||
Projekt: $PROJECT_NAME
|
||||
Datum: $DATE
|
||||
Archiv: $ARCHIVE_FILE
|
||||
|
||||
Logfile im Anhang.
|
||||
EOF
|
||||
else
|
||||
echo "Mail nicht installiert – übersprungen."
|
||||
fi
|
||||
}
|
||||
|
||||
############################
|
||||
# Fehlerbehandlung
|
||||
############################
|
||||
error_handler() {
|
||||
echo "FEHLER aufgetreten!"
|
||||
send_mail "FEHLER"
|
||||
exit 1
|
||||
}
|
||||
|
||||
trap error_handler ERR
|
||||
|
||||
############################
|
||||
# Compose Projekte
|
||||
############################
|
||||
|
||||
echo "Verfügbare Docker Compose Projekte:"
|
||||
|
||||
mapfile -t PROJECTS < <(
|
||||
docker ps --format '{{.Label "com.docker.compose.project"}}' \
|
||||
| sort -u \
|
||||
| grep -v '^$'
|
||||
)
|
||||
|
||||
if [[ ${#PROJECTS[@]} -eq 0 ]]; then
|
||||
echo "Keine Compose-Projekte gefunden."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for i in "${!PROJECTS[@]}"; do
|
||||
echo "[$((i+1))] ${PROJECTS[$i]}"
|
||||
done
|
||||
|
||||
echo
|
||||
read -p "Projekt auswählen (Nummer): " SELECTION
|
||||
|
||||
if ! [[ "$SELECTION" =~ ^[0-9]+$ ]] || (( SELECTION < 1 || SELECTION > ${#PROJECTS[@]} )); then
|
||||
echo "Ungültige Auswahl."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PROJECT_NAME="${PROJECTS[$((SELECTION-1))]}"
|
||||
LOG_FILE="$LOG_DIR/docker-backup-${PROJECT_NAME}.log"
|
||||
|
||||
exec > >(tee -a "$LOG_FILE") 2>&1
|
||||
|
||||
echo
|
||||
echo "===== Backup gestartet ====="
|
||||
echo "Projekt : $PROJECT_NAME"
|
||||
echo "Host : $HOSTNAME"
|
||||
echo "Datum : $DATE"
|
||||
echo
|
||||
|
||||
############################
|
||||
# Container sammeln
|
||||
############################
|
||||
|
||||
mapfile -t CONTAINERS < <(
|
||||
docker ps \
|
||||
--filter "label=com.docker.compose.project=$PROJECT_NAME" \
|
||||
--format '{{.Names}}'
|
||||
)
|
||||
|
||||
echo "Container im Stack:"
|
||||
printf ' - %s\n' "${CONTAINERS[@]}"
|
||||
echo
|
||||
|
||||
############################
|
||||
# Mounts sammeln
|
||||
############################
|
||||
|
||||
MOUNTS=()
|
||||
|
||||
for c in "${CONTAINERS[@]}"; do
|
||||
mapfile -t PATHS < <(
|
||||
docker inspect "$c" \
|
||||
| jq -r '.[0].Mounts[] | select(.Type=="volume" or .Type=="bind") | .Source'
|
||||
)
|
||||
|
||||
for p in "${PATHS[@]}"; do
|
||||
[[ -d "$p" ]] && MOUNTS+=("$p")
|
||||
done
|
||||
done
|
||||
|
||||
mapfile -t MOUNTS < <(printf "%s\n" "${MOUNTS[@]}" | sort -u)
|
||||
|
||||
if [[ ${#MOUNTS[@]} -eq 0 ]]; then
|
||||
echo "Keine gültigen Mounts gefunden."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
############################
|
||||
# Stack stoppen
|
||||
############################
|
||||
|
||||
echo "Stoppe Stack..."
|
||||
docker stop "${CONTAINERS[@]}" >/dev/null
|
||||
sleep 3
|
||||
|
||||
############################
|
||||
# Daten kopieren
|
||||
############################
|
||||
|
||||
TMP_DIR="/tmp/docker-backup-$PROJECT_NAME"
|
||||
rm -rf "$TMP_DIR"
|
||||
mkdir -p "$TMP_DIR"
|
||||
|
||||
echo "Kopiere Daten..."
|
||||
|
||||
for mount in "${MOUNTS[@]}"; do
|
||||
BASENAME=$(basename "$mount")
|
||||
rsync -a "$mount/" "$TMP_DIR/$BASENAME/"
|
||||
done
|
||||
|
||||
############################
|
||||
# ZIP Archiv erstellen
|
||||
############################
|
||||
|
||||
ARCHIVE_FILE="$BACKUP_DIR/${HOSTNAME}-${PROJECT_NAME}-${DATE}.zip"
|
||||
|
||||
echo "Erstelle ZIP Archiv..."
|
||||
|
||||
TOTAL_SIZE=$(du -sb "$TMP_DIR" | awk '{print $1}')
|
||||
|
||||
(
|
||||
cd "$TMP_DIR"
|
||||
zip -r -q - .
|
||||
) | pv -s "$TOTAL_SIZE" > "$ARCHIVE_FILE"
|
||||
|
||||
echo "Archiv erstellt: $ARCHIVE_FILE"
|
||||
|
||||
############################
|
||||
# Stack starten
|
||||
############################
|
||||
|
||||
echo "Starte Stack..."
|
||||
docker start "${CONTAINERS[@]}" >/dev/null
|
||||
echo "Stack läuft wieder."
|
||||
|
||||
############################
|
||||
# Optionaler Upload
|
||||
############################
|
||||
|
||||
echo
|
||||
read -p "Backup zum SFTP hochladen? (j/n): " DO_UPLOAD
|
||||
|
||||
if [[ "$DO_UPLOAD" == "j" ]]; then
|
||||
|
||||
if [[ -z "$SFTP_PASS" ]]; then
|
||||
read -s -p "SFTP Passwort eingeben: " SFTP_PASS
|
||||
echo
|
||||
fi
|
||||
|
||||
echo "Starte Upload..."
|
||||
|
||||
sshpass -p "$SFTP_PASS" \
|
||||
scp -P "$SFTP_PORT" "$ARCHIVE_FILE" \
|
||||
"$SFTP_USER@$SFTP_SERVER:$REMOTE_DIR/"
|
||||
|
||||
echo "Upload abgeschlossen."
|
||||
fi
|
||||
|
||||
############################
|
||||
# Cleanup
|
||||
############################
|
||||
|
||||
rm -rf "$TMP_DIR"
|
||||
|
||||
echo "Backup erfolgreich abgeschlossen."
|
||||
|
||||
send_mail "ERFOLGREICH"
|
||||
|
||||
echo "===== Fertig ====="
|
||||
exit 0
|
||||
|
||||
|
||||
Reference in New Issue
Block a user