Files
GerbilManager/deploy/truenas/custom-app.compose.yaml
Gulum 0a4bcabd98
Some checks failed
CI / Backend Tests (.NET) (push) Successful in 1m9s
CI / Frontend Tests (Node/Vite) (push) Successful in 9m34s
CI / Docker Build & Push (push) Successful in 1m29s
CI / Deploy auf TrueNAS (Custom App) (push) Failing after 3s
feat(deploy): publicsite-Container intern (Port 8081) + app.update im Deploy-Skript
- custom-app.compose.yaml: publicsite (nginx) ergaenzt, LAN-only, statisches HTML aus
  publicsite-Volume (POST /api/publish); PUBLICSITE_PORT-Platzhalter
- truenas-deploy.sh: bei existierender App app.update (statt nur redeploy), damit
  Compose-Aenderungen (neue Dienste) uebernommen werden
- CLAUDE.md: 5. Dienst dokumentiert

Verifiziert: publicsite Up auf 8081, publish -> HTTP 200 (inkl. abgabetiere-Seite).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-19 14:24:54 +02:00

117 lines
4.6 KiB
YAML

# GerbilManager — TrueNAS SCALE Custom App (Goldeye 25.10)
# =========================================================
# Diese Datei ist die VORLAGE fuer die TrueNAS-"Custom App" (taucht unter Apps auf).
# Sie wird NICHT direkt mit `docker compose` gestartet, sondern von
# deploy/truenas/scripts/truenas-deploy.sh
# gerendert (Platzhalter aus deploy/truenas/.env eingesetzt) und via
# midclt call app.create {custom_app:true, app_name:gerbilmanager, custom_compose_config_string:<yaml>}
# an die TrueNAS-Middleware uebergeben. Redeploys laufen ueber `midclt call app.redeploy`.
#
# Unterschiede zur lokalen deploy/truenas/compose.yaml:
# * ABSOLUTE Host-Bind-Pfade (Custom Apps kennen keine relativen ./-Mounts) —
# gleiche Konvention wie die anderen Apps dieser NAS (/mnt/JailStorage/DockerVolumes/...).
# * pull_policy: always -> `app.redeploy` zieht das frische :latest aus der Registry.
# * kein publicsite-Container (oeffentliche Seite ist ein separater Schritt mit Domain/Proxy).
#
# Platzhalter (werden von truenas-deploy.sh aus .env ersetzt):
# __POSTGRES_PASSWORD__ __REGISTRY__ __TAG__ __PORT__ __AI_BASEURL__ __AI_APIKEY__ __AI_MODEL__
services:
# --- PostgreSQL 18 (Debian-Image: Locale en_US.utf8 == Quell-DB) ---
db:
image: postgres:18
restart: unless-stopped
environment:
POSTGRES_PASSWORD: "__POSTGRES_PASSWORD__"
POSTGRES_DB: gerbilmanager
POSTGRES_USER: postgres
TZ: Europe/Berlin
volumes:
# postgres:18 legt PGDATA unter /var/lib/postgresql/18/docker ab und deklariert
# das Volume als /var/lib/postgresql (NICHT .../data). Mount an .../data -> Start
# scheitert ("data in unused mount/volume") -> db unhealthy.
- /mnt/JailStorage/DockerVolumes/gerbilmanager/pgdata:/var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d gerbilmanager"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
# --- .NET API ---
api:
image: "__REGISTRY__/gerbilmanager-api:__TAG__"
pull_policy: always
restart: unless-stopped
environment:
ASPNETCORE_ENVIRONMENT: Production
ConnectionStrings__gerbilmanager: "Host=db;Port=5432;Database=gerbilmanager;Username=postgres;Password=__POSTGRES_PASSWORD__"
Photos__RootPath: /data/photos
DataProtection__KeyRingPath: /data/keys
PublicSite__RootPath: /data/publicsite
AI__BaseUrl: "__AI_BASEURL__"
AI__ApiKey: "__AI_APIKEY__"
AI__Model: "__AI_MODEL__"
TZ: Europe/Berlin
volumes:
- /mnt/JailStorage/DockerVolumes/gerbilmanager/photos:/data/photos
- /mnt/JailStorage/DockerVolumes/gerbilmanager/keys:/data/keys
- /mnt/JailStorage/DockerVolumes/gerbilmanager/publicsite:/data/publicsite
depends_on:
db:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:8080/health || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 90s
# --- Frontend (nginx: React-SPA + /api-Proxy) ---
frontend:
image: "__REGISTRY__/gerbilmanager-frontend:__TAG__"
pull_policy: always
restart: unless-stopped
ports:
- "__PORT__:80"
depends_on:
api:
condition: service_healthy
# --- Oeffentliche Seite (WEB-2), vorerst nur INTERN gehostet ---
# Serviert NUR statisches HTML aus dem publicsite-Volume (live/), das die API via
# POST /api/publish schreibt. Kein Proxy auf api/frontend. Solange nichts publiziert
# wurde, ist das Volume leer -> 404 (erwartet). Extern (Domain/TLS) ist ein spaeterer
# Schritt ueber Julians Reverse-Proxy (siehe deploy/truenas/vhost-snippet.conf).
publicsite:
image: nginx:alpine
restart: unless-stopped
ports:
- "__PUBLICSITE_PORT__:80"
volumes:
- /mnt/JailStorage/DockerVolumes/gerbilmanager/publicsite:/usr/share/nginx/html:ro
- /mnt/JailStorage/DockerVolumes/gerbilmanager/deploy/truenas/nginx/publicsite.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- api
# --- Backup-Sidecar (taeglicher pg_dump + Foto-Archiv + Rotation) ---
backup:
image: postgres:18
restart: unless-stopped
environment:
PGPASSWORD: "__POSTGRES_PASSWORD__"
POSTGRES_HOST: db
POSTGRES_USER: postgres
POSTGRES_DB: gerbilmanager
BACKUP_KEEP_DAYS: "7"
TZ: Europe/Berlin
volumes:
- /mnt/JailStorage/DockerVolumes/gerbilmanager/photos:/data/photos:ro
- /mnt/JailStorage/DockerVolumes/gerbilmanager/backups:/backups
- /mnt/JailStorage/DockerVolumes/gerbilmanager/scripts:/scripts:ro
depends_on:
db:
condition: service_healthy
entrypoint: ["/bin/sh", "/scripts/entrypoint.sh"]