Registry truenas:13000 -> git.rismer.de/gulum (alle 6 Stellen). Dataset-Pfade auf /mnt/JailStorage/DockerVolumes/gerbilmanager/ gesetzt. docs/ops.md: vollstaendiges Goldeye-Runbook (Ordner + UID-999-Perms, Registry-Login, Port-80-Fallback, Restore-Drill-Pflichtschritt, ZFS-Pfade). docker compose config: OK.
13 KiB
GerbilManager — Betriebsanleitung (TrueNAS SCALE Goldeye)
Zielgruppe: Julian (Systemadministration) und Ehefrau (tägliche Nutzung). Bookmark für die Ehefrau: http://<NAS-IP>/ (z. B. http://truenas/)
Inhaltsverzeichnis
- Übersicht & Architektur
- Voraussetzungen
- Erstinstallation auf TrueNAS Goldeye
- App starten / stoppen / aktualisieren
- Backup & Wiederherstellung
- ZFS-Snapshot-Schichtung
- CI/CD via Gitea Actions
- Fehlerbehebung
1. Übersicht & Architektur
Browser / Handy
| HTTP :80 (oder PORT aus .env, z.B. 8080)
v
┌──────────────────┐
│ frontend (nginx) │ statisches React-SPA + Reverse-Proxy
└──────┬───────────┘
│ /api/* → http://api:8080/*
│ /scalar → http://api:8080/scalar
v
┌──────────────────┐
│ api (.NET 10) │ GerbilManagerWebAPI, Minimal API
└──────┬───────────┘
│ ConnectionStrings__gerbilmanager
v
┌──────────────────┐ ┌──────────────────────┐
│ db (Postgres 17)│ │ backup (Sidecar) │
└──────────────────┘ │ pg_dump + tar + cron │
│ └──────────────────────┘
└─ pgdata-Volume → /mnt/JailStorage/DockerVolumes/gerbilmanager/pgdata
photos-Volume → /mnt/JailStorage/DockerVolumes/gerbilmanager/photos
backups-Volume → /mnt/JailStorage/DockerVolumes/gerbilmanager/backups
keys-Volume → /mnt/JailStorage/DockerVolumes/gerbilmanager/keys
Einziger veröffentlichter Port: 80 (konfigurierbar via PORT in .env).
Alles andere läuft intern im Docker-Netz.
2. Voraussetzungen
| Was | Details |
|---|---|
| TrueNAS SCALE | 25.10.2.1 „Goldeye" (native Docker Custom Apps) |
| Container Registry | git.rismer.de/gulum (externes HTTPS) |
| Docker | bereits auf TrueNAS Goldeye vorhanden |
| Verzeichnisse | 4 Ordner unter /mnt/JailStorage/DockerVolumes/gerbilmanager/ anlegen (Schritt 3.1) |
3. Erstinstallation auf TrueNAS Goldeye
3.1 Verzeichnisse anlegen und Berechtigungen setzen
Öffne eine Shell auf der NAS (TrueNAS → System → Shell oder SSH):
# Vier Ordner anlegen
mkdir -p /mnt/JailStorage/DockerVolumes/gerbilmanager/pgdata
mkdir -p /mnt/JailStorage/DockerVolumes/gerbilmanager/photos
mkdir -p /mnt/JailStorage/DockerVolumes/gerbilmanager/backups
mkdir -p /mnt/JailStorage/DockerVolumes/gerbilmanager/keys
# Postgres-Container läuft als UID 999 (postgres) / GID 999 intern.
# pgdata muss von UID 999 beschreibbar sein; postgres erzwingt chmod 0700.
chown -R 999:999 /mnt/JailStorage/DockerVolumes/gerbilmanager/pgdata
chmod 700 /mnt/JailStorage/DockerVolumes/gerbilmanager/pgdata
# photos, backups und keys werden von der API bzw. dem Sidecar beschrieben
# (laufen als root im Container) — keine weiteren ACL-Anpassungen nötig.
TrueNAS Dataset-ACL-Hinweis: Falls
JailStorageein ZFS-Dataset mit NFSv4-ACLs ist, undchownmeldet „Operation not permitted": setze in TrueNAS → Datasets →JailStorage→ Berechtigungen → ACL-Typ: POSIX (oder nutze das UI-Formular „Eigentümer: 999, Gruppe: 999" für daspgdata-Unterverzeichnis).
3.2 Registry-Login auf der NAS
docker login git.rismer.de
# Benutzername und Token/Passwort eingeben (Gitea-Account oder Access Token mit read:packages)
Der Login wird unter /root/.docker/config.json gespeichert und bleibt nach Reboots erhalten.
3.3 Repository klonen
git clone https://git.rismer.de/gulum/GerbilManager.git /opt/gerbilmanager
cd /opt/gerbilmanager
3.4 Konfiguration anlegen
cp deploy/truenas/.env.example deploy/truenas/.env
nano deploy/truenas/.env
Mindestens setzen:
| Variable | Wert |
|---|---|
POSTGRES_PASSWORD |
Sicheres Passwort (mind. 20 Zeichen, keine ") |
AI__BaseUrl |
Gemini: https://generativelanguage.googleapis.com/v1beta/openai |
AI__ApiKey |
Dein Gemini API-Key |
AI__Model |
gemini-2.0-flash (oder gemini-flash-latest) |
PORT |
80 — falls Port 80 auf der NAS bereits belegt ist: auf 8080 ändern |
Die Pfad-Variablen (PGDATA_PATH, PHOTOS_PATH, etc.) sind bereits auf die Goldeye-Standardpfade
vorbelegt und müssen nur geändert werden, wenn du einen anderen Pool nutzt.
3.5 Images ziehen und App starten
cd /opt/gerbilmanager
docker compose -f deploy/truenas/compose.yaml pull
docker compose -f deploy/truenas/compose.yaml up -d
Erster Start dauert ca. 2–3 Minuten (Postgres-Init + EF-Migrationen).
TrueNAS Goldeye Custom App (Alternative): Statt der Shell kann die App auch über TrueNAS → Apps → „Custom App installieren" → „Install via YAML" deployt werden: compose-Inhalt einfügen, Volumes als Host-Pfade konfigurieren. Die Shell-Methode ist einfacher und gibt mehr Kontrolle.
3.6 Verifikation
# Alle 4 Container laufen?
docker compose -f deploy/truenas/compose.yaml ps
# API-Healthcheck (erwartet: {"status":"Healthy"})
curl -s http://localhost/api/health
# Tier-Gesamtanzahl prüfen (erwartet > 0 nach Import)
curl -s "http://localhost/api/gerbils?pageSize=1" | grep -o '"totalCount":[0-9]*'
# API-Doku (Scalar) im Browser
http://<NAS-IP>/scalar
# Foto-Upload: in der Webapp ein Tier öffnen → Foto hochladen → Foto erscheint
4. App starten / stoppen / aktualisieren
Starten
cd /opt/gerbilmanager
docker compose -f deploy/truenas/compose.yaml up -d
Stoppen
docker compose -f deploy/truenas/compose.yaml down
Aktualisieren (nach CI-Push auf main)
cd /opt/gerbilmanager
git pull
docker compose -f deploy/truenas/compose.yaml pull
docker compose -f deploy/truenas/compose.yaml up -d
EF-Migrationen laufen automatisch beim API-Start — kein manueller Schritt nötig.
5. Backup & Wiederherstellung
Automatisches Backup
Der backup-Sidecar-Container läuft dauerhaft und sichert täglich um 03:00 Uhr:
- Kompletter
pg_dumpder Datenbank als.sql - Komprimiertes Foto-Archiv als
.tar.gz - Rotation: Backups älter als
BACKUP_KEEP_DAYS(Standard: 7) werden gelöscht
Backups liegen unter: /mnt/JailStorage/DockerVolumes/gerbilmanager/backups/YYYY-MM-DD_HH-MM/
/mnt/JailStorage/DockerVolumes/gerbilmanager/backups/
2026-06-06_03-00/
gerbilmanager_2026-06-06_03-00.sql (Datenbank-Dump, Klartext SQL)
photos_2026-06-06_03-00.tar.gz (Fotos)
backup.log (Protokoll)
Manuelles Backup auslösen
docker compose -f deploy/truenas/compose.yaml exec backup /bin/sh /scripts/backup.sh
Backup-Log prüfen
tail -50 /mnt/JailStorage/DockerVolumes/gerbilmanager/backups/backup.log
Backup-Validierung: Das Skript prüft ob der Dump CREATE TABLE enthält — fehlt dieser
Marker, erscheint eine WARNUNG im Log. Größe 0 KB bedeutet Fehlschlag.
Wiederherstellung — Runbook
WARNUNG: Alle aktuellen Datenbankdaten und Fotos werden überschrieben!
Schritt 1: API und Frontend stoppen (DB und backup-Sidecar laufen weiter)
docker compose -f deploy/truenas/compose.yaml stop api frontend
Schritt 2: Restore ausführen
# Neuestes Backup automatisch wählen und bestätigen:
docker compose -f deploy/truenas/compose.yaml exec -T backup \
/bin/sh /scripts/restore.sh latest -f
# Bestimmtes Backup (Datum aus Verzeichnisname):
docker compose -f deploy/truenas/compose.yaml exec -T backup \
/bin/sh /scripts/restore.sh 2026-06-06_03-00 -f
Das Skript:
- Trennt alle offenen DB-Verbindungen
- Spielt den SQL-Dump mit
psql -h db -U postgres -d gerbilmanager < dump.sqlein - Entpackt das Foto-Archiv nach
/data/photos
Schritt 3: API neu starten
docker compose -f deploy/truenas/compose.yaml start api frontend
Schritt 4 — Verifikation (Pflicht nach erstem Restore-Drill):
# Tier-Anzahl prüfen
curl -s "http://localhost/api/gerbils?pageSize=1" | grep -o '"totalCount":[0-9]*'
# ColorVariety-Anzahl (Stammdaten, erwartet: >= 60)
curl -s http://localhost/api/color-varieties | python3 -c "import sys,json; print(len(json.load(sys.stdin)))"
# Foto stichprobenartig prüfen
ls /mnt/JailStorage/DockerVolumes/gerbilmanager/photos/ | head -5
Restore-Nachweis (Round-Trip-Test, lokal 2026-06-06)
Protokoll vom getesteten Restore auf lokalem Aspire-Postgres:
73 ColorVarieties vorhanden
→ DELETE 12 Zeilen → 61 verbleibend
→ psql < dump.sql eingespielt
→ 73 ColorVarieties bestätigt
Exit-Code: 0
Erster TrueNAS-Restore-Drill: nach Erstinstallation bitte ausführen und Tier-Anzahl notieren — beweist dass Backup + Restore auf dem NAS korrekt funktionieren.
6. ZFS-Snapshot-Schichtung
ZFS-Snapshots ergänzen die pg_dump-Backups als zweite Sicherungsebene. Sie schützen vor versehentlichem Datenverlust auf Dataset-Ebene.
Empfohlene Snapshot-Konfiguration
In TrueNAS → Datasets → JailStorage/DockerVolumes/gerbilmanager → Snapshots → Regelmäßige Snapshots:
| Unterordner | Häufigkeit | Aufbewahrung |
|---|---|---|
.../photos |
Stündlich | 24 Stunden |
.../photos |
Täglich | 30 Tage |
.../pgdata |
Stündlich | 24 Stunden |
.../pgdata |
Täglich | 30 Tage |
.../backups |
Täglich | 90 Tage |
Hinweis:
pgdataenthält Live-Postgres-Dateien. ZFS-Snapshots davon sind crash-konsistent, aber nicht application-konsistent — für einen sauberen DB-Restore immer denpg_dumpverwenden, nicht den ZFS-Snapshot vonpgdata.
Snapshot manuell erstellen (z. B. vor Update)
# Pool-/Dataset-Name anpassen falls nötig
zfs snapshot JailStorage/DockerVolumes/gerbilmanager/photos@vor-update-$(date +%Y%m%d)
zfs snapshot JailStorage/DockerVolumes/gerbilmanager/backups@vor-update-$(date +%Y%m%d)
Aus ZFS-Snapshot wiederherstellen (Fotos)
# Snapshots auflisten
zfs list -t snapshot JailStorage/DockerVolumes/gerbilmanager/photos
# Einzelne Datei aus Snapshot kopieren
cp /mnt/JailStorage/DockerVolumes/gerbilmanager/photos/.zfs/snapshot/<NAME>/datei.jpg \
/mnt/JailStorage/DockerVolumes/gerbilmanager/photos/
7. CI/CD via Gitea Actions
CI pusht Images nach Erfolg zu git.rismer.de/gulum/gerbilmanager-api und
git.rismer.de/gulum/gerbilmanager-frontend.
Registry-Secrets in Gitea
Gitea → Repository → Einstellungen → Secrets:
| Secret | Wert |
|---|---|
REGISTRY_USER |
Gitea-Benutzername |
REGISTRY_TOKEN |
Gitea Access Token mit package:write |
Update nach CI-Push
# Auf der NAS nach erfolgreichem CI-Lauf:
cd /opt/gerbilmanager
git pull
docker compose -f deploy/truenas/compose.yaml pull
docker compose -f deploy/truenas/compose.yaml up -d
8. Fehlerbehebung
App startet nicht
docker compose -f deploy/truenas/compose.yaml logs
docker compose -f deploy/truenas/compose.yaml logs api
docker compose -f deploy/truenas/compose.yaml logs db
Port 80 belegt
Falls Port 80 vom TrueNAS-System selbst genutzt wird:
# In deploy/truenas/.env:
PORT=8080
# Dann neu starten:
docker compose -f deploy/truenas/compose.yaml up -d
Postgres startet nicht (Permission denied auf pgdata)
# UID 999 muss Eigentümer des pgdata-Verzeichnisses sein:
chown -R 999:999 /mnt/JailStorage/DockerVolumes/gerbilmanager/pgdata
chmod 700 /mnt/JailStorage/DockerVolumes/gerbilmanager/pgdata
docker compose -f deploy/truenas/compose.yaml restart db
Registry-Pull schlägt fehl
# Neu einloggen:
docker login git.rismer.de
# Dann pull wiederholen:
docker compose -f deploy/truenas/compose.yaml pull
Datenbank nicht erreichbar
docker compose -f deploy/truenas/compose.yaml ps db
docker compose -f deploy/truenas/compose.yaml exec db \
psql -U postgres -d gerbilmanager -c "\dt"
Backup-Fehler
tail -50 /mnt/JailStorage/DockerVolumes/gerbilmanager/backups/backup.log
docker compose -f deploy/truenas/compose.yaml exec backup /bin/sh /scripts/backup.sh
Fotos werden nicht angezeigt
docker compose -f deploy/truenas/compose.yaml exec api ls /data/photos
Kompletter Neustart (Daten bleiben erhalten)
docker compose -f deploy/truenas/compose.yaml down
docker compose -f deploy/truenas/compose.yaml up -d