425 lines
11 KiB
Markdown
425 lines
11 KiB
Markdown
# 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 (`<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 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.
|