Files
appRobotRender/doc/docker_containerization_roadmap.md
2026-06-02 17:16:24 +02:00

425 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 (~12 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 13), 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 (`<blender>/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 13 produktiv nutzbar,
bevor die verteilte Orchestrierung (Phase 58) 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.