Skip to content

Docker Setup

IntegraMon wird als Multi-Process-Container gebaut. Ein Image enthaelt:

  • Nginx
  • Gunicorn mit der Django-ASGI-App
  • Redis bei REDIS_LOCAL=true
  • PostgreSQL bei DB_LOCAL=true und DB_BACKEND=postgresql
  • mehrere Celery-Worker
  • den Custom-Controller cpi/worker.py
  • die PDF-Export-Toolchain mit Chromium und Mermaid CLI

Supervisor startet und koordiniert diese Prozesse.

Runtime-Boot-Sequenz

Beim Containerstart ist die Abfolge:

  1. deploy/scripts/boot.py wandelt JSON-Konfiguration in /app/backend/src/.env
  2. deploy/start.sh sourced diese .env
  3. mount.py mountet optional Koofr, SMB oder SSHFS
  4. DATA_DIR und LOG_DIR werden aufgeloest
  5. Nginx-Konfiguration wird aus Templates gerendert, sofern kein NGINX_CONF_OVERRIDE gesetzt ist
  6. Supervisor startet PostgreSQL, Redis, Migration, Web, Celery, Controller und Nginx

Darum ist die Docker-Konfiguration nicht nur eine Menge docker run -e ...-Variablen. Die Boot-Schicht schreibt und normalisiert die effektive Runtime-Umgebung zuerst um.

Wie Konfiguration in den Container gelangt

Es gibt zwei unterstuetzte Bootstrap-Kanaele:

  1. CONFIG_JSON_B64
  2. eine gemountete Datei unter /run/secrets/app-config.json

Beide erwarten JSON mit Upper-Case-Keys wie:

{
  "DB_BACKEND": "postgresql",
  "DB_HOST": "127.0.0.1",
  "DB_PORT": 5432,
  "DB_NAME": "monitorx",
  "DB_USER": "postgres",
  "DB_PASSWORD": "secret",
  "CELERY_BROKER_URL": "redis://localhost:6379/0",
  "REDIS_CACHE_URL": "redis://localhost:6379/2",
  "DATA_DIR": "/app/data"
}

Warum CONFIG_JSON_B64 existiert

Base64-JSON ist nuetzlich, weil es:

  • ein strukturiertes Payload statt vieler -e KEY=value-Flags liefert
  • gut auf Plattformen mit reiner ENV-Injektion funktioniert
  • Quoting-Probleme bei JSON im Shell-Kontext vermeidet
  • dieselben Keys transportiert, die spaeter als .env-Eintraege landen

Im Container macht boot.py dann:

  1. Whitespace entfernen
  2. base64 dekodieren
  3. JSON parsen
  4. normalisierte KEY=value-Zeilen in /app/backend/src/.env schreiben

Ist CONFIG_JSON_B64 ungueltig, stoppt der Boot sofort.

Tatsaechliche Prioritaet in Docker

Die effektive Reihenfolge im laufenden Container ist:

  1. CONFIG_JSON_B64
  2. /run/secrets/app-config.json
  3. bestehende /app/backend/src/.env
  4. boot.py-Fallback-Defaults
  5. Django-Setting-Fallbacks
  6. Laufzeitdaten aus der Datenbank wie Worker-Tuning, Metrik-Intervalle, Tenant-Konfiguration, Templates und Cleanup-Settings

Das ist wichtig, weil Einstellungen ueber mehrere Ebenen verteilt sind:

  • Infrastruktur-Settings wie DB oder Redis kommen aus ENV
  • Application-Defaults greifen trotzdem, wenn ein Key fehlt
  • Tenant-Verhalten kommt oft aus cConfigExt
  • Plattform-Tuning kommt oft aus cMetricSettings und cWorkerTuningSettings

Beispiel: lokaler All-in-One-Container

docker run -d \
  --name integramon-local \
  -p 80:80 \
  -v "$(pwd)/data:/app/data" \
  -v "$(pwd)/deploy/env/postgreslocal.docker.json:/run/secrets/app-config.json:ro" \
  --restart unless-stopped \
  integramon:latest

Dieses Muster nutzt:

  • internes PostgreSQL
  • internes Redis
  • persistente Application-Daten unter /app/data
  • generierte Nginx-Konfiguration aus dem HTTP-Template

Beispiel: externes PostgreSQL und Redis

docker run -d \
  --name integramon-prod \
  -p 80:80 \
  -e APP_BASE_PATH="/integramon" \
  -e FRONTEND_BASE_URL="https://example.com/integramon" \
  -e ENABLE_SSL="false" \
  -e CONFIG_JSON_B64="$CONFIG_JSON_B64" \
  -v "$(pwd)/data:/app/data" \
  --restart unless-stopped \
  integramon:latest

In diesem Modell sollte das JSON-Payload setzen:

  • DB_LOCAL=false
  • REDIS_LOCAL=false
  • externe DB_HOST, DB_USER, DB_PASSWORD
  • externe CELERY_BROKER_URL, CELERY_RESULT_BACKEND, REDIS_CACHE_URL und idealerweise CHANNELS_REDIS_URL

Beispiel: Compose-Muster

Die vorhandene docker-compose.yml im Repo zeigt derzeit eher ein Entwicklungssetup mit:

  • postgres
  • redis
  • app

Fuer Produktion sollte Compose zusaetzlich Persistenz und explizite Runtime-Config einbinden:

services:
  app:
    image: integramon:latest
    restart: unless-stopped
    ports:
      - "80:80"
    environment:
      APP_BASE_PATH: /integramon
      FRONTEND_BASE_URL: https://example.com/integramon
      CONFIG_JSON_B64: ${CONFIG_JSON_B64}
    volumes:
      - ./data:/app/data

Volumes und Persistenz

Empfohlene persistente Mounts:

  • /app/data
  • optional Zertifikatsdateien fuer SSL_CERT und SSL_KEY
  • optional ein Custom-Nginx-Config fuer NGINX_CONF_OVERRIDE
  • optional /run/secrets/app-config.json

Was in /app/data landet, haengt vom Modus ab:

  • SQLite-DB-Datei bei DB_BACKEND=sqlite
  • Tenant-Archive
  • Tenant-Job-Logs
  • Laufzeit-Verzeichnisse aus cConfigExt

Was nicht automatisch persistent ist, wenn du es nicht separat mountest:

  • /var/log/nginx
  • interne PostgreSQL-Clusterdateien
  • interner Redis-Zustand, weil interner Redis ohne RDB und AOF laeuft

Fuer Produktion bedeutet das:

  • internen Redis nicht als dauerhaften Queue-Speicher behandeln
  • externes PostgreSQL bevorzugen oder PostgreSQL-Daten mounten, wenn die Datenbank im Container bleiben soll

Interne versus externe Services

DB_LOCAL und REDIS_LOCAL entscheiden nur, ob Supervisor die internen Daemons startet.

Sie schreiben die Django-Verbindungseinstellungen nicht automatisch um.

Beispiele:

  • REDIS_LOCAL=false ohne externe Redis-URLs laesst Django weiterhin auf lokale Redis-Defaults zeigen und faellt aus
  • DB_LOCAL=false mit DB_BACKEND=postgresql braucht trotzdem gueltige externe Postgres-Credentials

Reverse Proxy und Subpath-Verhalten

APP_BASE_PATH wird an drei Stellen genutzt:

  1. Nginx-Location-Blocks
  2. runtime-generierte /var/www/html/app-config.js
  3. umgeschriebenes <base href> in index.html

Deshalb kann dasselbe Frontend-Build sowohl unter / als auch unter einem Subpath wie /integramon laufen.

HTTPS-Verhalten

Wenn ENABLE_SSL=true, rendert start.sh das HTTPS-Nginx-Template und erwartet:

  • SERVER_NAME
  • SSL_CERT
  • SSL_KEY

Sind diese Pfade falsch oder fehlen sie, startet Nginx nicht.

Fuer Deployments hinter einem vorgeschalteten Reverse Proxy oder Load Balancer ist es meist einfacher, ENABLE_SSL=false zu lassen und TLS upstream zu terminieren.

Logging und Restart-Verhalten

Supervisor schreibt Prozesslogs in LOG_DIR, typischerweise:

  • postgres.log
  • redis.log
  • migrate.log
  • gunicorn.log
  • celery-*.log
  • worker.log
  • nginx.log

Der Container-CMD ist bash /start.sh, daher fuehrt jeder Container-Restart die gesamte Bootstrap-Sequenz erneut aus.

Empfohlene Docker-Restart-Policy:

  • unless-stopped fuer langlebige Umgebungen

PDF-Generierung in Docker

Das Image installiert bereits alles, was manage.py export_docs_pdfs benoetigt:

  • Chromium
  • Mermaid CLI
  • Cairo- und Pango-Libraries
  • den kompletten Doku-Baum

Der Docker-Build fuehrt sogar aus:

python /app/backend/src/manage.py export_docs_pdfs --output-dir /app/generated-docs

Das bedeutet: Neue Markdown-Seiten unter docs/integramon/docs und docs/integramon/sysdocs muessen mit derselben Export-Pipeline kompatibel bleiben. Normales Markdown, Standard-Tabellen und Mermaid-Bloecke sind dafuer sichere Patterns.