# Backup & Restore

# Daten einer einzelnen Apllikation sichern

### Beschreibung:

Es gibt momente da möchte man nicht alles wiederherstellen, sondern nur eine Einzelne Applikation.  
Oder man möchte eine Applikation mit Daten auf eine andere Instanz übertragen.

### Vorrausetzung:

Der SQL-Server ist von außen erreichbar oder auf den gleichem Host erreichbar.  
DIe Applikationen die transferiert werden haben quelle und ziel den gleichen Versionsstand.

### Abblauf:

Appliaktion auf neue Instanz ausrollen.  
Applikationsdaten auf neue Instanz ausrollen (Die vorhandenen aus der Datenbank werden gelöscht).

#### Backupprogramm erstellen:

Das Backupprogramm ist ein docker-container auf Debian 13 trixie basis  
  
Es besteht aus einer dockerfile  
einem Script  
einer docker-compose datei

#### Das Script backup\_Script.py

```
#!/usr/bin/python3
import os
import subprocess
from datetime import datetime

def backup_or_restore():
    # Read environment variables
    host = os.getenv("BACKUP_HOST")
    database = os.getenv("BACKUP_DATABASE")
    schema = os.getenv("BACKUP_SCHEMA")
    user = os.getenv("BACKUP_USER")
    password = os.getenv("BACKUP_PASSWORD")
    action = os.getenv("BACKUP_ACTION", "backup")
    restore_file = os.getenv("RESTORE_FILE")  # Datei für das Restore

    # Set backup file name with current date
    backup_file = f"/backup/{database}_{schema}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.sql"

    # Set environment variable for password
    env = {"PGPASSWORD": password}

    if action == "backup":
        # Create the backup command
        command = [
            "pg_dump",
            "-h", host,
            "-U", user,
            "-d", database,
            "-n", schema,
            "-f", backup_file
        ]
        try:
            print("Erstelle Backup...")
            subprocess.run(command, env=env, check=True)
            print(f"Backup erfolgreich erstellt: {backup_file}")
        except subprocess.CalledProcessError as e:
            print(f"Fehler beim Erstellen des Backups: {e}")

    elif action == "restore":
        # Verwende die angegebene Datei oder den automatisch benannten Dateinamen
        if not restore_file:
            print("Fehler: Keine Datei für das Restore angegeben.")
            return
        
        drop_schema_command = f"DROP SCHEMA IF EXISTS {schema} CASCADE;\n"
        
        try:
            # Read the specified backup file
            with open(restore_file, 'r') as f:
                backup_content = f.read()

            restore_content = drop_schema_command + backup_content

            # Write to a temporary file
            temp_file = f"{restore_file}.temp.sql"
            with open(temp_file, 'w') as f:
                f.write(restore_content)

            # Run the restore command
            command = [
                "psql",
                "-h", host,
                "-U", user,
                "-d", database,
                "-f", temp_file
            ]
            print("Stelle Backup wieder her...")
            subprocess.run(command, env=env, check=True)
            print("Wiederherstellung erfolgreich.")

            # Delete the temporary file
            if os.path.exists(temp_file):
                os.remove(temp_file)
                print(f"Temporäre Datei nach Fehler gelöscht: {temp_file}")

        except Exception as e:
            print(f"Fehler bei der Wiederherstellung: {e}")
            # Optional: Remove temp file if it exists, even on failure
            if os.path.exists(temp_file):
                os.remove(temp_file)
                print(f"Temporäre Datei nach Fehler gelöscht: {temp_file}")
    else:
        print("Ungültige Aktion. Verwenden Sie 'backup' oder 'restore'.")

if __name__ == "__main__":
    backup_or_restore()

```

#### Dockerfile:

```
# Base image: Debian 13
FROM debian:trixie

# Install Python3 and PostgreSQL client tools
RUN apt update && \
    apt install -y python3 python3-pip postgresql-client && \
    rm -rf /var/lib/apt/lists/*

# Set the work directory and backup directory
WORKDIR /backup

# Copy the Python script to /usr/bin
COPY backup_script.py /usr/bin/backup_script.py
RUN chmod +x /usr/bin/backup_script.py

# Set environment variables
ENV BACKUP_HOST ""
ENV BACKUP_DATABASE ""
ENV BACKUP_SCHEMA ""
ENV BACKUP_USER ""
ENV BACKUP_PASSWORD ""
ENV BACKUP_ACTION "backup"  # Default action is "backup", can be "restore" as well

# Run the script on container start
ENTRYPOINT ["/usr/bin/backup_script.py"]

```

Docker compose datei

```
version: '3.3'

services:    
    postgres_backup:
      build: .
      environment:
        - BACKUP_HOST=127.0.0.1 #hostname or ip
        - BACKUP_DATABASE=app #database name for rei3 let it os
        - BACKUP_SCHEMA=hacker_soft_lizenzmanager #the applikation name
        - BACKUP_USER=app #rei 3 standard user
        - BACKUP_PASSWORD=app #your password (app is standard)
        - BACKUP_ACTION=backup # Use "backup" for backup and  "restore" for restore actions
        - RESTORE_FILE=/backup/app_20241027_195303.sql #the path to file to restore
      volumes:
        - ./backup:/backup  # Mount local backup folder
      restart: "no"  # Do not restart automatically

```

#### Starten:

Den container starten. Beim ertsen mal wird da image erstellt wenn es noch nicht besteht.

```
docker-compose up -d postgres_backup
```

Soll das Image neuerstellt werden dann

```
docker-compose up -d --build postgres_backup
```

mit dem Befehl können wir uns das Log anschauen

```
docker-compose logs postgres_backup
```

Screenshots:

Our Applikation with Data on Source  
[![Auswahl_303.png](https://wiki.hacker-net.de/uploads/images/gallery/2024-10/scaled-1680-/gEqGMT4Q37tkJCYs-auswahl-303.png)](https://wiki.hacker-net.de/uploads/images/gallery/2024-10/gEqGMT4Q37tkJCYs-auswahl-303.png)

Make backup:

Comamnds and output:

```
root@rei3:~/rei3# docker-compose up -d postgres_backup 
Recreating rei3_postgres_backup_1 ... done
root@rei3:~/rei3# docker-compose logs postgres_backup 
Attaching to rei3_postgres_backup_1
postgres_backup_1  | Erstelle Backup...
postgres_backup_1  | Backup erfolgreich erstellt: /backup/app_20241027_202341.sql
root@rei3:~/rei3# 
```

Nun auf der Ziel instance keine Applikation und Schema von der app existiert  
  
[![Auswahl_305.png](https://wiki.hacker-net.de/uploads/images/gallery/2024-10/scaled-1680-/JHGYdKnWExL2Hwlh-auswahl-305.png)](https://wiki.hacker-net.de/uploads/images/gallery/2024-10/JHGYdKnWExL2Hwlh-auswahl-305.png)  
[![Auswahl_304.png](https://wiki.hacker-net.de/uploads/images/gallery/2024-10/scaled-1680-/6d4bI7wvGh7JYMAc-auswahl-304.png)](https://wiki.hacker-net.de/uploads/images/gallery/2024-10/6d4bI7wvGh7JYMAc-auswahl-304.png)

Nun die Anwendung installieren auf der Zielinstance  
[![Auswahl_306.png](https://wiki.hacker-net.de/uploads/images/gallery/2024-10/scaled-1680-/uBtG6Zwq773odyIP-auswahl-306.png)](https://wiki.hacker-net.de/uploads/images/gallery/2024-10/uBtG6Zwq773odyIP-auswahl-306.png)

[![Auswahl_307.png](https://wiki.hacker-net.de/uploads/images/gallery/2024-10/scaled-1680-/GfaNJkiMd5G5r4xS-auswahl-307.png)](https://wiki.hacker-net.de/uploads/images/gallery/2024-10/GfaNJkiMd5G5r4xS-auswahl-307.png)

Und wenn man die App öffnen keine Ergebniss bei Software

[![Auswahl_308.png](https://wiki.hacker-net.de/uploads/images/gallery/2024-10/scaled-1680-/1JOwSM4MQuZ6BaXI-auswahl-308.png)](https://wiki.hacker-net.de/uploads/images/gallery/2024-10/1JOwSM4MQuZ6BaXI-auswahl-308.png)

Nun die docker-compose Datei ändern, auf restore und den richtigen Dateinamen bei restore\_file anpassen

```
- BACKUP_ACTION=restore  # Use "backup" for backup and  "restore" for restore actions
- RESTORE_FILE=/backup/app_20241027_202341.sql  #the path to file to restore
```

Nun den container nochmals starten:  
Command mit Output:

<details id="bkmrk-docker-compose-up--d-1"><summary>docker-compose up -d postgres\_backup</summary>

oot@rei3:~/rei3# docker-compose up -d postgres\_backup   
Recreating rei3\_postgres\_backup\_1 ... done  
root@rei3:~/rei3# docker-compose logs postgres\_backup   
Attaching to rei3\_postgres\_backup\_1  
postgres\_backup\_1 | psql:/backup/app\_20241027\_202341.sql.temp.sql:1: NOTICE: drop cascades to 6 other objects  
postgres\_backup\_1 | DETAIL: drop cascades to table hacker\_soft\_lizenzmanager.kunden  
postgres\_backup\_1 | drop cascades to table hacker\_soft\_lizenzmanager.lizenzen  
postgres\_backup\_1 | drop cascades to table hacker\_soft\_lizenzmanager.software  
postgres\_backup\_1 | drop cascades to sequence hacker\_soft\_lizenzmanager."sq\_23949c20-8f0d-4530-9bf1-35e5db82908b"  
postgres\_backup\_1 | drop cascades to sequence hacker\_soft\_lizenzmanager."sq\_524876be-5a68-4162-8a9b-2a240b129d47"  
postgres\_backup\_1 | drop cascades to sequence hacker\_soft\_lizenzmanager."sq\_b708e577-d88f-40ef-b594-811bd8aead74"  
postgres\_backup\_1 | DROP SCHEMA  
postgres\_backup\_1 | SET  
postgres\_backup\_1 | SET  
postgres\_backup\_1 | SET  
postgres\_backup\_1 | SET  
postgres\_backup\_1 | SET  
postgres\_backup\_1 | SET  
postgres\_backup\_1 | set\_config   
postgres\_backup\_1 | ------------  
postgres\_backup\_1 |   
postgres\_backup\_1 | (1 row)  
postgres\_backup\_1 |   
postgres\_backup\_1 | SET  
postgres\_backup\_1 | SET  
postgres\_backup\_1 | SET  
postgres\_backup\_1 | SET  
postgres\_backup\_1 | CREATE SCHEMA  
postgres\_backup\_1 | ALTER SCHEMA  
postgres\_backup\_1 | CREATE SEQUENCE  
postgres\_backup\_1 | ALTER SEQUENCE  
postgres\_backup\_1 | SET  
postgres\_backup\_1 | SET  
postgres\_backup\_1 | CREATE TABLE  
postgres\_backup\_1 | ALTER TABLE  
postgres\_backup\_1 | CREATE SEQUENCE  
postgres\_backup\_1 | ALTER SEQUENCE  
postgres\_backup\_1 | CREATE TABLE  
postgres\_backup\_1 | ALTER TABLE  
postgres\_backup\_1 | CREATE SEQUENCE  
postgres\_backup\_1 | ALTER SEQUENCE  
postgres\_backup\_1 | CREATE TABLE  
postgres\_backup\_1 | ALTER TABLE  
postgres\_backup\_1 | COPY 1  
postgres\_backup\_1 | COPY 0  
postgres\_backup\_1 | COPY 2  
postgres\_backup\_1 | setval   
postgres\_backup\_1 | --------  
postgres\_backup\_1 | 1  
postgres\_backup\_1 | (1 row)  
postgres\_backup\_1 |   
postgres\_backup\_1 | setval   
postgres\_backup\_1 | --------  
postgres\_backup\_1 | 1  
postgres\_backup\_1 | (1 row)  
postgres\_backup\_1 |   
postgres\_backup\_1 | setval   
postgres\_backup\_1 | --------  
postgres\_backup\_1 | 2  
postgres\_backup\_1 | (1 row)  
postgres\_backup\_1 |   
postgres\_backup\_1 | ALTER TABLE  
postgres\_backup\_1 | ALTER TABLE  
postgres\_backup\_1 | ALTER TABLE  
postgres\_backup\_1 | CREATE INDEX  
postgres\_backup\_1 | CREATE INDEX  
postgres\_backup\_1 | ALTER TABLE  
postgres\_backup\_1 | ALTER TABLE  
postgres\_backup\_1 | Stelle Backup wieder her...  
postgres\_backup\_1 | Wiederherstellung erfolgreich.  
postgres\_backup\_1 | Temporäre Datei gelöscht: /backup/app\_20241027\_202341.sql.temp.sql

</details>Wenn wir nun wieder in dei Applikation gehen und die Tabs hin und herwechseln sehen wir unsere Daten, sogar mit umlauten

[![Auswahl_309.png](https://wiki.hacker-net.de/uploads/images/gallery/2024-10/scaled-1680-/ouKDpKq5BKjoC6nd-auswahl-309.png)](https://wiki.hacker-net.de/uploads/images/gallery/2024-10/ouKDpKq5BKjoC6nd-auswahl-309.png)

Und das schmea ist logischerweise auch wieder da

[![Auswahl_310.png](https://wiki.hacker-net.de/uploads/images/gallery/2024-10/scaled-1680-/tXIpfSwPLkq9yBtP-auswahl-310.png)](https://wiki.hacker-net.de/uploads/images/gallery/2024-10/tXIpfSwPLkq9yBtP-auswahl-310.png)  
Fertig