From 6871d896669d444dbcc9c23f9a1c0bf341011b37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=94=91=E1=99=85=E1=95=BC=EA=99=86=E1=99=8E=E1=97=A3?= =?UTF-8?q?=E1=98=9CO=E1=97=A3?= Date: Sat, 28 Mar 2026 18:43:41 +0000 Subject: [PATCH] backup.sh script hinzugefuegt --- backup.sh | 230 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 backup.sh diff --git a/backup.sh b/backup.sh new file mode 100644 index 0000000..dcb48b1 --- /dev/null +++ b/backup.sh @@ -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" < ${#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 + +