Docker: Unterschied zwischen den Versionen

Aus XccesS Wiki
Zur Navigation springen Zur Suche springen
Die Seite wurde neu angelegt: „= Wiederherstellung der kompletten Docker-Umgebung nach Neuinstallation = Diese Seite beschreibt Schritt für Schritt, wie Du **nach einem Komplett-Reinstall des Servers** (Ubuntu 22.04 LTS, leerer Zustand) Deine zuvor mit dem Skript <code>backup_docker_rsync.sh</code> gesicherten Docker-Container, -Volumes und -Konfigurationsdateien wiederherstellst. Die Backups liegen auf einer QNAP-Freigabe unter <code>\\192.168.1.15\Backup\Docker\*</code> (Snap­sh…“
 
KKeine Bearbeitungszusammenfassung
 
Zeile 111: Zeile 111:


----
----
''Stand: 06 Juni 2025 – getestet mit Ubuntu 22.04 LTS & Docker 28.1''
= Docker-Backups im Homelab = 
Diese Seite beschreibt die komplette Einrichtung und Funktionsweise des Scripts
<code>backup_docker_rsync.sh</code>, mit dem alle Docker-Volumes, Compose-Dateien
und die Docker-Daemon-Konfiguration täglich auf das QNAP-NAS gesichert werden.
 
; Repository 
<code>/usr/local/sbin/backup_docker_rsync.sh</code> (lokal) 
; Zielpfad NAS 
<code>/mnt/Backup/Docker/YYYY-MM-DD-HHMM</code> ⇒ Symlink '''latest'''
 
== 1 Voraussetzungen ==
* **Ubuntu 22.04 LTS** (Root-Zugriff) 
* NAS-Share unter <code>/mnt/Backup</code> gemountet 
**Empfohlen**: NFS (+ <code>no_root_squash</code>). 
SMB/CIFS funktioniert mit den rsync-Optionen <code>--no-owner --no-group</code>.
* Pakete: 
<syntaxhighlight lang="bash">
apt install rsync jq
</syntaxhighlight>
 
== 2 Backupscript ==
<syntaxhighlight lang="bash">
#!/usr/bin/env bash
# ==========================================================================
#  backup_docker_rsync.sh  –  Docker-Volumes & Compose sichern (rsync)
#  › paust nur "running" Container  › unpaust garantiert wieder
# ==========================================================================
 
set -euo pipefail
shopt -s nullglob
 
# ─── Konfiguration ────────────────────────────────────────────────────────
SNAPROOT="/mnt/Backup/Docker"
RETENTION_DAYS=7
COMPOSE_BASE="/data/compose"
INITIALLY_PAUSED=$(docker ps -q --filter status=paused)
 
# rsync-Grundoptionen (SMB/NFS ohne chown-Erlaubnis → kein owner/group)
RSYNC_BASE="-a --no-owner --no-group --numeric-ids --delete --link-dest"
# -------------------------------------------------------------------------
 
timestamp() { date +'%F-%H%M'; }
log()      { printf '\e[36m[%s] %s\e[0m\n' "$(date +'%F %T')" "$*"; }
 
SNAPDIR="$SNAPROOT/$(timestamp)"
LINKDEST="$SNAPROOT/latest"
 
# ─── Cleanup-Funktion (immer ausführen) ───────────────────────────────────
TMP=""
PAUSED=""
cleanup() {
  [[ -n "$PAUSED" ]] && docker unpause $PAUSED 2>/dev/null || true
  [[ -n "$TMP"    ]] && rm -rf "$TMP"
}
trap cleanup EXIT
 
# ─── 1) Metadaten-Dump ────────────────────────────────────────────────────
TMP=$(mktemp -d /tmp/docker_dump.XXXX)
log "Erzeuge Metadaten-Dump in $TMP"
 
docker info            > "$TMP/docker-info.txt"
docker images --digests > "$TMP/images.txt"
docker ps -a            > "$TMP/containers.txt"
docker inspect $(docker ps -aq) > "$TMP/containers.json" 2>/dev/null || true
 
mkdir -p "$TMP/compose"
if [[ -d "$COMPOSE_BASE" ]]; then
  find "$COMPOSE_BASE" -type f -iname 'docker-compose*.yml' \
      -exec cp --parents {} "$TMP/compose" \;
fi
# plus dynamisch laufende Stacks
while read -r DIR; do
  [[ -d $DIR ]] || continue
  find "$DIR" -type f -iname 'docker-compose*.yml' \
      -exec cp --parents {} "$TMP/compose" \;
done < <(docker ps --format '{{.Label "com.docker.compose.project.working_dir"}}' | sort -u)
 
# ─── 2) Nur RUNNING-Container pausieren ──────────────────────────────────
RUNNING=$(docker ps --filter status=running -q)
if [[ -n "$RUNNING" ]]; then
  log "Pausiere $(echo "$RUNNING" | wc -w) laufende Container"
  # shellcheck disable=SC2086
  docker pause $RUNNING || true      # Fehler ignorieren
  PAUSED="$RUNNING"
fi
# ─── 3) rsync-Snapshot ────────────────────────────────────────────────────
log "Starte rsync in $SNAPDIR"
mkdir -p "$SNAPDIR"
 
# Link-Dest nur setzen, wenn latest existiert
[[ -e "$LINKDEST" ]] && LD=(--link-dest="$LINKDEST") || LD=()
 
rsync -a --no-owner --no-group --numeric-ids --delete "${LD[@]}" \
      /var/lib/docker/volumes/          "$SNAPDIR/volumes"
 
rsync -a --no-owner --no-group --numeric-ids --delete "${LD[@]}" \
      /etc/docker/                      "$SNAPDIR/etc-docker"
 
# systemd-Drop-Ins nur sichern, falls Verzeichnis existiert
if [[ -d /etc/systemd/system/docker.service.d ]]; then
  rsync -a --no-owner --no-group --numeric-ids --delete "${LD[@]}" \
        /etc/systemd/system/docker.service.d/ "$SNAPDIR/docker-systemd"
fi
 
rsync -a --no-owner --no-group "$TMP/" "$SNAPDIR/metadata"
 
# ─── 4) „latest“-Symlink & Retention ─────────────────────────────────────
ln -snf "$SNAPDIR" "$SNAPROOT/latest"
 
log "Lösche Snapshots älter als $RETENTION_DAYS Tage"
find "$SNAPROOT" -maxdepth 1 -type d -name '20*' -mtime +"$RETENTION_DAYS" \
    -exec rm -rf {} +
# … rsync und Retention bereits gelaufen …
 
# 6) latest-Symlink aktualisieren
ln -snf "$SNAPDIR" "$SNAPROOT/latest"
 
# 7) Leserechte für SMB-User
log "Setze lesbare Rechte für SMB-Nutzer"
find "$SNAPDIR" -type d -exec chmod 755 {} +
find "$SNAPDIR" -type f -exec chmod 644 {} +
# unpause alles, was jetzt pausiert ist
docker unpause $(docker ps -q --filter status=paused) || true
# und PAUSE-Status von vorher wiederherstellen
for c in $INITIALLY_PAUSED; do
    docker pause "$c" || true
done
 
log "Backup abgeschlossen"
 
 
</syntaxhighlight>
 
=== 2.1 Wichtige Variablen im Kopfbereich ===
{| class="wikitable"
! Variable !! Standardwert !! Bedeutung
|-
| <code>SNAPROOT</code>    || <code>/mnt/Backup/Docker</code> || Ablageort der Snapshots
|-
| <code>RETENTION_DAYS</code> || <code>7</code> || Aufbewahrung (ältere Snapshots werden gelöscht)
|-
| <code>COMPOSE_BASE</code>  || <code>/data/compose</code> || Oberordner der Compose-Stacks
|}
 
== 3 Cron Job (täglich 02:30 Uhr) ==
<syntaxhighlight lang="cron">
# crontab -e  (als root)
30 2 * * * /usr/local/sbin/backup_docker_rsync.sh \
          >> /var/log/backup_docker.log 2>&1
</syntaxhighlight>
 
* '''Logging''': Alle Ausgaben in <code>/var/log/backup_docker.log</code>. 
* Bei Fehlercodes ≠0 wird der Cron-MTA eine Mail an root schicken (sofern konfiguriert).
 
== 4 Funktionsweise ==
# **Metadaten-Dump** (Docker info, Container-/Image-Listen, Compose-YAMLs). 
# **Nur noch laufende Container** werden kurz mit <code>docker pause</code> eingefroren. 
# **rsync Snapshot** 
  * Hard-Links via <code>--link-dest</code> → jede Sicherung „Vollkopie“, aber nur Deltas belegen Platz. 
  * Ohne <code>-o -g</code> ⇒ kompatibel mit SMB/NFS-Shares. 
# **Unpause** der zuvor laufenden Container (Cleanup-Trap gewährleistet dies selbst bei Abbruch). 
# **latest-Symlink** wird aktualisiert, alte Snapshots nach <code>RETENTION_DAYS</code> gelöscht. 
# **Rechte 755/644** auf neuem Snapshot → Windows-Benutzer können per SMB browsen.
 
== 5 Snapshot-Struktur ==
<pre>
/mnt/Backup/Docker/
└── 2025-06-06-0230/
    ├── volumes/                # kompletter Inhalt von /var/lib/docker/volumes
    ├── etc-docker/            # /etc/docker
    ├── docker-systemd/        # systemd-Drop-Ins (falls vorhanden)
    └── metadata/
        ├── docker-info.txt
        ├── images.txt
        ├── containers.txt
        └── compose/…          # alle docker-compose*.yml
latest -> 2025-06-06-0230
</pre>
 
== 6 Manueller Testlauf ==
<syntaxhighlight lang="bash">
/usr/local/sbin/backup_docker_rsync.sh
echo $?
# → 0  = Erfolg
</syntaxhighlight>
 
== 7 Wiederherstellung ==
*Siehe [[Docker]]* 
Kurzfassung für „latest“:
<syntaxhighlight lang="bash">
restore_docker_rsync.sh  -s latest
</syntaxhighlight>
 
== 8 Troubleshooting ==
{| class="wikitable"
! Meldung !! Ursache / Lösung
|-
| <code>--link-dest arg does not exist</code> || Erster Lauf → ignorieren.
|-
| <code>Operation not permitted (chown)</code> || SMB-Share ohne Chown-Rechte → OK; Daten wurden trotzdem kopiert.
|-
| Container bleiben <code>paused</code> || Script vor v1.1; aktualisieren ODER manuell 
  <code>docker unpause $(docker ps -q --filter status=paused)</code>
|-
| Windows kann nicht lesen || Fs-Rechte → Script ≥v1.2 setzt 755/644 
  oder Share mit <code>noperm</code> mounten.
|}
 
== 9 Versionshistorie ==
{| class="wikitable"
! Datum !! Version !! Änderung
|-
| 2025-06-06 || 1.2 || Rechtefix (755/644), robustes Unpause, Link-Dest-Check
|-
| 2025-06-05 || 1.1 || Pausiere nur laufende Container, Cleanup-Trap
|-
| 2025-06-04 || 1.0 || Erste produktive Version
|}
 
----
''Seite zuletzt aktualisiert: 06 Juni 2025''

Aktuelle Version vom 6. Juni 2025, 17:22 Uhr

Wiederherstellung der kompletten Docker-Umgebung nach Neuinstallation

Diese Seite beschreibt Schritt für Schritt, wie Du **nach einem Komplett-Reinstall des Servers** (Ubuntu 22.04 LTS, leerer Zustand) Deine zuvor mit dem Skript backup_docker_rsync.sh gesicherten Docker-Container, -Volumes und -Konfigurationsdateien wiederherstellst. Die Backups liegen auf einer QNAP-Freigabe unter \\192.168.1.15\Backup\Docker\* (Snap­shots) und werden lokal nach /mnt/Backup/Docker/ gemountet.

Voraussetzungen
  • Frisches Linux – Root-SSH-Zugang
  • NAS online, Netzwerk erreichbar
  • Zeitstempel des Snapshots (oder latest)
  • Sicherungs-Script restore_docker_rsync.sh (siehe Scripts/Docker_Restore)

1 Linux-Grundsystem vorbereiten

# apt update && apt upgrade -y
# apt install vim curl rsync gnupg2 ca-certificates lsb-release \
               software-properties-common

2 Docker Engine installieren

## 2.1 Docker-Repo hinterlegen
# install -m 0755 -d /etc/apt/keyrings
# curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
      | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
   https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" \
  | tee /etc/apt/sources.list.d/docker.list

## 2.2 Engine + Compose laden
# apt update
# apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin \
               docker-compose-plugin -y

## 2.3 Daemon starten + beim Boot aktivieren
# systemctl enable --now docker
# docker --version   # prüfen

3 NAS-Share einbinden

Protokoll Beispiel-Mount Fstab-Eintrag
SMB/CIFS
# apt install cifs-utils
# mkdir -p /mnt/Backup
# mount -t cifs //192.168.1.15/Backup /mnt/Backup \
      -o username=<NASUSER>,password=<PASS>,uid=0,gid=0,vers=3.0,noperm
//192.168.1.15/Backup /mnt/Backup cifs vers=3.0,uid=0,gid=0,noperm,_netdev,credentials=/root/.smb 0 0
NFS (empfohlen, behält UID/GID)
# apt install nfs-common
# mount -t nfs4 192.168.1.15:/Backup /mnt/Backup
192.168.1.15:/Backup /mnt/Backup nfs4 defaults,_netdev 0 0

Überprüfen:

# ls /mnt/Backup/Docker | head

4 Restore-Skript ablegen

# curl -o /usr/local/sbin/restore_docker_rsync.sh \
       https://<dein-git-oder-wiki>/restore_docker_rsync.sh
# chmod +x /usr/local/sbin/restore_docker_rsync.sh

5 Snapshot wählen

Alle verfügbaren Snapshots:

# ls /mnt/Backup/Docker
2025-06-01-0230  2025-06-02-0230  ...  latest

6 Wiederherstellung ausführen

Trockenlauf
# restore_docker_rsync.sh -s 2025-06-06-1557 --dry-run

Wenn die Ausgabe plausibel ist → Live-Restore:

# restore_docker_rsync.sh -s 2025-06-06-1557
  • Docker-Dienst stoppt automatisch
  • Volumes, Config & Compose-YAMLs werden zurückkopiert
  • Docker startet neu, alle Stacks laufen wieder

7 Validierung

# docker ps
# docker compose -f /data/compose/XX/docker-compose.yml ps

Stichproben-Check von Web-UIs / APIs der Dienste.

8 Backup-Automatisierung nachziehen

backup_docker_rsync.sh und Cron-Eintrag wiederherstellen → siehe Doku/Backup_Docker

Troubleshooting

  • „permission denied“ → Share nicht mit uid=0,gid=0 gemountet
  • Container bleiben paused → manuell docker unpause $(docker ps -q --filter status=paused)
  • Netzwerk-Ports kollidieren → prüfen, dass keine anderen Services auf dem frischen OS laufen

Docker-Backups im Homelab

Diese Seite beschreibt die komplette Einrichtung und Funktionsweise des Scripts backup_docker_rsync.sh, mit dem alle Docker-Volumes, Compose-Dateien und die Docker-Daemon-Konfiguration täglich auf das QNAP-NAS gesichert werden.

Repository

/usr/local/sbin/backup_docker_rsync.sh (lokal)

Zielpfad NAS

/mnt/Backup/Docker/YYYY-MM-DD-HHMM ⇒ Symlink latest

1 Voraussetzungen

  • **Ubuntu 22.04 LTS** (Root-Zugriff)
  • NAS-Share unter /mnt/Backup gemountet
    • Empfohlen**: NFS (+ no_root_squash).

SMB/CIFS funktioniert mit den rsync-Optionen --no-owner --no-group.

  • Pakete:
apt install rsync jq

2 Backupscript

#!/usr/bin/env bash
# ==========================================================================
#  backup_docker_rsync.sh  –  Docker-Volumes & Compose sichern (rsync)
#  › paust nur "running" Container   › unpaust garantiert wieder
# ==========================================================================

set -euo pipefail
shopt -s nullglob

# ─── Konfiguration ────────────────────────────────────────────────────────
SNAPROOT="/mnt/Backup/Docker"
RETENTION_DAYS=7
COMPOSE_BASE="/data/compose"
INITIALLY_PAUSED=$(docker ps -q --filter status=paused)

# rsync-Grundoptionen (SMB/NFS ohne chown-Erlaubnis → kein owner/group)
RSYNC_BASE="-a --no-owner --no-group --numeric-ids --delete --link-dest"
# -------------------------------------------------------------------------

timestamp() { date +'%F-%H%M'; }
log()       { printf '\e[36m[%s] %s\e[0m\n' "$(date +'%F %T')" "$*"; }

SNAPDIR="$SNAPROOT/$(timestamp)"
LINKDEST="$SNAPROOT/latest"

# ─── Cleanup-Funktion (immer ausführen) ───────────────────────────────────
TMP=""
PAUSED=""
cleanup() {
  [[ -n "$PAUSED" ]] && docker unpause $PAUSED 2>/dev/null || true
  [[ -n "$TMP"    ]] && rm -rf "$TMP"
}
trap cleanup EXIT

# ─── 1) Metadaten-Dump ────────────────────────────────────────────────────
TMP=$(mktemp -d /tmp/docker_dump.XXXX)
log "Erzeuge Metadaten-Dump in $TMP"

docker info             > "$TMP/docker-info.txt"
docker images --digests > "$TMP/images.txt"
docker ps -a            > "$TMP/containers.txt"
docker inspect $(docker ps -aq) > "$TMP/containers.json" 2>/dev/null || true

mkdir -p "$TMP/compose"
if [[ -d "$COMPOSE_BASE" ]]; then
  find "$COMPOSE_BASE" -type f -iname 'docker-compose*.yml' \
       -exec cp --parents {} "$TMP/compose" \;
fi
# plus dynamisch laufende Stacks
while read -r DIR; do
  [[ -d $DIR ]] || continue
  find "$DIR" -type f -iname 'docker-compose*.yml' \
       -exec cp --parents {} "$TMP/compose" \;
done < <(docker ps --format '{{.Label "com.docker.compose.project.working_dir"}}' | sort -u)

# ─── 2) Nur RUNNING-Container pausieren ──────────────────────────────────
RUNNING=$(docker ps --filter status=running -q)
if [[ -n "$RUNNING" ]]; then
  log "Pausiere $(echo "$RUNNING" | wc -w) laufende Container"
  # shellcheck disable=SC2086
  docker pause $RUNNING || true      # Fehler ignorieren
  PAUSED="$RUNNING"
fi
# ─── 3) rsync-Snapshot ────────────────────────────────────────────────────
log "Starte rsync in $SNAPDIR"
mkdir -p "$SNAPDIR"

# Link-Dest nur setzen, wenn latest existiert
[[ -e "$LINKDEST" ]] && LD=(--link-dest="$LINKDEST") || LD=()

rsync -a --no-owner --no-group --numeric-ids --delete "${LD[@]}" \
      /var/lib/docker/volumes/          "$SNAPDIR/volumes"

rsync -a --no-owner --no-group --numeric-ids --delete "${LD[@]}" \
      /etc/docker/                      "$SNAPDIR/etc-docker"

# systemd-Drop-Ins nur sichern, falls Verzeichnis existiert
if [[ -d /etc/systemd/system/docker.service.d ]]; then
  rsync -a --no-owner --no-group --numeric-ids --delete "${LD[@]}" \
        /etc/systemd/system/docker.service.d/ "$SNAPDIR/docker-systemd"
fi

rsync -a --no-owner --no-group "$TMP/" "$SNAPDIR/metadata"

# ─── 4) „latest“-Symlink & Retention ─────────────────────────────────────
ln -snf "$SNAPDIR" "$SNAPROOT/latest"

log "Lösche Snapshots älter als $RETENTION_DAYS Tage"
find "$SNAPROOT" -maxdepth 1 -type d -name '20*' -mtime +"$RETENTION_DAYS" \
     -exec rm -rf {} +
# … rsync und Retention bereits gelaufen …

# 6) latest-Symlink aktualisieren
ln -snf "$SNAPDIR" "$SNAPROOT/latest"

# 7) Leserechte für SMB-User
log "Setze lesbare Rechte für SMB-Nutzer"
find "$SNAPDIR" -type d -exec chmod 755 {} +
find "$SNAPDIR" -type f -exec chmod 644 {} +
# unpause alles, was jetzt pausiert ist
docker unpause $(docker ps -q --filter status=paused) || true
# und PAUSE-Status von vorher wiederherstellen
for c in $INITIALLY_PAUSED; do
    docker pause "$c" || true
done

log "Backup abgeschlossen"

2.1 Wichtige Variablen im Kopfbereich

Variable Standardwert Bedeutung
SNAPROOT /mnt/Backup/Docker Ablageort der Snapshots
RETENTION_DAYS 7 Aufbewahrung (ältere Snapshots werden gelöscht)
COMPOSE_BASE /data/compose Oberordner der Compose-Stacks

3 Cron Job (täglich 02:30 Uhr)

# crontab -e   (als root)
30 2 * * * /usr/local/sbin/backup_docker_rsync.sh \
           >> /var/log/backup_docker.log 2>&1
  • Logging: Alle Ausgaben in /var/log/backup_docker.log.
  • Bei Fehlercodes ≠0 wird der Cron-MTA eine Mail an root schicken (sofern konfiguriert).

4 Funktionsweise

  1. **Metadaten-Dump** (Docker info, Container-/Image-Listen, Compose-YAMLs).
  2. **Nur noch laufende Container** werden kurz mit docker pause eingefroren.
  3. **rsync Snapshot**
  * Hard-Links via --link-dest → jede Sicherung „Vollkopie“, aber nur Deltas belegen Platz.  
  * Ohne -o -g ⇒ kompatibel mit SMB/NFS-Shares.  
  1. **Unpause** der zuvor laufenden Container (Cleanup-Trap gewährleistet dies selbst bei Abbruch).
  2. **latest-Symlink** wird aktualisiert, alte Snapshots nach RETENTION_DAYS gelöscht.
  3. **Rechte 755/644** auf neuem Snapshot → Windows-Benutzer können per SMB browsen.

5 Snapshot-Struktur

/mnt/Backup/Docker/
└── 2025-06-06-0230/
    ├── volumes/                # kompletter Inhalt von /var/lib/docker/volumes
    ├── etc-docker/             # /etc/docker
    ├── docker-systemd/         # systemd-Drop-Ins (falls vorhanden)
    └── metadata/
        ├── docker-info.txt
        ├── images.txt
        ├── containers.txt
        └── compose/…           # alle docker-compose*.yml
latest -> 2025-06-06-0230

6 Manueller Testlauf

/usr/local/sbin/backup_docker_rsync.sh
echo $?
# → 0  = Erfolg

7 Wiederherstellung

Kurzfassung für „latest“:

restore_docker_rsync.sh  -s latest

8 Troubleshooting

Meldung Ursache / Lösung
--link-dest arg does not exist Erster Lauf → ignorieren.
Operation not permitted (chown) SMB-Share ohne Chown-Rechte → OK; Daten wurden trotzdem kopiert.
Container bleiben paused Script vor v1.1; aktualisieren ODER manuell
 docker unpause $(docker ps -q --filter status=paused)
Windows kann nicht lesen Fs-Rechte → Script ≥v1.2 setzt 755/644
 oder Share mit noperm mounten.

9 Versionshistorie

Datum Version Änderung
2025-06-06 1.2 Rechtefix (755/644), robustes Unpause, Link-Dest-Check
2025-06-05 1.1 Pausiere nur laufende Container, Cleanup-Trap
2025-06-04 1.0 Erste produktive Version

Seite zuletzt aktualisiert: 06 Juni 2025