# Docker Containerization Roadmap ## Ziel Die Blender-Rendering-Pipeline soll vollständig containerisiert und später in eine verteilte Job-Infrastruktur integriert werden. Wichtige Randbedingungen: * Blender-Container sollen nur laufen, wenn tatsächlich Renderaufträge vorhanden sind. * Verschiedene Jobtypen sollen unterschiedliche Container verwenden können. * Die Infrastruktur soll zukünftig nicht nur Blender-Rendering, sondern auch andere Workloads (AI-Training, STL-Verarbeitung, Datensatz-Generierung, Batch-Konvertierungen usw.) unterstützen. * Die Ausführung soll auf mehreren PCs/Worker-Nodes möglich sein. * Die bestehende Python-Logik soll möglichst unverändert bleiben. --- # Review / Bewertung **Gesamteinschätzung:** schlüssig und machbar. Die Zielarchitektur (Redis-Queue + Nomad-Scheduler, Container nur bei Bedarf, mehrere Workload-Typen, horizontale Skalierung) ist tragfähig und zukunftssicher. Es fehlen einige technische Punkte, die unten ergänzt sind. ## Wichtigste Korrektur: Renderer und Pipeline sind ZWEI Container, nicht einer Phase 1 spricht von „Rendering-Pipeline **+** Analyse-Pipeline" in *einem* Container. Das sollte getrennt werden — die beiden haben grundverschiedene Profile: | | Render-Container | Pipeline-Container | |---|---|---| | Image | `approbot/blender-renderer` | `approbot/pose-pipeline` | | Basis | Blender 4.5 + bpy + cv2 + numpy (~1–2 GB) | `python:3.11-slim` + numpy/scipy/opencv (~200 MB) | | GPU | ja (Cycles, CUDA/OPTIX) | nein | | Zweck | **Test-Datengenerator** (nur Sim/Dev) | **Produkt** (läuft auch mit echten Webcam-Fotos!) | | Änderungsrate | selten | häufig | | CI-tauglich | nein (schwer, GPU) | ja (schnell, headless) | Das ist keine Kosmetik: Die **Pipeline ist das eigentliche Deliverable** (Roboter-Pose aus Fotos) und wird real deployed; der Renderer ist nur Werkzeug zur Testdaten-Erzeugung. Getrennt heißt: die Pipeline bleibt schlank, schnell CI-testbar und ohne Blender-Ballast deploybar; der Renderer wird nur dort gestartet, wo eine GPU steht. **Datenaustausch** zwischen beiden: gemeinsames Volume (Phase 1–3), später Object-Storage (MinIO/S3) im verteilten Betrieb. ## Technische Schlüsselpunkte (bisher nicht in der Roadmap) 1. **cv2 in Blenders Python:** `render_robot.py` importiert `cv2` (ArUco-Generierung). Blender bringt sein *eigenes* gebündeltes Python mit — `opencv-python` muss **dort** installiert werden (`/python/bin/python -m pip install opencv-python`), nicht ins System-Python. Häufige Stolperfalle. 2. **ArUco = opencv-contrib:** Die Pipeline nutzt `cv2.aruco`. Im Pipeline-Container `opencv-contrib-python-headless` verwenden (nicht Basis-`opencv-python`), Version pinnen. 3. **robot.json-Mutation ist im Parallelbetrieb ein Race:** `render_Loop.py` schreibt pro Render in die *gemeinsame* `robot.json` (Kamera, Pose, Auflösung). Laufen mehrere Render-Jobs parallel auf einem Node, überschreiben sie sich gegenseitig. Im Job-Modell muss jeder Job seine Parameter aus dem **Job-Payload** bekommen und in eine **eigene temporäre Config** schreiben — nicht in die geteilte robot.json. (Architektur-Fix, gehört *vor* Phase 4.) 4. **GPU im Container & Scheduler:** `--gpus all` + NVIDIA Container Toolkit; Nomad braucht das GPU-Device-Plugin, damit Render-Jobs nur auf GPU-Nodes landen. CPU-Fallback (Cycles `device='CPU'`) als Sicherheitsnetz behalten. 5. **Versionen pinnen:** Blender 4.5.x exakt, `requirements.txt` mit festen Versionen (numpy/scipy/opencv) — sonst driften die Mess-Ergebnisse (vgl. der fy-Intrinsik-Bug). 6. **Job-Granularität:** `{"jobType":"blender-render","pose":8}` rendert 7 Kameras pro Job. Feinkörniger (1 Job = 1 Kamera) parallelisiert besser über mehrere Nodes — abwägen. ## Empfehlung: MVP vor Nomad Redis + Nomad ist die richtige End-Vision, aber als Zwischenstufe genügt **docker-compose mit zwei Images + Profiles** (Renderer on-demand via `docker compose run`, Pipeline als schneller Service / CI-Step). Damit sind getrennte Container + Phase 1–3 produktiv nutzbar, bevor die verteilte Orchestrierung (Phase 5–8) aufgebaut wird. --- # Phase 1 – Dockerisierung der bestehenden Rendering-Pipeline ## Ziel Die aktuelle Blender-Pipeline läuft vollständig innerhalb eines Docker-Containers. ### Aufgaben Code/Infrastruktur erstellt (Dateien in `setup/generateSets/`): * [x] `Dockerfile.renderer` (Ubuntu + Blender 4.5 headless) und `Dockerfile.pipeline` (slim Python) * [x] `docker-compose.yml` mit beiden Services + gemeinsamem `data`-Volume * [x] cv2 in **Blenders** gebündeltem Python (im Renderer-Dockerfile) — nicht System-Python * [x] `requirements.pipeline.txt` (numpy, scipy, opencv-contrib-python-headless), gepinnt * [x] Pfad-/Config-env in `render_robot.py` (`ROBOT_JSON`, `RENDER_OUTPUT`) und `render_Loop.py` (`BLENDER_EXE`) * [x] `pipeline/run_pipeline.py` — plattformunabhängiger Orchestrator (1→2→3→3b→4), lokal getestet * [x] `README.docker.md` mit Build-/Run-Anleitung * [x] Portainer-Skript: `curl` → `curl.exe` (PowerShell-Alias-Falle) gefixt Im Container zu verifizieren (Docker/GPU lokal nicht testbar in der Entwicklung): * [ ] `docker compose build` (Blender-Download/-Version prüfen) * [ ] `render_Loop.py`/`render_robot.py` im Renderer-Container (STL-Import, PNG, NPZ, markers.json) * [ ] `pipeline/run_pipeline.py` im Pipeline-Container auf den gerenderten PNGs ### Ergebnis Zwei Container: `approbot/blender-renderer` erzeugt Bilder/npz/Ground-Truth, `approbot/pose-pipeline` wertet sie aus — beide reproduzierbar, über ein gemeinsames `data`-Volume verbunden. Der Pipeline-Orchestrator nutzt **pro Kamera die eigene npz** (wichtig wegen der per-Kamera-Kalibrierfehler aus dem Linsenfehler-Feature A). --- # Phase 2 – Pfad-Unabhängigkeit ## Ziel Alle absoluten Benutzerpfade entfernen. ### Aktuelle Situation Beispiel: ```python Path.home() / "SynologyDrive" / ... ``` ### Ziel Container-interne Pfade verwenden: ```text /workspace/data /workspace/setup /workspace/output ``` ### Aufgaben * [ ] ROBOT_JSON_FILE auf Containerpfade umstellen * [ ] OUTPUT_FILE auf Containerpfade umstellen * [ ] STL-Suche auf Containerpfade umstellen * [ ] Konfiguration über Environment-Variablen ermöglichen * [ ] **render_robot.py: Config-Pfad per env (`ROBOT_JSON`)** statt hardcodiert; und **render_Loop.py: pro Render eine *temporäre* Config schreiben** statt die geteilte robot.json zu mutieren (Voraussetzung für parallele Jobs, siehe Schlüsselpunkt 3) * [ ] BLENDER_EXE per env/PATH (aktuell hardcodierter Windows-Pfad) ### Ergebnis Die Pipeline ist vollständig unabhängig vom lokalen Benutzerprofil und parallel-tauglich. --- # Phase 3 – Repository-Struktur bereinigen ## Ziel Klare Trennung zwischen Code, Daten und Ergebnissen. ### Zielstruktur ```text appRobotRendering/ ├── data/ │ ├── robot/ │ ├── simulation/ │ └── surfaces/ │ ├── setup/ │ └── generateSets/ │ ├── render_loop.py │ ├── render_robot.py │ ├── Dockerfile │ └── docker-compose.yaml │ ├── jobs/ │ └── output/ ``` ### Aufgaben * [ ] Verzeichnisstruktur vereinheitlichen * [ ] Dokumentation ergänzen * [ ] Mountpoints definieren --- # Phase 4 – Job-Modell einführen ## Ziel Rendering-Aufträge werden als eigenständige Jobs beschrieben. ### Beispiel ```json { "jobType": "blender-render", "pose": 8 } ``` ### Spätere Erweiterungen ```json { "jobType": "dataset-generation" } ``` ```json { "jobType": "stl-conversion" } ``` ```json { "jobType": "ai-training" } ``` ### Aufgaben * [ ] Job-Format definieren * [ ] Job-Metadaten definieren * [ ] Retry-Konzept definieren * [ ] Statusmodell definieren ### Status ```text queued running completed failed timeout ``` --- # Phase 5 – Redis als Queue ## Ziel Entkopplung zwischen Auftragserzeugung und Ausführung. ### Aufgaben * [ ] Redis bereitstellen * [ ] Job-Queue definieren * [ ] Job-Status speichern * [ ] Retry-Mechanismus definieren ### Hinweis Redis startet keine Worker. Redis dient ausschließlich als: * Queue * Statusspeicher * Kommunikationsschicht --- # Phase 6 – Nomad Scheduler ## Ziel Container werden nur bei tatsächlichem Bedarf gestartet. ### Architektur ```text Job Producer │ ▼ Redis │ ▼ Nomad │ ▼ Docker Container ``` ### Aufgaben * [ ] Nomad Server aufsetzen * [ ] Worker-Nodes registrieren * [ ] Docker Driver aktivieren * [ ] Batch-Jobs definieren ### Ergebnis Nomad entscheidet: * welcher Node frei ist * welcher Container gestartet wird * wann ein Container beendet wird --- # Phase 7 – Blender als Nomad Batch Job ## Ziel Blender läuft nur während der Bearbeitung eines Auftrags. ### Beispiel ```text Job: blender-render Container: approbot/blender-renderer:latest ``` Ablauf: 1. Job wird eingereicht 2. Nomad startet Blender-Container 3. Rendering läuft 4. Ergebnisse werden gespeichert 5. Container beendet sich 6. Ressourcen werden freigegeben ### Ergebnis Keine dauerhaft laufenden Blender-Worker. --- # Phase 8 – Multi-Container Plattform ## Ziel Beliebige Jobtypen auf derselben Infrastruktur ausführen. ### Beispiele #### Blender Rendering ```text Container: approbot/blender-renderer ``` #### AI Training ```text Container: approbot/trainer ``` #### STL Processing ```text Container: approbot/stl-worker ``` #### Dataset Generation ```text Container: approbot/dataset-worker ``` ### Ergebnis Der verwendete Container wird durch den Jobtyp bestimmt. --- # Zielarchitektur ```text Nomad │ ┌────────────────┼────────────────┐ │ │ │ Blender Job AI Job Dataset Job │ │ │ Blender Training Dataset Worker Container Container Container └────────────────┼────────────────┘ │ Docker │ Worker Nodes (PCs) ``` Eigenschaften: * keine dauerhaft laufenden Blender-Container * unterschiedliche Container pro Jobtyp * horizontale Skalierung auf mehrere PCs * saubere Trennung von Scheduling und Ausführung * zukünftige Erweiterbarkeit für beliebige Workloads --- # Offene Punkte / nicht vergessen * **Cluster-Storage:** geteiltes NFS/Volume (einfach) vs. Object-Storage MinIO/S3 (entkoppelt Nodes, skaliert). Ab >1 Worker-Node bevorzugt Object-Storage. * **robot.json als geteilter Mutable-State auflösen** (Schlüsselpunkt 3) — Voraussetzung für parallele Render-Jobs auf einem Node. * **Reproduzierbarkeit:** Blender- und Python-Versionen pinnen; `requirements.txt` einchecken. * **GPU-Headless:** prüfen, ob Cycles im Container EGL braucht; sonst CPU-Fallback verifizieren. * **CI-Hook:** Pipeline-Container in CI → `benchmark/run_benchmark.py` gegen Ground-Truth bei jedem Commit (schnell, ohne Blender) — fängt Regressionen wie den fy-Bug automatisch. * **Monitoring/Logs:** Job-Logs zentral (stdout → Nomad/Loki), Render-Zeiten messen. * **Image-Registry:** private Registry (Harbor o. Ä.) für die `approbot/*`-Images.